xref: /netbsd-src/external/mpl/bind/dist/bin/named/server.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
1 /*	$NetBSD: server.c,v 1.22 2024/09/22 00:13:56 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 <stdbool.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #ifdef HAVE_DNSTAP
28 #include <fstrm.h>
29 #endif
30 
31 #include <isc/aes.h>
32 #include <isc/app.h>
33 #include <isc/attributes.h>
34 #include <isc/base64.h>
35 #include <isc/commandline.h>
36 #include <isc/dir.h>
37 #include <isc/file.h>
38 #include <isc/hash.h>
39 #include <isc/hex.h>
40 #include <isc/hmac.h>
41 #include <isc/httpd.h>
42 #include <isc/lex.h>
43 #include <isc/meminfo.h>
44 #include <isc/netmgr.h>
45 #include <isc/nonce.h>
46 #include <isc/parseint.h>
47 #include <isc/portset.h>
48 #include <isc/print.h>
49 #include <isc/refcount.h>
50 #include <isc/resource.h>
51 #include <isc/result.h>
52 #include <isc/siphash.h>
53 #include <isc/stat.h>
54 #include <isc/stats.h>
55 #include <isc/stdio.h>
56 #include <isc/string.h>
57 #include <isc/task.h>
58 #include <isc/timer.h>
59 #include <isc/util.h>
60 
61 #include <dns/adb.h>
62 #include <dns/badcache.h>
63 #include <dns/cache.h>
64 #include <dns/catz.h>
65 #include <dns/db.h>
66 #include <dns/dispatch.h>
67 #include <dns/dlz.h>
68 #include <dns/dns64.h>
69 #include <dns/dnsrps.h>
70 #include <dns/dnssec.h>
71 #include <dns/dyndb.h>
72 #include <dns/events.h>
73 #include <dns/fixedname.h>
74 #include <dns/forward.h>
75 #include <dns/geoip.h>
76 #include <dns/journal.h>
77 #include <dns/kasp.h>
78 #include <dns/keymgr.h>
79 #include <dns/keytable.h>
80 #include <dns/keyvalues.h>
81 #include <dns/master.h>
82 #include <dns/masterdump.h>
83 #include <dns/nsec3.h>
84 #include <dns/nta.h>
85 #include <dns/order.h>
86 #include <dns/peer.h>
87 #include <dns/private.h>
88 #include <dns/rbt.h>
89 #include <dns/rdataclass.h>
90 #include <dns/rdatalist.h>
91 #include <dns/rdataset.h>
92 #include <dns/rdatastruct.h>
93 #include <dns/resolver.h>
94 #include <dns/rootns.h>
95 #include <dns/rriterator.h>
96 #include <dns/secalg.h>
97 #include <dns/soa.h>
98 #include <dns/stats.h>
99 #include <dns/time.h>
100 #include <dns/tkey.h>
101 #include <dns/tsig.h>
102 #include <dns/ttl.h>
103 #include <dns/view.h>
104 #include <dns/zone.h>
105 #include <dns/zt.h>
106 
107 #include <dst/dst.h>
108 
109 #include <isccfg/grammar.h>
110 #include <isccfg/kaspconf.h>
111 #include <isccfg/namedconf.h>
112 
113 #include <ns/client.h>
114 #include <ns/hooks.h>
115 #include <ns/interfacemgr.h>
116 #include <ns/listenlist.h>
117 
118 #include <bind9/check.h>
119 
120 #include <named/config.h>
121 #include <named/control.h>
122 #if defined(HAVE_GEOIP2)
123 #include <named/geoip.h>
124 #endif /* HAVE_GEOIP2 */
125 #include <named/log.h>
126 #include <named/logconf.h>
127 #include <named/main.h>
128 #include <named/os.h>
129 #include <named/server.h>
130 #include <named/statschannel.h>
131 #include <named/tkeyconf.h>
132 #include <named/transportconf.h>
133 #include <named/tsigconf.h>
134 #include <named/zoneconf.h>
135 #ifdef HAVE_LIBSCF
136 #include <stdlib.h>
137 
138 #include <named/smf_globals.h>
139 #endif /* ifdef HAVE_LIBSCF */
140 
141 #ifdef HAVE_LMDB
142 #include <lmdb.h>
143 #define count_newzones	   count_newzones_db
144 #define configure_newzones configure_newzones_db
145 #define dumpzone	   dumpzone_db
146 #else /* HAVE_LMDB */
147 #define count_newzones	   count_newzones_file
148 #define configure_newzones configure_newzones_file
149 #define dumpzone	   dumpzone_file
150 #endif /* HAVE_LMDB */
151 
152 #ifndef SIZE_MAX
153 #define SIZE_MAX ((size_t)-1)
154 #endif /* ifndef SIZE_MAX */
155 
156 #ifndef SIZE_AS_PERCENT
157 #define SIZE_AS_PERCENT ((size_t)-2)
158 #endif /* ifndef SIZE_AS_PERCENT */
159 
160 #ifdef TUNE_LARGE
161 #define RESOLVER_NTASKS_PERCPU 32
162 #else
163 #define RESOLVER_NTASKS_PERCPU 8
164 #endif /* TUNE_LARGE */
165 
166 /* RFC7828 defines timeout as 16-bit value specified in units of 100
167  * milliseconds, so the maximum and minimum advertised and keepalive
168  * timeouts are capped by the data type (it's ~109 minutes)
169  */
170 #define MIN_INITIAL_TIMEOUT    UINT32_C(2500)	/* 2.5 seconds */
171 #define MAX_INITIAL_TIMEOUT    UINT32_C(120000) /* 2 minutes */
172 #define MIN_IDLE_TIMEOUT       UINT32_C(100)	/* 0.1 seconds */
173 #define MAX_IDLE_TIMEOUT       UINT32_C(120000) /* 2 minutes */
174 #define MIN_KEEPALIVE_TIMEOUT  UINT32_C(100)	/* 0.1 seconds */
175 #define MAX_KEEPALIVE_TIMEOUT  UINT32_C(UINT16_MAX * 100)
176 #define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */
177 #define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100)
178 
179 /*%
180  * Check an operation for failure.  Assumes that the function
181  * using it has a 'result' variable and a 'cleanup' label.
182  */
183 #define CHECK(op)                            \
184 	do {                                 \
185 		result = (op);               \
186 		if (result != ISC_R_SUCCESS) \
187 			goto cleanup;        \
188 	} while (0)
189 
190 #define TCHECK(op)                               \
191 	do {                                     \
192 		tresult = (op);                  \
193 		if (tresult != ISC_R_SUCCESS) {  \
194 			isc_buffer_clear(*text); \
195 			goto cleanup;            \
196 		}                                \
197 	} while (0)
198 
199 #define CHECKM(op, msg)                                                        \
200 	do {                                                                   \
201 		result = (op);                                                 \
202 		if (result != ISC_R_SUCCESS) {                                 \
203 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
204 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
205 				      "%s: %s", msg,                           \
206 				      isc_result_totext(result));              \
207 			goto cleanup;                                          \
208 		}                                                              \
209 	} while (0)
210 
211 #define CHECKMF(op, msg, file)                                                 \
212 	do {                                                                   \
213 		result = (op);                                                 \
214 		if (result != ISC_R_SUCCESS) {                                 \
215 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
216 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
217 				      "%s '%s': %s", msg, file,                \
218 				      isc_result_totext(result));              \
219 			goto cleanup;                                          \
220 		}                                                              \
221 	} while (0)
222 
223 #define CHECKFATAL(op, msg)                         \
224 	do {                                        \
225 		result = (op);                      \
226 		if (result != ISC_R_SUCCESS) {      \
227 			fatal(server, msg, result); \
228 		}                                   \
229 	} while (0)
230 
231 /*%
232  * Maximum ADB size for views that share a cache.  Use this limit to suppress
233  * the total of memory footprint, which should be the main reason for sharing
234  * a cache.  Only effective when a finite max-cache-size is specified.
235  * This is currently defined to be 8MB.
236  */
237 #define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
238 
239 struct named_dispatch {
240 	isc_sockaddr_t addr;
241 	unsigned int dispatchgen;
242 	dns_dispatch_t *dispatch;
243 	ISC_LINK(struct named_dispatch) link;
244 };
245 
246 struct named_cache {
247 	dns_cache_t *cache;
248 	dns_view_t *primaryview;
249 	bool needflush;
250 	bool adbsizeadjusted;
251 	dns_rdataclass_t rdclass;
252 	ISC_LINK(named_cache_t) link;
253 };
254 
255 struct dumpcontext {
256 	isc_mem_t *mctx;
257 	bool dumpcache;
258 	bool dumpzones;
259 	bool dumpadb;
260 	bool dumpbad;
261 	bool dumpexpired;
262 	bool dumpfail;
263 	FILE *fp;
264 	ISC_LIST(struct viewlistentry) viewlist;
265 	struct viewlistentry *view;
266 	struct zonelistentry *zone;
267 	dns_dumpctx_t *mdctx;
268 	dns_db_t *db;
269 	dns_db_t *cache;
270 	isc_task_t *task;
271 	dns_dbversion_t *version;
272 };
273 
274 struct viewlistentry {
275 	dns_view_t *view;
276 	ISC_LINK(struct viewlistentry) link;
277 	ISC_LIST(struct zonelistentry) zonelist;
278 };
279 
280 struct zonelistentry {
281 	dns_zone_t *zone;
282 	ISC_LINK(struct zonelistentry) link;
283 };
284 
285 /*%
286  * Configuration context to retain for each view that allows
287  * new zones to be added at runtime.
288  */
289 typedef struct ns_cfgctx {
290 	isc_mem_t *mctx;
291 	cfg_parser_t *conf_parser;
292 	cfg_parser_t *add_parser;
293 	cfg_obj_t *config;
294 	cfg_obj_t *vconfig;
295 	cfg_obj_t *nzf_config;
296 	cfg_aclconfctx_t *actx;
297 } ns_cfgctx_t;
298 
299 /*%
300  * A function to write out added-zone configuration to the new_zone_file
301  * specified in 'view'. Maybe called by delete_zoneconf().
302  */
303 typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
304 
305 /*%
306  * Holds state information for the initial zone loading process.
307  * Uses the isc_refcount structure to count the number of views
308  * with pending zone loads, dereferencing as each view finishes.
309  */
310 typedef struct {
311 	named_server_t *server;
312 	bool reconfig;
313 	isc_refcount_t refs;
314 } ns_zoneload_t;
315 
316 typedef struct {
317 	named_server_t *server;
318 } catz_cb_data_t;
319 
320 typedef struct catz_chgzone_event {
321 	ISC_EVENT_COMMON(struct catz_chgzone_event);
322 	dns_catz_entry_t *entry;
323 	dns_catz_zone_t *origin;
324 	dns_view_t *view;
325 	catz_cb_data_t *cbd;
326 	bool mod;
327 } catz_chgzone_event_t;
328 
329 typedef struct catz_reconfig_data {
330 	dns_catz_zone_t *catz;
331 	const cfg_obj_t *config;
332 	catz_cb_data_t *cbd;
333 } catz_reconfig_data_t;
334 
335 typedef struct {
336 	unsigned int magic;
337 #define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
338 	isc_buffer_t **text;
339 	isc_result_t result;
340 } ns_dzarg_t;
341 
342 /*
343  * These zones should not leak onto the Internet.
344  */
345 const char *empty_zones[] = {
346 	/* RFC 1918 */
347 	"10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
348 	"18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
349 	"21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
350 	"24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
351 	"27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
352 	"30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
353 
354 	/* RFC 6598 */
355 	"64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
356 	"67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
357 	"70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
358 	"73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
359 	"76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
360 	"79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
361 	"82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
362 	"85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
363 	"88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
364 	"91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
365 	"94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
366 	"97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
367 	"100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA", "102.100.IN-ADDR.ARPA",
368 	"103.100.IN-ADDR.ARPA", "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
369 	"106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA", "108.100.IN-ADDR.ARPA",
370 	"109.100.IN-ADDR.ARPA", "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
371 	"112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA", "114.100.IN-ADDR.ARPA",
372 	"115.100.IN-ADDR.ARPA", "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
373 	"118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA", "120.100.IN-ADDR.ARPA",
374 	"121.100.IN-ADDR.ARPA", "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
375 	"124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA", "126.100.IN-ADDR.ARPA",
376 	"127.100.IN-ADDR.ARPA",
377 
378 	/* RFC 5735 and RFC 5737 */
379 	"0.IN-ADDR.ARPA",		/* THIS NETWORK */
380 	"127.IN-ADDR.ARPA",		/* LOOPBACK */
381 	"254.169.IN-ADDR.ARPA",		/* LINK LOCAL */
382 	"2.0.192.IN-ADDR.ARPA",		/* TEST NET */
383 	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
384 	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
385 	"255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
386 
387 	/* Local IPv6 Unicast Addresses */
388 	"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."
389 	"ARPA",
390 	"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."
391 	"ARPA",
392 	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
393 	"D.F.IP6.ARPA", "8.E.F.IP6.ARPA", /* LINK LOCAL */
394 	"9.E.F.IP6.ARPA",		  /* LINK LOCAL */
395 	"A.E.F.IP6.ARPA",		  /* LINK LOCAL */
396 	"B.E.F.IP6.ARPA",		  /* LINK LOCAL */
397 
398 	/* Example Prefix, RFC 3849. */
399 	"8.B.D.0.1.0.0.2.IP6.ARPA",
400 
401 	/* RFC 7534 */
402 	"EMPTY.AS112.ARPA",
403 
404 	/* RFC 8375 */
405 	"HOME.ARPA",
406 
407 	/* RFC 9462 */
408 	"RESOLVER.ARPA",
409 
410 	NULL
411 };
412 
413 noreturn static void
414 fatal(named_server_t *server, const char *msg, isc_result_t result);
415 
416 static void
417 named_server_reload(isc_task_t *task, isc_event_t *event);
418 
419 #ifdef HAVE_LIBNGHTTP2
420 static isc_result_t
421 listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
422 	       const ns_listen_tls_params_t *tls_params,
423 	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
424 	       isc_mem_t *mctx, ns_listenelt_t **target);
425 #endif
426 
427 static isc_result_t
428 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
429 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
430 		     isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target);
431 
432 static isc_result_t
433 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
434 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
435 		      isc_tlsctx_cache_t *tlsctx_cache,
436 		      ns_listenlist_t **target);
437 
438 static isc_result_t
439 configure_forward(const cfg_obj_t *config, dns_view_t *view,
440 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
441 		  const cfg_obj_t *forwardtype);
442 
443 static isc_result_t
444 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
445 		     const cfg_obj_t *alternates);
446 
447 static isc_result_t
448 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
449 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
450 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
451 	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
452 	       bool is_catz_member, bool modify);
453 
454 static void
455 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
456 			     dns_view_t *view);
457 
458 static isc_result_t
459 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
460 		   isc_mem_t *mctx, cfg_aclconfctx_t *actx);
461 
462 static isc_result_t
463 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
464 
465 static void
466 end_reserved_dispatches(named_server_t *server, bool all);
467 
468 static void
469 newzone_cfgctx_destroy(void **cfgp);
470 
471 static isc_result_t
472 putstr(isc_buffer_t **b, const char *str);
473 
474 static isc_result_t
475 putmem(isc_buffer_t **b, const char *str, size_t len);
476 
477 static isc_result_t
478 putuint8(isc_buffer_t **b, uint8_t val);
479 
480 static isc_result_t
481 putnull(isc_buffer_t **b);
482 
483 static int
484 count_zones(const cfg_obj_t *conf);
485 
486 #ifdef HAVE_LMDB
487 static isc_result_t
488 migrate_nzf(dns_view_t *view);
489 
490 static isc_result_t
491 nzd_writable(dns_view_t *view);
492 
493 static isc_result_t
494 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
495 
496 static isc_result_t
497 nzd_env_reopen(dns_view_t *view);
498 
499 static void
500 nzd_env_close(dns_view_t *view);
501 
502 static isc_result_t
503 nzd_close(MDB_txn **txnp, bool commit);
504 
505 static isc_result_t
506 nzd_count(dns_view_t *view, int *countp);
507 #else  /* ifdef HAVE_LMDB */
508 static isc_result_t
509 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
510 #endif /* ifdef HAVE_LMDB */
511 
512 /*%
513  * Configure a single view ACL at '*aclp'.  Get its configuration from
514  * 'vconfig' (for per-view configuration) and maybe from 'config'
515  */
516 static isc_result_t
517 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
518 		   const cfg_obj_t *gconfig, const char *aclname,
519 		   const char *acltuplename, cfg_aclconfctx_t *actx,
520 		   isc_mem_t *mctx, dns_acl_t **aclp) {
521 	isc_result_t result;
522 	const cfg_obj_t *maps[4];
523 	const cfg_obj_t *aclobj = NULL;
524 	int i = 0;
525 
526 	if (*aclp != NULL) {
527 		dns_acl_detach(aclp);
528 	}
529 	if (vconfig != NULL) {
530 		maps[i++] = cfg_tuple_get(vconfig, "options");
531 	}
532 	if (config != NULL) {
533 		const cfg_obj_t *options = NULL;
534 		(void)cfg_map_get(config, "options", &options);
535 		if (options != NULL) {
536 			maps[i++] = options;
537 		}
538 	}
539 	if (gconfig != NULL) {
540 		const cfg_obj_t *options = NULL;
541 		(void)cfg_map_get(gconfig, "options", &options);
542 		if (options != NULL) {
543 			maps[i++] = options;
544 		}
545 	}
546 	maps[i] = NULL;
547 
548 	(void)named_config_get(maps, aclname, &aclobj);
549 	if (aclobj == NULL) {
550 		/*
551 		 * No value available.	*aclp == NULL.
552 		 */
553 		return (ISC_R_SUCCESS);
554 	}
555 
556 	if (acltuplename != NULL) {
557 		/*
558 		 * If the ACL is given in an optional tuple, retrieve it.
559 		 * The parser should have ensured that a valid object be
560 		 * returned.
561 		 */
562 		aclobj = cfg_tuple_get(aclobj, acltuplename);
563 	}
564 
565 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
566 				    aclp);
567 
568 	return (result);
569 }
570 
571 /*%
572  * Configure a sortlist at '*aclp'.  Essentially the same as
573  * configure_view_acl() except it calls cfg_acl_fromconfig with a
574  * nest_level value of 2.
575  */
576 static isc_result_t
577 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
578 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
579 			dns_acl_t **aclp) {
580 	isc_result_t result;
581 	const cfg_obj_t *maps[3];
582 	const cfg_obj_t *aclobj = NULL;
583 	int i = 0;
584 
585 	if (*aclp != NULL) {
586 		dns_acl_detach(aclp);
587 	}
588 	if (vconfig != NULL) {
589 		maps[i++] = cfg_tuple_get(vconfig, "options");
590 	}
591 	if (config != NULL) {
592 		const cfg_obj_t *options = NULL;
593 		(void)cfg_map_get(config, "options", &options);
594 		if (options != NULL) {
595 			maps[i++] = options;
596 		}
597 	}
598 	maps[i] = NULL;
599 
600 	(void)named_config_get(maps, "sortlist", &aclobj);
601 	if (aclobj == NULL) {
602 		return (ISC_R_SUCCESS);
603 	}
604 
605 	/*
606 	 * Use a nest level of 3 for the "top level" of the sortlist;
607 	 * this means each entry in the top three levels will be stored
608 	 * as lists of separate, nested ACLs, rather than merged together
609 	 * into IP tables as is usually done with ACLs.
610 	 */
611 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
612 				    aclp);
613 
614 	return (result);
615 }
616 
617 static isc_result_t
618 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
619 			 const char *confname, const char *conftuplename,
620 			 isc_mem_t *mctx, dns_rbt_t **rbtp) {
621 	isc_result_t result;
622 	const cfg_obj_t *maps[3];
623 	const cfg_obj_t *obj = NULL;
624 	const cfg_listelt_t *element;
625 	int i = 0;
626 	dns_fixedname_t fixed;
627 	dns_name_t *name;
628 	isc_buffer_t b;
629 	const char *str;
630 	const cfg_obj_t *nameobj;
631 
632 	if (*rbtp != NULL) {
633 		dns_rbt_destroy(rbtp);
634 	}
635 	if (vconfig != NULL) {
636 		maps[i++] = cfg_tuple_get(vconfig, "options");
637 	}
638 	if (config != NULL) {
639 		const cfg_obj_t *options = NULL;
640 		(void)cfg_map_get(config, "options", &options);
641 		if (options != NULL) {
642 			maps[i++] = options;
643 		}
644 	}
645 	maps[i] = NULL;
646 
647 	(void)named_config_get(maps, confname, &obj);
648 	if (obj == NULL) {
649 		/*
650 		 * No value available.	*rbtp == NULL.
651 		 */
652 		return (ISC_R_SUCCESS);
653 	}
654 
655 	if (conftuplename != NULL) {
656 		obj = cfg_tuple_get(obj, conftuplename);
657 		if (cfg_obj_isvoid(obj)) {
658 			return (ISC_R_SUCCESS);
659 		}
660 	}
661 
662 	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
663 	if (result != ISC_R_SUCCESS) {
664 		return (result);
665 	}
666 
667 	name = dns_fixedname_initname(&fixed);
668 	for (element = cfg_list_first(obj); element != NULL;
669 	     element = cfg_list_next(element))
670 	{
671 		nameobj = cfg_listelt_value(element);
672 		str = cfg_obj_asstring(nameobj);
673 		isc_buffer_constinit(&b, str, strlen(str));
674 		isc_buffer_add(&b, strlen(str));
675 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
676 		/*
677 		 * We don't need the node data, but need to set dummy data to
678 		 * avoid a partial match with an empty node.  For example, if
679 		 * we have foo.example.com and bar.example.com, we'd get a match
680 		 * for baz.example.com, which is not the expected result.
681 		 * We simply use (void *)1 as the dummy data.
682 		 */
683 		result = dns_rbt_addname(*rbtp, name, (void *)1);
684 		if (result != ISC_R_SUCCESS) {
685 			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
686 				    "failed to add %s for %s: %s", str,
687 				    confname, isc_result_totext(result));
688 			goto cleanup;
689 		}
690 	}
691 
692 	return (result);
693 
694 cleanup:
695 	dns_rbt_destroy(rbtp);
696 	return (result);
697 }
698 
699 static isc_result_t
700 ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
701 	      unsigned char *digest, dns_rdata_ds_t *ds) {
702 	isc_result_t result;
703 	dns_rdata_dnskey_t keystruct;
704 	dns_rdata_t rdata = DNS_RDATA_INIT;
705 	uint32_t rdata1, rdata2, rdata3;
706 	const char *datastr = NULL, *namestr = NULL;
707 	unsigned char data[4096];
708 	isc_buffer_t databuf;
709 	unsigned char rrdata[4096];
710 	isc_buffer_t rrdatabuf;
711 	isc_region_t r;
712 	dns_fixedname_t fname;
713 	dns_name_t *name = NULL;
714 	isc_buffer_t namebuf;
715 	const char *atstr = NULL;
716 	enum {
717 		INIT_DNSKEY,
718 		STATIC_DNSKEY,
719 		INIT_DS,
720 		STATIC_DS,
721 		TRUSTED
722 	} anchortype;
723 
724 	REQUIRE(namestrp != NULL && *namestrp == NULL);
725 	REQUIRE(ds != NULL);
726 
727 	/* if DNSKEY, flags; if DS, key tag */
728 	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
729 
730 	/* if DNSKEY, protocol; if DS, algorithm */
731 	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
732 
733 	/* if DNSKEY, algorithm; if DS, digest type */
734 	rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3"));
735 
736 	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
737 	*namestrp = namestr;
738 
739 	name = dns_fixedname_initname(&fname);
740 	isc_buffer_constinit(&namebuf, namestr, strlen(namestr));
741 	isc_buffer_add(&namebuf, strlen(namestr));
742 	CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL));
743 
744 	if (*initialp) {
745 		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
746 
747 		if (strcasecmp(atstr, "static-key") == 0) {
748 			*initialp = false;
749 			anchortype = STATIC_DNSKEY;
750 		} else if (strcasecmp(atstr, "static-ds") == 0) {
751 			*initialp = false;
752 			anchortype = STATIC_DS;
753 		} else if (strcasecmp(atstr, "initial-key") == 0) {
754 			anchortype = INIT_DNSKEY;
755 		} else if (strcasecmp(atstr, "initial-ds") == 0) {
756 			anchortype = INIT_DS;
757 		} else {
758 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
759 				    "key '%s': "
760 				    "invalid initialization method '%s'",
761 				    namestr, atstr);
762 			result = ISC_R_FAILURE;
763 			goto cleanup;
764 		}
765 	} else {
766 		anchortype = TRUSTED;
767 	}
768 
769 	isc_buffer_init(&databuf, data, sizeof(data));
770 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
771 
772 	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
773 				.common.rdtype = dns_rdatatype_ds };
774 
775 	ISC_LINK_INIT(&ds->common, link);
776 
777 	switch (anchortype) {
778 	case INIT_DNSKEY:
779 	case STATIC_DNSKEY:
780 	case TRUSTED:
781 		/*
782 		 * This function should never be reached for view
783 		 * class other than IN
784 		 */
785 		keystruct.common.rdclass = dns_rdataclass_in;
786 		keystruct.common.rdtype = dns_rdatatype_dnskey;
787 
788 		/*
789 		 * The key data in keystruct is not dynamically allocated.
790 		 */
791 		keystruct.mctx = NULL;
792 
793 		ISC_LINK_INIT(&keystruct.common, link);
794 
795 		if (rdata1 > 0xffff) {
796 			CHECKM(ISC_R_RANGE, "key flags");
797 		}
798 		if (rdata1 & DNS_KEYFLAG_REVOKE) {
799 			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
800 		}
801 		if (rdata2 > 0xff) {
802 			CHECKM(ISC_R_RANGE, "key protocol");
803 		}
804 		if (rdata3 > 0xff) {
805 			CHECKM(ISC_R_RANGE, "key algorithm");
806 		}
807 
808 		keystruct.flags = (uint16_t)rdata1;
809 		keystruct.protocol = (uint8_t)rdata2;
810 		keystruct.algorithm = (uint8_t)rdata3;
811 
812 		if (!dst_algorithm_supported(keystruct.algorithm)) {
813 			CHECK(DST_R_UNSUPPORTEDALG);
814 		}
815 
816 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
817 		CHECK(isc_base64_decodestring(datastr, &databuf));
818 		isc_buffer_usedregion(&databuf, &r);
819 		keystruct.datalen = r.length;
820 		keystruct.data = r.base;
821 
822 		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
823 					   keystruct.common.rdtype, &keystruct,
824 					   &rrdatabuf));
825 		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
826 					  digest, ds));
827 		break;
828 
829 	case INIT_DS:
830 	case STATIC_DS:
831 		if (rdata1 > 0xffff) {
832 			CHECKM(ISC_R_RANGE, "key tag");
833 		}
834 		if (rdata2 > 0xff) {
835 			CHECKM(ISC_R_RANGE, "key algorithm");
836 		}
837 		if (rdata3 > 0xff) {
838 			CHECKM(ISC_R_RANGE, "digest type");
839 		}
840 
841 		ds->key_tag = (uint16_t)rdata1;
842 		ds->algorithm = (uint8_t)rdata2;
843 		ds->digest_type = (uint8_t)rdata3;
844 
845 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
846 		CHECK(isc_hex_decodestring(datastr, &databuf));
847 		isc_buffer_usedregion(&databuf, &r);
848 
849 		switch (ds->digest_type) {
850 		case DNS_DSDIGEST_SHA1:
851 			if (r.length != ISC_SHA1_DIGESTLENGTH) {
852 				CHECK(ISC_R_UNEXPECTEDEND);
853 			}
854 			break;
855 		case DNS_DSDIGEST_SHA256:
856 			if (r.length != ISC_SHA256_DIGESTLENGTH) {
857 				CHECK(ISC_R_UNEXPECTEDEND);
858 			}
859 			break;
860 		case DNS_DSDIGEST_SHA384:
861 			if (r.length != ISC_SHA384_DIGESTLENGTH) {
862 				CHECK(ISC_R_UNEXPECTEDEND);
863 			}
864 			break;
865 		default:
866 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
867 				    "key '%s': "
868 				    "unknown ds digest type %u",
869 				    namestr, ds->digest_type);
870 			result = ISC_R_FAILURE;
871 			goto cleanup;
872 			break;
873 		}
874 
875 		ds->length = r.length;
876 		ds->digest = digest;
877 		memmove(ds->digest, r.base, r.length);
878 
879 		break;
880 
881 	default:
882 		UNREACHABLE();
883 	}
884 
885 	return (ISC_R_SUCCESS);
886 
887 cleanup:
888 	return (result);
889 }
890 
891 static void
892 sfd_add(const dns_name_t *name, void *arg) {
893 	if (arg != NULL) {
894 		dns_view_sfd_add(arg, name);
895 	}
896 }
897 
898 /*%
899  * Parse 'key' in the context of view configuration 'vconfig'.  If successful,
900  * add the key to 'secroots' if both of the following conditions are true:
901  *
902  *   - 'keyname_match' is NULL or it matches the owner name of 'key',
903  *   - support for the algorithm used by 'key' is not disabled by 'resolver'
904  *     for the owner name of 'key'.
905  *
906  * 'managed' is true for managed keys and false for trusted keys.  'mctx' is
907  * the memory context to use for allocating memory.
908  */
909 static isc_result_t
910 process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
911 	    const dns_name_t *keyname_match, dns_view_t *view, bool managed) {
912 	dns_fixedname_t fkeyname;
913 	dns_name_t *keyname = NULL;
914 	const char *namestr = NULL;
915 	dns_rdata_ds_t ds;
916 	isc_result_t result;
917 	bool initializing = managed;
918 	unsigned char digest[ISC_MAX_MD_SIZE];
919 	isc_buffer_t b;
920 
921 	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
922 
923 	switch (result) {
924 	case ISC_R_SUCCESS:
925 		/*
926 		 * Trust anchor was parsed correctly.
927 		 */
928 		isc_buffer_constinit(&b, namestr, strlen(namestr));
929 		isc_buffer_add(&b, strlen(namestr));
930 		keyname = dns_fixedname_initname(&fkeyname);
931 		result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
932 		if (result != ISC_R_SUCCESS) {
933 			return (result);
934 		}
935 		break;
936 	case DST_R_UNSUPPORTEDALG:
937 	case DST_R_BADKEYTYPE:
938 		/*
939 		 * Key was parsed correctly, but it cannot be used; this is not
940 		 * a fatal error - log a warning about this key being ignored,
941 		 * but do not prevent any further ones from being processed.
942 		 */
943 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
944 			    "ignoring %s for '%s': %s",
945 			    initializing ? "initial-key" : "static-key",
946 			    namestr, isc_result_totext(result));
947 		return (ISC_R_SUCCESS);
948 	case DST_R_NOCRYPTO:
949 		/*
950 		 * Crypto support is not available.
951 		 */
952 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
953 			    "ignoring %s for '%s': no crypto support",
954 			    initializing ? "initial-key" : "static-key",
955 			    namestr);
956 		return (result);
957 	default:
958 		/*
959 		 * Something unexpected happened; we have no choice but to
960 		 * indicate an error so that the configuration loading process
961 		 * is interrupted.
962 		 */
963 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
964 			    "configuring %s for '%s': %s",
965 			    initializing ? "initial-key" : "static-key",
966 			    namestr, isc_result_totext(result));
967 		return (ISC_R_FAILURE);
968 	}
969 
970 	/*
971 	 * If the caller requested to only load keys for a specific name and
972 	 * the owner name of this key does not match the requested name, do not
973 	 * load it.
974 	 */
975 	if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) {
976 		goto done;
977 	}
978 
979 	/*
980 	 * Ensure that 'resolver' allows using the algorithm of this key for
981 	 * its owner name.  If it does not, do not load the key and log a
982 	 * warning, but do not prevent further keys from being processed.
983 	 */
984 	if (!dns_resolver_algorithm_supported(view->resolver, keyname,
985 					      ds.algorithm))
986 	{
987 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
988 			    "ignoring %s for '%s': algorithm is disabled",
989 			    initializing ? "initial-key" : "static-key",
990 			    namestr);
991 		goto done;
992 	}
993 
994 	/*
995 	 * Add the key to 'secroots'.  Keys from a "trust-anchors" or
996 	 * "managed-keys" statement may be either static or initializing
997 	 * keys. If it's not initializing, we don't want to treat it as
998 	 * managed, so we use 'initializing' twice here, for both the
999 	 * 'managed' and 'initializing' arguments to dns_keytable_add().
1000 	 */
1001 	result = dns_keytable_add(secroots, initializing, initializing, keyname,
1002 				  &ds, sfd_add, view);
1003 
1004 done:
1005 	return (result);
1006 }
1007 
1008 /*
1009  * Load keys from configuration into key table. If 'keyname' is specified,
1010  * only load keys matching that name. If 'managed' is true, load the key as
1011  * an initializing key.
1012  */
1013 static isc_result_t
1014 load_view_keys(const cfg_obj_t *keys, dns_view_t *view, bool managed,
1015 	       const dns_name_t *keyname) {
1016 	const cfg_listelt_t *elt, *elt2;
1017 	const cfg_obj_t *keylist;
1018 	isc_result_t result;
1019 	dns_keytable_t *secroots = NULL;
1020 
1021 	CHECK(dns_view_getsecroots(view, &secroots));
1022 
1023 	for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt))
1024 	{
1025 		keylist = cfg_listelt_value(elt);
1026 
1027 		for (elt2 = cfg_list_first(keylist); elt2 != NULL;
1028 		     elt2 = cfg_list_next(elt2))
1029 		{
1030 			CHECK(process_key(cfg_listelt_value(elt2), secroots,
1031 					  keyname, view, managed));
1032 		}
1033 	}
1034 
1035 cleanup:
1036 	if (secroots != NULL) {
1037 		dns_keytable_detach(&secroots);
1038 	}
1039 	if (result == DST_R_NOCRYPTO) {
1040 		result = ISC_R_SUCCESS;
1041 	}
1042 	return (result);
1043 }
1044 
1045 /*%
1046  * Check whether a key has been successfully loaded.
1047  */
1048 static bool
1049 keyloaded(dns_view_t *view, const dns_name_t *name) {
1050 	isc_result_t result;
1051 	dns_keytable_t *secroots = NULL;
1052 	dns_keynode_t *keynode = NULL;
1053 
1054 	result = dns_view_getsecroots(view, &secroots);
1055 	if (result != ISC_R_SUCCESS) {
1056 		return (false);
1057 	}
1058 
1059 	result = dns_keytable_find(secroots, name, &keynode);
1060 
1061 	if (keynode != NULL) {
1062 		dns_keytable_detachkeynode(secroots, &keynode);
1063 	}
1064 	if (secroots != NULL) {
1065 		dns_keytable_detach(&secroots);
1066 	}
1067 
1068 	return (result == ISC_R_SUCCESS);
1069 }
1070 
1071 /*%
1072  * Configure DNSSEC keys for a view.
1073  *
1074  * The per-view configuration values and the server-global defaults are read
1075  * from 'vconfig' and 'config'.
1076  */
1077 static isc_result_t
1078 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
1079 			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
1080 			  bool auto_root, isc_mem_t *mctx) {
1081 	isc_result_t result = ISC_R_SUCCESS;
1082 	const cfg_obj_t *view_keys = NULL;
1083 	const cfg_obj_t *global_keys = NULL;
1084 	const cfg_obj_t *view_managed_keys = NULL;
1085 	const cfg_obj_t *view_trust_anchors = NULL;
1086 	const cfg_obj_t *global_managed_keys = NULL;
1087 	const cfg_obj_t *global_trust_anchors = NULL;
1088 	const cfg_obj_t *maps[4];
1089 	const cfg_obj_t *voptions = NULL;
1090 	const cfg_obj_t *options = NULL;
1091 	const cfg_obj_t *obj = NULL;
1092 	const char *directory;
1093 	int i = 0;
1094 
1095 	/* We don't need trust anchors for the _bind view */
1096 	if (strcmp(view->name, "_bind") == 0 &&
1097 	    view->rdclass == dns_rdataclass_chaos)
1098 	{
1099 		return (ISC_R_SUCCESS);
1100 	}
1101 
1102 	if (vconfig != NULL) {
1103 		voptions = cfg_tuple_get(vconfig, "options");
1104 		if (voptions != NULL) {
1105 			(void)cfg_map_get(voptions, "trusted-keys", &view_keys);
1106 
1107 			/* managed-keys and trust-anchors are synonyms. */
1108 			(void)cfg_map_get(voptions, "managed-keys",
1109 					  &view_managed_keys);
1110 			(void)cfg_map_get(voptions, "trust-anchors",
1111 					  &view_trust_anchors);
1112 
1113 			maps[i++] = voptions;
1114 		}
1115 	}
1116 
1117 	if (config != NULL) {
1118 		(void)cfg_map_get(config, "trusted-keys", &global_keys);
1119 
1120 		/* managed-keys and trust-anchors are synonyms. */
1121 		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
1122 		(void)cfg_map_get(config, "trust-anchors",
1123 				  &global_trust_anchors);
1124 
1125 		(void)cfg_map_get(config, "options", &options);
1126 		if (options != NULL) {
1127 			maps[i++] = options;
1128 		}
1129 	}
1130 
1131 	maps[i++] = named_g_defaults;
1132 	maps[i] = NULL;
1133 
1134 	result = dns_view_initsecroots(view, mctx);
1135 	if (result != ISC_R_SUCCESS) {
1136 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1137 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1138 			      "couldn't create keytable");
1139 		return (ISC_R_UNEXPECTED);
1140 	}
1141 
1142 	result = dns_view_initntatable(view, named_g_taskmgr, named_g_timermgr);
1143 	if (result != ISC_R_SUCCESS) {
1144 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1145 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1146 			      "couldn't create NTA table");
1147 		return (ISC_R_UNEXPECTED);
1148 	}
1149 
1150 	if (auto_root && view->rdclass == dns_rdataclass_in) {
1151 		const cfg_obj_t *builtin_keys = NULL;
1152 
1153 		/*
1154 		 * If bind.keys exists and is populated, it overrides
1155 		 * the trust-anchors clause hard-coded in named_g_config.
1156 		 */
1157 		if (bindkeys != NULL) {
1158 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1159 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1160 				      "obtaining root key for view %s "
1161 				      "from '%s'",
1162 				      view->name, named_g_server->bindkeysfile);
1163 
1164 			(void)cfg_map_get(bindkeys, "trust-anchors",
1165 					  &builtin_keys);
1166 
1167 			if (builtin_keys == NULL) {
1168 				isc_log_write(
1169 					named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1170 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
1171 					"dnssec-validation auto: "
1172 					"WARNING: root zone key "
1173 					"not found");
1174 			}
1175 		}
1176 
1177 		if (builtin_keys == NULL) {
1178 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1179 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1180 				      "using built-in root key for view %s",
1181 				      view->name);
1182 
1183 			(void)cfg_map_get(named_g_config, "trust-anchors",
1184 					  &builtin_keys);
1185 		}
1186 
1187 		if (builtin_keys != NULL) {
1188 			CHECK(load_view_keys(builtin_keys, view, true,
1189 					     dns_rootname));
1190 		}
1191 
1192 		if (!keyloaded(view, dns_rootname)) {
1193 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1194 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1195 				      "root key not loaded");
1196 			result = ISC_R_FAILURE;
1197 			goto cleanup;
1198 		}
1199 	}
1200 
1201 	if (view->rdclass == dns_rdataclass_in) {
1202 		CHECK(load_view_keys(view_keys, view, false, NULL));
1203 		CHECK(load_view_keys(view_trust_anchors, view, true, NULL));
1204 		CHECK(load_view_keys(view_managed_keys, view, true, NULL));
1205 
1206 		CHECK(load_view_keys(global_keys, view, false, NULL));
1207 		CHECK(load_view_keys(global_trust_anchors, view, true, NULL));
1208 		CHECK(load_view_keys(global_managed_keys, view, true, NULL));
1209 	}
1210 
1211 	/*
1212 	 * Add key zone for managed keys.
1213 	 */
1214 	obj = NULL;
1215 	(void)named_config_get(maps, "managed-keys-directory", &obj);
1216 	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
1217 	if (directory != NULL) {
1218 		result = isc_file_isdirectory(directory);
1219 	}
1220 	if (result != ISC_R_SUCCESS) {
1221 		isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1222 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1223 			      "invalid managed-keys-directory %s: %s",
1224 			      directory, isc_result_totext(result));
1225 		goto cleanup;
1226 	} else if (directory != NULL) {
1227 		if (!isc_file_isdirwritable(directory)) {
1228 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1229 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1230 				      "managed-keys-directory '%s' "
1231 				      "is not writable",
1232 				      directory);
1233 			result = ISC_R_NOPERM;
1234 			goto cleanup;
1235 		}
1236 	}
1237 
1238 	CHECK(add_keydata_zone(view, directory, named_g_mctx));
1239 
1240 cleanup:
1241 	return (result);
1242 }
1243 
1244 static isc_result_t
1245 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
1246 	const cfg_listelt_t *element;
1247 	const cfg_obj_t *obj;
1248 	const char *str;
1249 	dns_fixedname_t fixed;
1250 	dns_name_t *name;
1251 	bool value;
1252 	isc_result_t result;
1253 	isc_buffer_t b;
1254 
1255 	name = dns_fixedname_initname(&fixed);
1256 	for (element = cfg_list_first(mbs); element != NULL;
1257 	     element = cfg_list_next(element))
1258 	{
1259 		obj = cfg_listelt_value(element);
1260 		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
1261 		isc_buffer_constinit(&b, str, strlen(str));
1262 		isc_buffer_add(&b, strlen(str));
1263 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1264 		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
1265 		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
1266 	}
1267 
1268 	result = ISC_R_SUCCESS;
1269 
1270 cleanup:
1271 	return (result);
1272 }
1273 
1274 /*%
1275  * Get a dispatch appropriate for the resolver of a given view.
1276  */
1277 static isc_result_t
1278 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
1279 			      dns_dispatch_t **dispatchp, bool is_firstview) {
1280 	isc_result_t result = ISC_R_FAILURE;
1281 	dns_dispatch_t *disp = NULL;
1282 	isc_sockaddr_t sa;
1283 	const cfg_obj_t *obj = NULL;
1284 
1285 	switch (af) {
1286 	case AF_INET:
1287 		result = named_config_get(maps, "query-source", &obj);
1288 		INSIST(result == ISC_R_SUCCESS);
1289 		break;
1290 	case AF_INET6:
1291 		result = named_config_get(maps, "query-source-v6", &obj);
1292 		INSIST(result == ISC_R_SUCCESS);
1293 		break;
1294 	default:
1295 		UNREACHABLE();
1296 	}
1297 
1298 	sa = *(cfg_obj_assockaddr(obj));
1299 	INSIST(isc_sockaddr_pf(&sa) == af);
1300 
1301 	/*
1302 	 * If we don't support this address family, we're done!
1303 	 */
1304 	switch (af) {
1305 	case AF_INET:
1306 		result = isc_net_probeipv4();
1307 		break;
1308 	case AF_INET6:
1309 		result = isc_net_probeipv6();
1310 		break;
1311 	default:
1312 		UNREACHABLE();
1313 	}
1314 	if (result != ISC_R_SUCCESS) {
1315 		return (ISC_R_SUCCESS);
1316 	}
1317 
1318 	/*
1319 	 * Try to find a dispatcher that we can share.
1320 	 */
1321 	if (isc_sockaddr_getport(&sa) != 0) {
1322 		INSIST(obj != NULL);
1323 		if (is_firstview) {
1324 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
1325 				    "using specific query-source port "
1326 				    "suppresses port randomization and can be "
1327 				    "insecure.");
1328 		}
1329 	}
1330 
1331 	result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, &disp);
1332 	if (result != ISC_R_SUCCESS) {
1333 		isc_sockaddr_t any;
1334 		char buf[ISC_SOCKADDR_FORMATSIZE];
1335 
1336 		switch (af) {
1337 		case AF_INET:
1338 			isc_sockaddr_any(&any);
1339 			break;
1340 		case AF_INET6:
1341 			isc_sockaddr_any6(&any);
1342 			break;
1343 		}
1344 		if (isc_sockaddr_equal(&sa, &any)) {
1345 			return (ISC_R_SUCCESS);
1346 		}
1347 		isc_sockaddr_format(&sa, buf, sizeof(buf));
1348 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1349 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1350 			      "could not get query source dispatcher (%s)",
1351 			      buf);
1352 		return (result);
1353 	}
1354 
1355 	*dispatchp = disp;
1356 
1357 	return (ISC_R_SUCCESS);
1358 }
1359 
1360 static isc_result_t
1361 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1362 	dns_rdataclass_t rdclass;
1363 	dns_rdatatype_t rdtype;
1364 	const cfg_obj_t *obj;
1365 	dns_fixedname_t fixed;
1366 	unsigned int mode = 0;
1367 	const char *str;
1368 	isc_buffer_t b;
1369 	isc_result_t result;
1370 	bool addroot;
1371 
1372 	result = named_config_getclass(cfg_tuple_get(ent, "class"),
1373 				       dns_rdataclass_any, &rdclass);
1374 	if (result != ISC_R_SUCCESS) {
1375 		return (result);
1376 	}
1377 
1378 	result = named_config_gettype(cfg_tuple_get(ent, "type"),
1379 				      dns_rdatatype_any, &rdtype);
1380 	if (result != ISC_R_SUCCESS) {
1381 		return (result);
1382 	}
1383 
1384 	obj = cfg_tuple_get(ent, "name");
1385 	if (cfg_obj_isstring(obj)) {
1386 		str = cfg_obj_asstring(obj);
1387 	} else {
1388 		str = "*";
1389 	}
1390 	addroot = (strcmp(str, "*") == 0);
1391 	isc_buffer_constinit(&b, str, strlen(str));
1392 	isc_buffer_add(&b, strlen(str));
1393 	dns_fixedname_init(&fixed);
1394 	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, dns_rootname,
1395 				   0, NULL);
1396 	if (result != ISC_R_SUCCESS) {
1397 		return (result);
1398 	}
1399 
1400 	obj = cfg_tuple_get(ent, "ordering");
1401 	INSIST(cfg_obj_isstring(obj));
1402 	str = cfg_obj_asstring(obj);
1403 	if (!strcasecmp(str, "fixed")) {
1404 #if DNS_RDATASET_FIXED
1405 		mode = DNS_RDATASETATTR_FIXEDORDER;
1406 #else  /* if DNS_RDATASET_FIXED */
1407 		mode = DNS_RDATASETATTR_CYCLIC;
1408 #endif /* DNS_RDATASET_FIXED */
1409 	} else if (!strcasecmp(str, "random")) {
1410 		mode = DNS_RDATASETATTR_RANDOMIZE;
1411 	} else if (!strcasecmp(str, "cyclic")) {
1412 		mode = DNS_RDATASETATTR_CYCLIC;
1413 	} else if (!strcasecmp(str, "none")) {
1414 		mode = DNS_RDATASETATTR_NONE;
1415 	} else {
1416 		UNREACHABLE();
1417 	}
1418 
1419 	/*
1420 	 * "*" should match everything including the root (BIND 8 compat).
1421 	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1422 	 * explicit entry for "." when the name is "*".
1423 	 */
1424 	if (addroot) {
1425 		result = dns_order_add(order, dns_rootname, rdtype, rdclass,
1426 				       mode);
1427 		if (result != ISC_R_SUCCESS) {
1428 			return (result);
1429 		}
1430 	}
1431 
1432 	return (dns_order_add(order, dns_fixedname_name(&fixed), rdtype,
1433 			      rdclass, mode));
1434 }
1435 
1436 static isc_result_t
1437 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1438 	isc_netaddr_t na;
1439 	dns_peer_t *peer;
1440 	const cfg_obj_t *obj;
1441 	const char *str;
1442 	isc_result_t result;
1443 	unsigned int prefixlen;
1444 
1445 	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1446 
1447 	peer = NULL;
1448 	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1449 	if (result != ISC_R_SUCCESS) {
1450 		return (result);
1451 	}
1452 
1453 	obj = NULL;
1454 	(void)cfg_map_get(cpeer, "bogus", &obj);
1455 	if (obj != NULL) {
1456 		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1457 	}
1458 
1459 	obj = NULL;
1460 	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1461 	if (obj != NULL) {
1462 		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1463 	}
1464 
1465 	obj = NULL;
1466 	(void)cfg_map_get(cpeer, "request-expire", &obj);
1467 	if (obj != NULL) {
1468 		CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
1469 	}
1470 
1471 	obj = NULL;
1472 	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
1473 	if (obj != NULL) {
1474 		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1475 	}
1476 
1477 	obj = NULL;
1478 	(void)cfg_map_get(cpeer, "request-nsid", &obj);
1479 	if (obj != NULL) {
1480 		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1481 	}
1482 
1483 	obj = NULL;
1484 	(void)cfg_map_get(cpeer, "send-cookie", &obj);
1485 	if (obj != NULL) {
1486 		CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj)));
1487 	}
1488 
1489 	obj = NULL;
1490 	(void)cfg_map_get(cpeer, "edns", &obj);
1491 	if (obj != NULL) {
1492 		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1493 	}
1494 
1495 	obj = NULL;
1496 	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1497 	if (obj != NULL) {
1498 		uint32_t udpsize = cfg_obj_asuint32(obj);
1499 		if (udpsize < 512U) {
1500 			udpsize = 512U;
1501 		}
1502 		if (udpsize > 4096U) {
1503 			udpsize = 4096U;
1504 		}
1505 		CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize));
1506 	}
1507 
1508 	obj = NULL;
1509 	(void)cfg_map_get(cpeer, "edns-version", &obj);
1510 	if (obj != NULL) {
1511 		uint32_t ednsversion = cfg_obj_asuint32(obj);
1512 		if (ednsversion > 255U) {
1513 			ednsversion = 255U;
1514 		}
1515 		CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion));
1516 	}
1517 
1518 	obj = NULL;
1519 	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
1520 	if (obj != NULL) {
1521 		uint32_t udpsize = cfg_obj_asuint32(obj);
1522 		if (udpsize < 512U) {
1523 			udpsize = 512U;
1524 		}
1525 		if (udpsize > 4096U) {
1526 			udpsize = 4096U;
1527 		}
1528 		CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize));
1529 	}
1530 
1531 	obj = NULL;
1532 	(void)cfg_map_get(cpeer, "padding", &obj);
1533 	if (obj != NULL) {
1534 		uint32_t padding = cfg_obj_asuint32(obj);
1535 		if (padding > 512U) {
1536 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
1537 				    "server padding value cannot "
1538 				    "exceed 512: lowering");
1539 			padding = 512U;
1540 		}
1541 		CHECK(dns_peer_setpadding(peer, (uint16_t)padding));
1542 	}
1543 
1544 	obj = NULL;
1545 	(void)cfg_map_get(cpeer, "tcp-only", &obj);
1546 	if (obj != NULL) {
1547 		CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
1548 	}
1549 
1550 	obj = NULL;
1551 	(void)cfg_map_get(cpeer, "tcp-keepalive", &obj);
1552 	if (obj != NULL) {
1553 		CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj)));
1554 	}
1555 
1556 	obj = NULL;
1557 	(void)cfg_map_get(cpeer, "transfers", &obj);
1558 	if (obj != NULL) {
1559 		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1560 	}
1561 
1562 	obj = NULL;
1563 	(void)cfg_map_get(cpeer, "transfer-format", &obj);
1564 	if (obj != NULL) {
1565 		str = cfg_obj_asstring(obj);
1566 		if (strcasecmp(str, "many-answers") == 0) {
1567 			CHECK(dns_peer_settransferformat(peer,
1568 							 dns_many_answers));
1569 		} else if (strcasecmp(str, "one-answer") == 0) {
1570 			CHECK(dns_peer_settransferformat(peer, dns_one_answer));
1571 		} else {
1572 			UNREACHABLE();
1573 		}
1574 	}
1575 
1576 	obj = NULL;
1577 	(void)cfg_map_get(cpeer, "keys", &obj);
1578 	if (obj != NULL) {
1579 		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1580 		if (result != ISC_R_SUCCESS) {
1581 			goto cleanup;
1582 		}
1583 	}
1584 
1585 	obj = NULL;
1586 	if (na.family == AF_INET) {
1587 		(void)cfg_map_get(cpeer, "transfer-source", &obj);
1588 	} else {
1589 		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1590 	}
1591 	if (obj != NULL) {
1592 		result = dns_peer_settransfersource(peer,
1593 						    cfg_obj_assockaddr(obj));
1594 		if (result != ISC_R_SUCCESS) {
1595 			goto cleanup;
1596 		}
1597 		named_add_reserved_dispatch(named_g_server,
1598 					    cfg_obj_assockaddr(obj));
1599 	}
1600 
1601 	obj = NULL;
1602 	if (na.family == AF_INET) {
1603 		(void)cfg_map_get(cpeer, "notify-source", &obj);
1604 	} else {
1605 		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1606 	}
1607 	if (obj != NULL) {
1608 		result = dns_peer_setnotifysource(peer,
1609 						  cfg_obj_assockaddr(obj));
1610 		if (result != ISC_R_SUCCESS) {
1611 			goto cleanup;
1612 		}
1613 		named_add_reserved_dispatch(named_g_server,
1614 					    cfg_obj_assockaddr(obj));
1615 	}
1616 
1617 	obj = NULL;
1618 	if (na.family == AF_INET) {
1619 		(void)cfg_map_get(cpeer, "query-source", &obj);
1620 	} else {
1621 		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
1622 	}
1623 	if (obj != NULL) {
1624 		result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj));
1625 		if (result != ISC_R_SUCCESS) {
1626 			goto cleanup;
1627 		}
1628 		named_add_reserved_dispatch(named_g_server,
1629 					    cfg_obj_assockaddr(obj));
1630 	}
1631 
1632 	*peerp = peer;
1633 	return (ISC_R_SUCCESS);
1634 
1635 cleanup:
1636 	dns_peer_detach(&peer);
1637 	return (result);
1638 }
1639 
1640 static isc_result_t
1641 configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
1642 		const dns_dyndbctx_t *dctx) {
1643 	isc_result_t result = ISC_R_SUCCESS;
1644 	const cfg_obj_t *obj;
1645 	const char *name, *library;
1646 
1647 	/* Get the name of the dyndb instance and the library path . */
1648 	name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name"));
1649 	library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library"));
1650 
1651 	obj = cfg_tuple_get(dyndb, "parameters");
1652 	if (obj != NULL) {
1653 		result = dns_dyndb_load(library, name, cfg_obj_asstring(obj),
1654 					cfg_obj_file(obj), cfg_obj_line(obj),
1655 					mctx, dctx);
1656 	}
1657 
1658 	if (result != ISC_R_SUCCESS) {
1659 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1660 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1661 			      "dynamic database '%s' configuration failed: %s",
1662 			      name, isc_result_totext(result));
1663 	}
1664 	return (result);
1665 }
1666 
1667 static isc_result_t
1668 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1669 	isc_result_t result;
1670 	const cfg_obj_t *algorithms;
1671 	const cfg_listelt_t *element;
1672 	const char *str;
1673 	dns_fixedname_t fixed;
1674 	dns_name_t *name;
1675 	isc_buffer_t b;
1676 
1677 	name = dns_fixedname_initname(&fixed);
1678 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1679 	isc_buffer_constinit(&b, str, strlen(str));
1680 	isc_buffer_add(&b, strlen(str));
1681 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1682 
1683 	algorithms = cfg_tuple_get(disabled, "algorithms");
1684 	for (element = cfg_list_first(algorithms); element != NULL;
1685 	     element = cfg_list_next(element))
1686 	{
1687 		isc_textregion_t r;
1688 		dns_secalg_t alg;
1689 
1690 		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1691 		r.length = strlen(r.base);
1692 
1693 		result = dns_secalg_fromtext(&alg, &r);
1694 		if (result != ISC_R_SUCCESS) {
1695 			uint8_t ui;
1696 			result = isc_parse_uint8(&ui, r.base, 10);
1697 			alg = ui;
1698 		}
1699 		if (result != ISC_R_SUCCESS) {
1700 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1701 				    ISC_LOG_ERROR, "invalid algorithm");
1702 			CHECK(result);
1703 		}
1704 		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1705 	}
1706 cleanup:
1707 	return (result);
1708 }
1709 
1710 static isc_result_t
1711 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1712 	isc_result_t result;
1713 	const cfg_obj_t *digests;
1714 	const cfg_listelt_t *element;
1715 	const char *str;
1716 	dns_fixedname_t fixed;
1717 	dns_name_t *name;
1718 	isc_buffer_t b;
1719 
1720 	name = dns_fixedname_initname(&fixed);
1721 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1722 	isc_buffer_constinit(&b, str, strlen(str));
1723 	isc_buffer_add(&b, strlen(str));
1724 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1725 
1726 	digests = cfg_tuple_get(disabled, "digests");
1727 	for (element = cfg_list_first(digests); element != NULL;
1728 	     element = cfg_list_next(element))
1729 	{
1730 		isc_textregion_t r;
1731 		dns_dsdigest_t digest;
1732 
1733 		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1734 		r.length = strlen(r.base);
1735 
1736 		/* disable_ds_digests handles numeric values. */
1737 		result = dns_dsdigest_fromtext(&digest, &r);
1738 		if (result != ISC_R_SUCCESS) {
1739 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1740 				    ISC_LOG_ERROR, "invalid algorithm");
1741 			CHECK(result);
1742 		}
1743 		CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
1744 	}
1745 cleanup:
1746 	return (result);
1747 }
1748 
1749 static bool
1750 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1751 	const cfg_listelt_t *element;
1752 	dns_fixedname_t fixed;
1753 	dns_name_t *name;
1754 	isc_result_t result;
1755 	const cfg_obj_t *value;
1756 	const char *str;
1757 	isc_buffer_t b;
1758 
1759 	name = dns_fixedname_initname(&fixed);
1760 
1761 	for (element = cfg_list_first(disablelist); element != NULL;
1762 	     element = cfg_list_next(element))
1763 	{
1764 		value = cfg_listelt_value(element);
1765 		str = cfg_obj_asstring(value);
1766 		isc_buffer_constinit(&b, str, strlen(str));
1767 		isc_buffer_add(&b, strlen(str));
1768 		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
1769 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1770 		if (dns_name_equal(name, zonename)) {
1771 			return (true);
1772 		}
1773 	}
1774 	return (false);
1775 }
1776 
1777 static isc_result_t
1778 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
1779 	     isc_mem_t *mctx) {
1780 	char **argv = NULL;
1781 	unsigned int i;
1782 	isc_result_t result = ISC_R_SUCCESS;
1783 
1784 	CHECK(dns_zone_getdbtype(zone, &argv, mctx));
1785 
1786 	/*
1787 	 * Check that all the arguments match.
1788 	 */
1789 	for (i = 0; i < dbtypec; i++) {
1790 		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
1791 			CHECK(ISC_R_FAILURE);
1792 
1793 			/*
1794 			 * Check that there are not extra arguments.
1795 			 */
1796 		}
1797 	}
1798 
1799 	/*
1800 	 * Check that there are not extra arguments.
1801 	 */
1802 	if (i == dbtypec && argv[i] != NULL) {
1803 		result = ISC_R_FAILURE;
1804 	}
1805 
1806 cleanup:
1807 	isc_mem_free(mctx, argv);
1808 	return (result);
1809 }
1810 
1811 static isc_result_t
1812 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
1813 	isc_result_t result;
1814 	isc_stats_t *zoneqrystats;
1815 
1816 	dns_zone_setstatlevel(zone, level);
1817 
1818 	zoneqrystats = NULL;
1819 	if (level == dns_zonestat_full) {
1820 		result = isc_stats_create(mctx, &zoneqrystats,
1821 					  ns_statscounter_max);
1822 		if (result != ISC_R_SUCCESS) {
1823 			return (result);
1824 		}
1825 	}
1826 	dns_zone_setrequeststats(zone, zoneqrystats);
1827 	if (zoneqrystats != NULL) {
1828 		isc_stats_detach(&zoneqrystats);
1829 	}
1830 
1831 	return (ISC_R_SUCCESS);
1832 }
1833 
1834 static named_cache_t *
1835 cachelist_find(named_cachelist_t *cachelist, const char *cachename,
1836 	       dns_rdataclass_t rdclass) {
1837 	named_cache_t *nsc;
1838 
1839 	for (nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
1840 	     nsc = ISC_LIST_NEXT(nsc, link))
1841 	{
1842 		if (nsc->rdclass == rdclass &&
1843 		    strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1844 		{
1845 			return (nsc);
1846 		}
1847 	}
1848 
1849 	return (NULL);
1850 }
1851 
1852 static bool
1853 cache_reusable(dns_view_t *originview, dns_view_t *view,
1854 	       bool new_zero_no_soattl) {
1855 	if (originview->rdclass != view->rdclass ||
1856 	    originview->checknames != view->checknames ||
1857 	    dns_resolver_getzeronosoattl(originview->resolver) !=
1858 		    new_zero_no_soattl ||
1859 	    originview->acceptexpired != view->acceptexpired ||
1860 	    originview->enablevalidation != view->enablevalidation ||
1861 	    originview->maxcachettl != view->maxcachettl ||
1862 	    originview->maxncachettl != view->maxncachettl)
1863 	{
1864 		return (false);
1865 	}
1866 
1867 	return (true);
1868 }
1869 
1870 static bool
1871 cache_sharable(dns_view_t *originview, dns_view_t *view,
1872 	       bool new_zero_no_soattl, uint64_t new_max_cache_size,
1873 	       uint32_t new_stale_ttl, uint32_t new_stale_refresh_time) {
1874 	/*
1875 	 * If the cache cannot even reused for the same view, it cannot be
1876 	 * shared with other views.
1877 	 */
1878 	if (!cache_reusable(originview, view, new_zero_no_soattl)) {
1879 		return (false);
1880 	}
1881 
1882 	/*
1883 	 * Check other cache related parameters that must be consistent among
1884 	 * the sharing views.
1885 	 */
1886 	if (dns_cache_getservestalettl(originview->cache) != new_stale_ttl ||
1887 	    dns_cache_getservestalerefresh(originview->cache) !=
1888 		    new_stale_refresh_time ||
1889 	    dns_cache_getcachesize(originview->cache) != new_max_cache_size)
1890 	{
1891 		return (false);
1892 	}
1893 
1894 	return (true);
1895 }
1896 
1897 /*
1898  * Callback from DLZ configure when the driver sets up a writeable zone
1899  */
1900 static isc_result_t
1901 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
1902 	dns_name_t *origin = dns_zone_getorigin(zone);
1903 	dns_rdataclass_t zclass = view->rdclass;
1904 	isc_result_t result;
1905 
1906 	result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
1907 	if (result != ISC_R_SUCCESS) {
1908 		return (result);
1909 	}
1910 	dns_zone_setstats(zone, named_g_server->zonestats);
1911 
1912 	return (named_zone_configure_writeable_dlz(dlzdb, zone, zclass,
1913 						   origin));
1914 }
1915 
1916 static isc_result_t
1917 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1918 	      unsigned int prefixlen, const char *server, const char *contact) {
1919 	char reverse[48 + sizeof("ip6.arpa.")] = { 0 };
1920 	char buf[sizeof("x.x.")];
1921 	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1922 	const char *sep = ": view ";
1923 	const char *viewname = view->name;
1924 	const unsigned char *s6;
1925 	dns_fixedname_t fixed;
1926 	dns_name_t *name;
1927 	dns_zone_t *zone = NULL;
1928 	int dns64_dbtypec = 4;
1929 	isc_buffer_t b;
1930 	isc_result_t result;
1931 
1932 	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1933 		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1934 
1935 	if (!strcmp(viewname, "_default")) {
1936 		sep = "";
1937 		viewname = "";
1938 	}
1939 
1940 	/*
1941 	 * Construct the reverse name of the zone.
1942 	 */
1943 	s6 = na->type.in6.s6_addr;
1944 	while (prefixlen > 0) {
1945 		prefixlen -= 8;
1946 		snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen / 8] & 0xf,
1947 			 (s6[prefixlen / 8] >> 4) & 0xf);
1948 		strlcat(reverse, buf, sizeof(reverse));
1949 	}
1950 	strlcat(reverse, "ip6.arpa.", sizeof(reverse));
1951 
1952 	/*
1953 	 * Create the actual zone.
1954 	 */
1955 	if (server != NULL) {
1956 		dns64_dbtype[2] = server;
1957 	}
1958 	if (contact != NULL) {
1959 		dns64_dbtype[3] = contact;
1960 	}
1961 	name = dns_fixedname_initname(&fixed);
1962 	isc_buffer_constinit(&b, reverse, strlen(reverse));
1963 	isc_buffer_add(&b, strlen(reverse));
1964 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1965 	CHECK(dns_zone_create(&zone, mctx));
1966 	CHECK(dns_zone_setorigin(zone, name));
1967 	dns_zone_setview(zone, view);
1968 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
1969 	dns_zone_setclass(zone, view->rdclass);
1970 	dns_zone_settype(zone, dns_zone_primary);
1971 	dns_zone_setstats(zone, named_g_server->zonestats);
1972 	dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype);
1973 	if (view->queryacl != NULL) {
1974 		dns_zone_setqueryacl(zone, view->queryacl);
1975 	}
1976 	if (view->queryonacl != NULL) {
1977 		dns_zone_setqueryonacl(zone, view->queryonacl);
1978 	}
1979 	dns_zone_setdialup(zone, dns_dialuptype_no);
1980 	dns_zone_setnotifytype(zone, dns_notifytype_no);
1981 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
1982 	CHECK(setquerystats(zone, mctx, dns_zonestat_none)); /* XXXMPA */
1983 	CHECK(dns_view_addzone(view, zone));
1984 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1985 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1986 		      "dns64 reverse zone%s%s: %s", sep, viewname, reverse);
1987 
1988 cleanup:
1989 	if (zone != NULL) {
1990 		dns_zone_detach(&zone);
1991 	}
1992 	return (result);
1993 }
1994 
1995 #ifdef USE_DNSRPS
1996 typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
1997 struct conf_dnsrps_ctx {
1998 	isc_result_t result;
1999 	char *cstr;
2000 	size_t cstr_size;
2001 	isc_mem_t *mctx;
2002 };
2003 
2004 /*
2005  * Add to the DNSRPS configuration string.
2006  */
2007 static bool
2008 conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
2009 	size_t new_len, cur_len, new_cstr_size;
2010 	char *new_cstr;
2011 	va_list args;
2012 
2013 	if (ctx->cstr == NULL) {
2014 		ctx->cstr = isc_mem_get(ctx->mctx, 256);
2015 		ctx->cstr[0] = '\0';
2016 		ctx->cstr_size = 256;
2017 	}
2018 
2019 	cur_len = strlen(ctx->cstr);
2020 	va_start(args, p);
2021 	new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p,
2022 			    args) +
2023 		  1;
2024 	va_end(args);
2025 
2026 	if (cur_len + new_len <= ctx->cstr_size) {
2027 		return (true);
2028 	}
2029 
2030 	new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256;
2031 	new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
2032 
2033 	memmove(new_cstr, ctx->cstr, cur_len);
2034 	isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
2035 	ctx->cstr_size = new_cstr_size;
2036 	ctx->cstr = new_cstr;
2037 
2038 	/* cannot use args twice after a single va_start()on some systems */
2039 	va_start(args, p);
2040 	vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
2041 	va_end(args);
2042 	return (true);
2043 }
2044 
2045 /*
2046  * Get an DNSRPS configuration value using the global and view options
2047  * for the default.  Return false upon failure.
2048  */
2049 static bool
2050 conf_dnsrps_get(const cfg_obj_t **sub_obj, const cfg_obj_t **maps,
2051 		const cfg_obj_t *obj, const char *name,
2052 		conf_dnsrps_ctx_t *ctx) {
2053 	if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
2054 		*sub_obj = NULL;
2055 		return (false);
2056 	}
2057 
2058 	*sub_obj = cfg_tuple_get(obj, name);
2059 	if (cfg_obj_isvoid(*sub_obj)) {
2060 		*sub_obj = NULL;
2061 		if (maps != NULL &&
2062 		    ISC_R_SUCCESS != named_config_get(maps, name, sub_obj))
2063 		{
2064 			*sub_obj = NULL;
2065 		}
2066 	}
2067 	return (true);
2068 }
2069 
2070 /*
2071  * Handle a DNSRPS boolean configuration value with the global and view
2072  * options providing the default.
2073  */
2074 static void
2075 conf_dnsrps_yes_no(const cfg_obj_t *obj, const char *name,
2076 		   conf_dnsrps_ctx_t *ctx) {
2077 	const cfg_obj_t *sub_obj;
2078 
2079 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2080 		return;
2081 	}
2082 	if (sub_obj == NULL) {
2083 		return;
2084 	}
2085 	if (ctx == NULL) {
2086 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2087 			    "\"%s\" without \"dnsrps-enable yes\"", name);
2088 		return;
2089 	}
2090 
2091 	conf_dnsrps_sadd(ctx, " %s %s", name,
2092 			 cfg_obj_asboolean(sub_obj) ? "yes" : "no");
2093 }
2094 
2095 static void
2096 conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
2097 		conf_dnsrps_ctx_t *ctx) {
2098 	const cfg_obj_t *sub_obj;
2099 
2100 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2101 		return;
2102 	}
2103 	if (sub_obj == NULL) {
2104 		return;
2105 	}
2106 	if (ctx == NULL) {
2107 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2108 			    "\"%s\" without \"dnsrps-enable yes\"", name);
2109 		return;
2110 	}
2111 
2112 	if (cfg_obj_isduration(sub_obj)) {
2113 		conf_dnsrps_sadd(ctx, " %s %d", name,
2114 				 cfg_obj_asduration(sub_obj));
2115 	} else {
2116 		conf_dnsrps_sadd(ctx, " %s %d", name,
2117 				 cfg_obj_asuint32(sub_obj));
2118 	}
2119 }
2120 
2121 /*
2122  * Convert the parsed RPZ configuration statement to a string for
2123  * dns_rpz_new_zones().
2124  */
2125 static isc_result_t
2126 conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps, bool nsip_enabled,
2127 	    bool nsdname_enabled, dns_rpz_zbits_t *nsip_on,
2128 	    dns_rpz_zbits_t *nsdname_on, char **rps_cstr, size_t *rps_cstr_size,
2129 	    const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element) {
2130 	conf_dnsrps_ctx_t ctx;
2131 	const cfg_obj_t *zone_obj, *obj;
2132 	dns_rpz_num_t rpz_num;
2133 	bool on;
2134 	const char *s;
2135 
2136 	memset(&ctx, 0, sizeof(ctx));
2137 	ctx.result = ISC_R_SUCCESS;
2138 	ctx.mctx = view->mctx;
2139 
2140 	for (rpz_num = 0; zone_element != NULL && ctx.result == ISC_R_SUCCESS;
2141 	     ++rpz_num)
2142 	{
2143 		zone_obj = cfg_listelt_value(zone_element);
2144 
2145 		s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
2146 		conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
2147 
2148 		obj = cfg_tuple_get(zone_obj, "policy");
2149 		if (!cfg_obj_isvoid(obj)) {
2150 			s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2151 			conf_dnsrps_sadd(&ctx, " policy %s", s);
2152 			if (strcasecmp(s, "cname") == 0) {
2153 				s = cfg_obj_asstring(
2154 					cfg_tuple_get(obj, "cname"));
2155 				conf_dnsrps_sadd(&ctx, " %s", s);
2156 			}
2157 		}
2158 
2159 		conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
2160 		conf_dnsrps_yes_no(zone_obj, "log", &ctx);
2161 		conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
2162 		obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2163 		if (!cfg_obj_isvoid(obj)) {
2164 			if (cfg_obj_asboolean(obj)) {
2165 				*nsip_on |= DNS_RPZ_ZBIT(rpz_num);
2166 			} else {
2167 				*nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
2168 			}
2169 		}
2170 		on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2171 		if (nsip_enabled != on) {
2172 			conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes "
2173 						  : " nsip-enable no ");
2174 		}
2175 		obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2176 		if (!cfg_obj_isvoid(obj)) {
2177 			if (cfg_obj_asboolean(obj)) {
2178 				*nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
2179 			} else {
2180 				*nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
2181 			}
2182 		}
2183 		on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2184 		if (nsdname_enabled != on) {
2185 			conf_dnsrps_sadd(&ctx, on ? " nsdname-enable yes "
2186 						  : " nsdname-enable no ");
2187 		}
2188 		conf_dnsrps_sadd(&ctx, ";\n");
2189 		zone_element = cfg_list_next(zone_element);
2190 	}
2191 
2192 	conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
2193 	conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
2194 	conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
2195 	conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
2196 	conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
2197 	if (!nsip_enabled) {
2198 		conf_dnsrps_sadd(&ctx, " nsip-enable no ");
2199 	}
2200 	if (!nsdname_enabled) {
2201 		conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
2202 	}
2203 
2204 	/*
2205 	 * Get the general dnsrpzd parameters from the response-policy
2206 	 * statement in the view and the general options.
2207 	 */
2208 	if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
2209 	    obj != NULL)
2210 	{
2211 		conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
2212 	}
2213 
2214 	if (ctx.result == ISC_R_SUCCESS) {
2215 		*rps_cstr = ctx.cstr;
2216 		*rps_cstr_size = ctx.cstr_size;
2217 	} else {
2218 		if (ctx.cstr != NULL) {
2219 			isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
2220 		}
2221 		*rps_cstr = NULL;
2222 		*rps_cstr_size = 0;
2223 	}
2224 	return (ctx.result);
2225 }
2226 #endif /* ifdef USE_DNSRPS */
2227 
2228 static isc_result_t
2229 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2230 		   const char *str, const char *msg) {
2231 	isc_result_t result;
2232 
2233 	result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx);
2234 	if (result != ISC_R_SUCCESS) {
2235 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2236 			    "invalid %s '%s'", msg, str);
2237 	}
2238 	return (result);
2239 }
2240 
2241 static isc_result_t
2242 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2243 		    const char *str, const dns_name_t *origin) {
2244 	isc_result_t result;
2245 
2246 	result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE,
2247 				      view->mctx);
2248 	if (result != ISC_R_SUCCESS) {
2249 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2250 			    "invalid zone '%s'", str);
2251 	}
2252 	return (result);
2253 }
2254 
2255 static isc_result_t
2256 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
2257 		   bool recursive_only_default, bool add_soa_default,
2258 		   dns_ttl_t ttl_default, uint32_t minupdateinterval_default,
2259 		   const dns_rpz_zone_t *old, bool *old_rpz_okp) {
2260 	const cfg_obj_t *rpz_obj, *obj;
2261 	const char *str;
2262 	dns_rpz_zone_t *zone = NULL;
2263 	isc_result_t result;
2264 	dns_rpz_num_t rpz_num;
2265 
2266 	REQUIRE(old != NULL || !*old_rpz_okp);
2267 
2268 	rpz_obj = cfg_listelt_value(element);
2269 
2270 	if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
2271 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2272 			    "limit of %d response policy zones exceeded",
2273 			    DNS_RPZ_MAX_ZONES);
2274 		return (ISC_R_FAILURE);
2275 	}
2276 
2277 	result = dns_rpz_new_zone(view->rpzs, &zone);
2278 	if (result != ISC_R_SUCCESS) {
2279 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2280 			    "Error creating new RPZ zone : %s",
2281 			    isc_result_totext(result));
2282 		return (result);
2283 	}
2284 
2285 	obj = cfg_tuple_get(rpz_obj, "recursive-only");
2286 	if (cfg_obj_isvoid(obj) ? recursive_only_default
2287 				: cfg_obj_asboolean(obj))
2288 	{
2289 		view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num);
2290 	} else {
2291 		view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num);
2292 	}
2293 
2294 	obj = cfg_tuple_get(rpz_obj, "log");
2295 	if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) {
2296 		view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num);
2297 	} else {
2298 		view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num);
2299 	}
2300 
2301 	obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2302 	if (cfg_obj_isduration(obj)) {
2303 		zone->max_policy_ttl = cfg_obj_asduration(obj);
2304 	} else {
2305 		zone->max_policy_ttl = ttl_default;
2306 	}
2307 	if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl) {
2308 		*old_rpz_okp = false;
2309 	}
2310 
2311 	obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2312 	if (cfg_obj_isduration(obj)) {
2313 		zone->min_update_interval = cfg_obj_asduration(obj);
2314 	} else {
2315 		zone->min_update_interval = minupdateinterval_default;
2316 	}
2317 	if (*old_rpz_okp &&
2318 	    zone->min_update_interval != old->min_update_interval)
2319 	{
2320 		*old_rpz_okp = false;
2321 	}
2322 
2323 	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
2324 	result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone");
2325 	if (result != ISC_R_SUCCESS) {
2326 		return (result);
2327 	}
2328 	if (dns_name_equal(&zone->origin, dns_rootname)) {
2329 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2330 			    "invalid zone name '%s'", str);
2331 		return (DNS_R_EMPTYLABEL);
2332 	}
2333 	if (!view->rpzs->p.dnsrps_enabled) {
2334 		for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1;
2335 		     ++rpz_num)
2336 		{
2337 			if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
2338 					   &zone->origin))
2339 			{
2340 				cfg_obj_log(rpz_obj, named_g_lctx,
2341 					    DNS_RPZ_ERROR_LEVEL,
2342 					    "duplicate '%s'", str);
2343 				result = DNS_R_DUPLICATE;
2344 				return (result);
2345 			}
2346 		}
2347 	}
2348 	if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) {
2349 		*old_rpz_okp = false;
2350 	}
2351 
2352 	result = configure_rpz_name2(view, rpz_obj, &zone->client_ip,
2353 				     DNS_RPZ_CLIENT_IP_ZONE, &zone->origin);
2354 	if (result != ISC_R_SUCCESS) {
2355 		return (result);
2356 	}
2357 
2358 	result = configure_rpz_name2(view, rpz_obj, &zone->ip, DNS_RPZ_IP_ZONE,
2359 				     &zone->origin);
2360 	if (result != ISC_R_SUCCESS) {
2361 		return (result);
2362 	}
2363 
2364 	result = configure_rpz_name2(view, rpz_obj, &zone->nsdname,
2365 				     DNS_RPZ_NSDNAME_ZONE, &zone->origin);
2366 	if (result != ISC_R_SUCCESS) {
2367 		return (result);
2368 	}
2369 
2370 	result = configure_rpz_name2(view, rpz_obj, &zone->nsip,
2371 				     DNS_RPZ_NSIP_ZONE, &zone->origin);
2372 	if (result != ISC_R_SUCCESS) {
2373 		return (result);
2374 	}
2375 
2376 	result = configure_rpz_name(view, rpz_obj, &zone->passthru,
2377 				    DNS_RPZ_PASSTHRU_NAME, "name");
2378 	if (result != ISC_R_SUCCESS) {
2379 		return (result);
2380 	}
2381 
2382 	result = configure_rpz_name(view, rpz_obj, &zone->drop,
2383 				    DNS_RPZ_DROP_NAME, "name");
2384 	if (result != ISC_R_SUCCESS) {
2385 		return (result);
2386 	}
2387 
2388 	result = configure_rpz_name(view, rpz_obj, &zone->tcp_only,
2389 				    DNS_RPZ_TCP_ONLY_NAME, "name");
2390 	if (result != ISC_R_SUCCESS) {
2391 		return (result);
2392 	}
2393 
2394 	obj = cfg_tuple_get(rpz_obj, "policy");
2395 	if (cfg_obj_isvoid(obj)) {
2396 		zone->policy = DNS_RPZ_POLICY_GIVEN;
2397 	} else {
2398 		str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2399 		zone->policy = dns_rpz_str2policy(str);
2400 		INSIST(zone->policy != DNS_RPZ_POLICY_ERROR);
2401 		if (zone->policy == DNS_RPZ_POLICY_CNAME) {
2402 			str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
2403 			result = configure_rpz_name(view, rpz_obj, &zone->cname,
2404 						    str, "cname");
2405 			if (result != ISC_R_SUCCESS) {
2406 				return (result);
2407 			}
2408 		}
2409 	}
2410 	if (*old_rpz_okp && (zone->policy != old->policy ||
2411 			     !dns_name_equal(&old->cname, &zone->cname)))
2412 	{
2413 		*old_rpz_okp = false;
2414 	}
2415 
2416 	obj = cfg_tuple_get(rpz_obj, "add-soa");
2417 	if (cfg_obj_isvoid(obj)) {
2418 		zone->addsoa = add_soa_default;
2419 	} else {
2420 		zone->addsoa = cfg_obj_asboolean(obj);
2421 	}
2422 	if (*old_rpz_okp && zone->addsoa != old->addsoa) {
2423 		*old_rpz_okp = false;
2424 	}
2425 
2426 	return (ISC_R_SUCCESS);
2427 }
2428 
2429 static isc_result_t
2430 configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
2431 	      const cfg_obj_t *rpz_obj, bool *old_rpz_okp) {
2432 	bool dnsrps_enabled;
2433 	const cfg_listelt_t *zone_element;
2434 	char *rps_cstr;
2435 	size_t rps_cstr_size;
2436 	const cfg_obj_t *sub_obj;
2437 	bool recursive_only_default, add_soa_default;
2438 	bool nsip_enabled, nsdname_enabled;
2439 	dns_rpz_zbits_t nsip_on, nsdname_on;
2440 	dns_ttl_t ttl_default;
2441 	uint32_t minupdateinterval_default;
2442 	dns_rpz_zones_t *zones;
2443 	const dns_rpz_zones_t *old;
2444 	bool pview_must_detach = false;
2445 	const dns_rpz_zone_t *old_zone;
2446 	isc_result_t result;
2447 	int i;
2448 
2449 	*old_rpz_okp = false;
2450 
2451 	zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
2452 	if (zone_element == NULL) {
2453 		return (ISC_R_SUCCESS);
2454 	}
2455 
2456 	nsip_enabled = true;
2457 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2458 	if (!cfg_obj_isvoid(sub_obj)) {
2459 		nsip_enabled = cfg_obj_asboolean(sub_obj);
2460 	}
2461 	nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2462 
2463 	nsdname_enabled = true;
2464 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2465 	if (!cfg_obj_isvoid(sub_obj)) {
2466 		nsdname_enabled = cfg_obj_asboolean(sub_obj);
2467 	}
2468 	nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2469 
2470 	/*
2471 	 * "dnsrps-enable yes|no" can be either a global or response-policy
2472 	 * clause.
2473 	 */
2474 	dnsrps_enabled = false;
2475 	rps_cstr = NULL;
2476 	rps_cstr_size = 0;
2477 	sub_obj = NULL;
2478 	(void)named_config_get(maps, "dnsrps-enable", &sub_obj);
2479 	if (sub_obj != NULL) {
2480 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2481 	}
2482 	sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
2483 	if (!cfg_obj_isvoid(sub_obj)) {
2484 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2485 	}
2486 #ifndef USE_DNSRPS
2487 	if (dnsrps_enabled) {
2488 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2489 			    "\"dnsrps-enable yes\" but"
2490 			    " without `./configure --enable-dnsrps`");
2491 		return (ISC_R_FAILURE);
2492 	}
2493 #else  /* ifndef USE_DNSRPS */
2494 	if (dnsrps_enabled) {
2495 		if (librpz == NULL) {
2496 			cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2497 				    "\"dnsrps-enable yes\" but %s",
2498 				    librpz_lib_open_emsg.c);
2499 			return (ISC_R_FAILURE);
2500 		}
2501 
2502 		/*
2503 		 * Generate the DNS Response Policy Service
2504 		 * configuration string.
2505 		 */
2506 		result = conf_dnsrps(view, maps, nsip_enabled, nsdname_enabled,
2507 				     &nsip_on, &nsdname_on, &rps_cstr,
2508 				     &rps_cstr_size, rpz_obj, zone_element);
2509 		if (result != ISC_R_SUCCESS) {
2510 			return (result);
2511 		}
2512 	}
2513 #endif /* ifndef USE_DNSRPS */
2514 
2515 	result = dns_rpz_new_zones(view->mctx, named_g_taskmgr,
2516 				   named_g_timermgr, rps_cstr, rps_cstr_size,
2517 				   &view->rpzs);
2518 	if (result != ISC_R_SUCCESS) {
2519 		return (result);
2520 	}
2521 
2522 	zones = view->rpzs;
2523 
2524 	zones->p.nsip_on = nsip_on;
2525 	zones->p.nsdname_on = nsdname_on;
2526 
2527 	sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
2528 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2529 		recursive_only_default = false;
2530 	} else {
2531 		recursive_only_default = true;
2532 	}
2533 
2534 	sub_obj = cfg_tuple_get(rpz_obj, "add-soa");
2535 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2536 		add_soa_default = false;
2537 	} else {
2538 		add_soa_default = true;
2539 	}
2540 
2541 	sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
2542 	if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
2543 		zones->p.break_dnssec = true;
2544 	} else {
2545 		zones->p.break_dnssec = false;
2546 	}
2547 
2548 	sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2549 	if (cfg_obj_isduration(sub_obj)) {
2550 		ttl_default = cfg_obj_asduration(sub_obj);
2551 	} else {
2552 		ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
2553 	}
2554 
2555 	sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2556 	if (cfg_obj_isduration(sub_obj)) {
2557 		minupdateinterval_default = cfg_obj_asduration(sub_obj);
2558 	} else {
2559 		minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
2560 	}
2561 
2562 	sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
2563 	if (cfg_obj_isuint32(sub_obj)) {
2564 		zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
2565 	} else {
2566 		zones->p.min_ns_labels = 2;
2567 	}
2568 
2569 	sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
2570 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2571 		zones->p.qname_wait_recurse = true;
2572 	} else {
2573 		zones->p.qname_wait_recurse = false;
2574 	}
2575 
2576 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-wait-recurse");
2577 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2578 		zones->p.nsdname_wait_recurse = true;
2579 	} else {
2580 		zones->p.nsdname_wait_recurse = false;
2581 	}
2582 
2583 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse");
2584 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2585 		zones->p.nsip_wait_recurse = true;
2586 	} else {
2587 		zones->p.nsip_wait_recurse = false;
2588 	}
2589 
2590 	if (pview != NULL) {
2591 		old = pview->rpzs;
2592 	} else {
2593 		result = dns_viewlist_find(&named_g_server->viewlist,
2594 					   view->name, view->rdclass, &pview);
2595 		if (result == ISC_R_SUCCESS) {
2596 			pview_must_detach = true;
2597 			old = pview->rpzs;
2598 		} else {
2599 			old = NULL;
2600 		}
2601 	}
2602 
2603 	if (old == NULL) {
2604 		*old_rpz_okp = false;
2605 	} else {
2606 		*old_rpz_okp = true;
2607 	}
2608 
2609 	for (i = 0; zone_element != NULL;
2610 	     ++i, zone_element = cfg_list_next(zone_element))
2611 	{
2612 		INSIST(!*old_rpz_okp || old != NULL);
2613 		if (*old_rpz_okp && i < old->p.num_zones) {
2614 			old_zone = old->zones[i];
2615 		} else {
2616 			*old_rpz_okp = false;
2617 			old_zone = NULL;
2618 		}
2619 		result = configure_rpz_zone(
2620 			view, zone_element, recursive_only_default,
2621 			add_soa_default, ttl_default, minupdateinterval_default,
2622 			old_zone, old_rpz_okp);
2623 		if (result != ISC_R_SUCCESS) {
2624 			if (pview_must_detach) {
2625 				dns_view_detach(&pview);
2626 			}
2627 			return (result);
2628 		}
2629 	}
2630 
2631 	/*
2632 	 * If this is a reloading and the parameters and list of policy
2633 	 * zones are unchanged, then use the same policy data.
2634 	 * Data for individual zones that must be reloaded will be merged.
2635 	 */
2636 	if (*old_rpz_okp) {
2637 		if (old != NULL &&
2638 		    memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
2639 		{
2640 			*old_rpz_okp = false;
2641 		} else if ((old == NULL || old->rps_cstr == NULL) !=
2642 			   (zones->rps_cstr == NULL))
2643 		{
2644 			*old_rpz_okp = false;
2645 		} else if (old != NULL && zones->rps_cstr != NULL &&
2646 			   strcmp(old->rps_cstr, zones->rps_cstr) != 0)
2647 		{
2648 			*old_rpz_okp = false;
2649 		}
2650 	}
2651 
2652 	if (*old_rpz_okp) {
2653 		dns_rpz_shutdown_rpzs(view->rpzs);
2654 		dns_rpz_detach_rpzs(&view->rpzs);
2655 		dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
2656 		dns_rpz_detach_rpzs(&pview->rpzs);
2657 	} else if (old != NULL && pview != NULL) {
2658 		++pview->rpzs->rpz_ver;
2659 		view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
2660 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
2661 			    "updated RPZ policy: version %d",
2662 			    view->rpzs->rpz_ver);
2663 	}
2664 
2665 	if (pview_must_detach) {
2666 		dns_view_detach(&pview);
2667 	}
2668 
2669 	return (ISC_R_SUCCESS);
2670 }
2671 
2672 static void
2673 catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2674 	catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2675 	isc_result_t result;
2676 	dns_forwarders_t *dnsforwarders = NULL;
2677 	dns_name_t *name = NULL;
2678 	isc_buffer_t namebuf;
2679 	isc_buffer_t *confbuf;
2680 	char nameb[DNS_NAME_FORMATSIZE];
2681 	const cfg_obj_t *zlist = NULL;
2682 	cfg_obj_t *zoneconf = NULL;
2683 	cfg_obj_t *zoneobj = NULL;
2684 	ns_cfgctx_t *cfg;
2685 	dns_zone_t *zone = NULL;
2686 
2687 	/*
2688 	 * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
2689 	 * is true, so this is expected to be non-NULL.
2690 	 */
2691 	cfg = (ns_cfgctx_t *)ev->view->new_zone_config;
2692 	if (cfg == NULL) {
2693 		CHECK(ISC_R_FAILURE);
2694 	}
2695 
2696 	name = dns_catz_entry_getname(ev->entry);
2697 
2698 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
2699 	dns_name_totext(name, true, &namebuf);
2700 	isc_buffer_putuint8(&namebuf, 0);
2701 
2702 	result = dns_fwdtable_find(ev->view->fwdtable, name, NULL,
2703 				   &dnsforwarders);
2704 	if (result == ISC_R_SUCCESS &&
2705 	    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
2706 	{
2707 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2708 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2709 			      "catz: catz_addmodzone_taskaction: "
2710 			      "zone '%s' will not be processed because of the "
2711 			      "explicitly configured forwarding for that zone",
2712 			      nameb);
2713 		goto cleanup;
2714 	}
2715 
2716 	result = dns_view_findzone(ev->view, name, &zone);
2717 
2718 	if (ev->mod) {
2719 		dns_catz_zone_t *parentcatz;
2720 
2721 		if (result != ISC_R_SUCCESS) {
2722 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2723 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2724 				      "catz: error \"%s\" while trying to "
2725 				      "modify zone '%s'",
2726 				      isc_result_totext(result), nameb);
2727 			goto cleanup;
2728 		}
2729 
2730 		if (!dns_zone_getadded(zone)) {
2731 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2732 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2733 				      "catz: catz_addmodzone_taskaction: "
2734 				      "zone '%s' is not a dynamically "
2735 				      "added zone",
2736 				      nameb);
2737 			goto cleanup;
2738 		}
2739 
2740 		parentcatz = dns_zone_get_parentcatz(zone);
2741 
2742 		if (parentcatz == NULL) {
2743 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2744 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2745 				      "catz: catz_addmodzone_taskaction: "
2746 				      "zone '%s' exists and is not added by "
2747 				      "a catalog zone, so won't be modified",
2748 				      nameb);
2749 			goto cleanup;
2750 		}
2751 		if (parentcatz != ev->origin) {
2752 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2753 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2754 				      "catz: catz_addmodzone_taskaction: "
2755 				      "zone '%s' exists in multiple "
2756 				      "catalog zones",
2757 				      nameb);
2758 			goto cleanup;
2759 		}
2760 
2761 		dns_zone_detach(&zone);
2762 	} else {
2763 		/* Zone shouldn't already exist when adding */
2764 		if (result == ISC_R_SUCCESS) {
2765 			if (dns_zone_get_parentcatz(zone) == NULL) {
2766 				isc_log_write(
2767 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2768 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2769 					"catz: "
2770 					"catz_addmodzone_taskaction: "
2771 					"zone '%s' will not be added "
2772 					"because it is an explicitly "
2773 					"configured zone",
2774 					nameb);
2775 			} else {
2776 				isc_log_write(
2777 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2778 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2779 					"catz: "
2780 					"catz_addmodzone_taskaction: "
2781 					"zone '%s' will not be added "
2782 					"because another catalog zone "
2783 					"already contains an entry with "
2784 					"that zone",
2785 					nameb);
2786 			}
2787 			goto cleanup;
2788 		} else if (result != ISC_R_NOTFOUND &&
2789 			   result != DNS_R_PARTIALMATCH)
2790 		{
2791 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2792 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2793 				      "catz: error \"%s\" while trying to "
2794 				      "add zone '%s'",
2795 				      isc_result_totext(result), nameb);
2796 			goto cleanup;
2797 		} else { /* this can happen in case of DNS_R_PARTIALMATCH */
2798 			if (zone != NULL) {
2799 				dns_zone_detach(&zone);
2800 			}
2801 		}
2802 	}
2803 	RUNTIME_CHECK(zone == NULL);
2804 	/* Create a config for new zone */
2805 	confbuf = NULL;
2806 	result = dns_catz_generate_zonecfg(ev->origin, ev->entry, &confbuf);
2807 	if (result == ISC_R_SUCCESS) {
2808 		cfg_parser_reset(cfg->add_parser);
2809 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
2810 					  &cfg_type_addzoneconf, 0, &zoneconf);
2811 		isc_buffer_free(&confbuf);
2812 	}
2813 	/*
2814 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer()
2815 	 * failed.
2816 	 */
2817 	if (result != ISC_R_SUCCESS) {
2818 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2819 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2820 			      "catz: error \"%s\" while trying to generate "
2821 			      "config for zone '%s'",
2822 			      isc_result_totext(result), nameb);
2823 		goto cleanup;
2824 	}
2825 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
2826 	if (!cfg_obj_islist(zlist)) {
2827 		CHECK(ISC_R_FAILURE);
2828 	}
2829 
2830 	/* For now we only support adding one zone at a time */
2831 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
2832 
2833 	/* Mark view unfrozen so that zone can be added */
2834 
2835 	result = isc_task_beginexclusive(task);
2836 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2837 	dns_view_thaw(ev->view);
2838 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
2839 				ev->cbd->server->mctx, ev->view,
2840 				&ev->cbd->server->viewlist,
2841 				&ev->cbd->server->kasplist, cfg->actx, true,
2842 				false, true, ev->mod);
2843 	dns_view_freeze(ev->view);
2844 	isc_task_endexclusive(task);
2845 
2846 	if (result != ISC_R_SUCCESS) {
2847 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2848 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2849 			      "catz: failed to configure zone '%s' - %d", nameb,
2850 			      result);
2851 		goto cleanup;
2852 	}
2853 
2854 	/* Is it there yet? */
2855 	CHECK(dns_zt_find(ev->view->zonetable, name, 0, NULL, &zone));
2856 
2857 	/*
2858 	 * Load the zone from the master file.	If this fails, we'll
2859 	 * need to undo the configuration we've done already.
2860 	 */
2861 	result = dns_zone_load(zone, true);
2862 	if (result != ISC_R_SUCCESS) {
2863 		dns_db_t *dbp = NULL;
2864 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2865 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2866 			      "catz: dns_zone_load() failed "
2867 			      "with %s; reverting.",
2868 			      isc_result_totext(result));
2869 
2870 		/* If the zone loaded partially, unload it */
2871 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2872 			dns_db_detach(&dbp);
2873 			dns_zone_unload(zone);
2874 		}
2875 
2876 		/* Remove the zone from the zone table */
2877 		dns_zt_unmount(ev->view->zonetable, zone);
2878 		goto cleanup;
2879 	}
2880 
2881 	/* Flag the zone as having been added at runtime */
2882 	dns_zone_setadded(zone, true);
2883 	dns_zone_set_parentcatz(zone, ev->origin);
2884 
2885 cleanup:
2886 	if (zone != NULL) {
2887 		dns_zone_detach(&zone);
2888 	}
2889 	if (zoneconf != NULL) {
2890 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
2891 	}
2892 	dns_catz_entry_detach(ev->origin, &ev->entry);
2893 	dns_catz_detach_catz(&ev->origin);
2894 	dns_view_weakdetach(&ev->view);
2895 	isc_event_free(ISC_EVENT_PTR(&ev));
2896 }
2897 
2898 static void
2899 catz_delzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2900 	catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2901 	isc_result_t result;
2902 	dns_zone_t *zone = NULL;
2903 	dns_db_t *dbp = NULL;
2904 	char cname[DNS_NAME_FORMATSIZE];
2905 	const char *file;
2906 
2907 	result = isc_task_beginexclusive(task);
2908 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2909 
2910 	dns_name_format(dns_catz_entry_getname(ev->entry), cname,
2911 			DNS_NAME_FORMATSIZE);
2912 	result = dns_view_findzone(ev->view, dns_catz_entry_getname(ev->entry),
2913 				   &zone);
2914 	if (result != ISC_R_SUCCESS) {
2915 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2916 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2917 			      "catz: catz_delzone_taskaction: "
2918 			      "zone '%s' not found",
2919 			      cname);
2920 		goto cleanup;
2921 	}
2922 
2923 	if (!dns_zone_getadded(zone)) {
2924 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2925 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2926 			      "catz: catz_delzone_taskaction: "
2927 			      "zone '%s' is not a dynamically added zone",
2928 			      cname);
2929 		goto cleanup;
2930 	}
2931 
2932 	if (dns_zone_get_parentcatz(zone) != ev->origin) {
2933 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2934 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2935 			      "catz: catz_delzone_taskaction: zone "
2936 			      "'%s' exists in multiple catalog zones",
2937 			      cname);
2938 		goto cleanup;
2939 	}
2940 
2941 	/* Stop answering for this zone */
2942 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2943 		dns_db_detach(&dbp);
2944 		dns_zone_unload(zone);
2945 	}
2946 
2947 	CHECK(dns_zt_unmount(ev->view->zonetable, zone));
2948 	file = dns_zone_getfile(zone);
2949 	if (file != NULL) {
2950 		isc_file_remove(file);
2951 		file = dns_zone_getjournal(zone);
2952 		if (file != NULL) {
2953 			isc_file_remove(file);
2954 		}
2955 	}
2956 
2957 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2958 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2959 		      "catz: catz_delzone_taskaction: "
2960 		      "zone '%s' deleted",
2961 		      cname);
2962 cleanup:
2963 	isc_task_endexclusive(task);
2964 	if (zone != NULL) {
2965 		dns_zone_detach(&zone);
2966 	}
2967 	dns_catz_entry_detach(ev->origin, &ev->entry);
2968 	dns_catz_detach_catz(&ev->origin);
2969 	dns_view_weakdetach(&ev->view);
2970 	isc_event_free(ISC_EVENT_PTR(&ev));
2971 }
2972 
2973 static isc_result_t
2974 catz_create_chg_task(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
2975 		     dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata,
2976 		     isc_eventtype_t type) {
2977 	catz_chgzone_event_t *event = NULL;
2978 	isc_task_t *task = NULL;
2979 	isc_result_t result;
2980 	isc_taskaction_t action = NULL;
2981 
2982 	result = isc_taskmgr_excltask(taskmgr, &task);
2983 	if (result != ISC_R_SUCCESS) {
2984 		return (result);
2985 	}
2986 
2987 	switch (type) {
2988 	case DNS_EVENT_CATZADDZONE:
2989 	case DNS_EVENT_CATZMODZONE:
2990 		action = catz_addmodzone_taskaction;
2991 		break;
2992 	case DNS_EVENT_CATZDELZONE:
2993 		action = catz_delzone_taskaction;
2994 		break;
2995 	default:
2996 		REQUIRE(0);
2997 		UNREACHABLE();
2998 	}
2999 
3000 	event = (catz_chgzone_event_t *)isc_event_allocate(
3001 		view->mctx, origin, type, action, NULL, sizeof(*event));
3002 
3003 	event->cbd = (catz_cb_data_t *)udata;
3004 	event->entry = NULL;
3005 	event->origin = NULL;
3006 	event->view = NULL;
3007 	event->mod = (type == DNS_EVENT_CATZMODZONE);
3008 
3009 	dns_catz_entry_attach(entry, &event->entry);
3010 	dns_catz_attach_catz(origin, &event->origin);
3011 	dns_view_weakattach(view, &event->view);
3012 
3013 	isc_task_send(task, ISC_EVENT_PTR(&event));
3014 	isc_task_detach(&task);
3015 
3016 	return (ISC_R_SUCCESS);
3017 }
3018 
3019 static isc_result_t
3020 catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3021 	     isc_taskmgr_t *taskmgr, void *udata) {
3022 	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3023 				     DNS_EVENT_CATZADDZONE));
3024 }
3025 
3026 static isc_result_t
3027 catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3028 	     isc_taskmgr_t *taskmgr, void *udata) {
3029 	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3030 				     DNS_EVENT_CATZDELZONE));
3031 }
3032 
3033 static isc_result_t
3034 catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3035 	     isc_taskmgr_t *taskmgr, void *udata) {
3036 	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3037 				     DNS_EVENT_CATZMODZONE));
3038 }
3039 
3040 static void
3041 catz_reconfigure(dns_catz_entry_t *entry, dns_view_t *view,
3042 		 catz_reconfig_data_t *data) {
3043 	isc_buffer_t namebuf;
3044 	isc_buffer_t *confbuf = NULL;
3045 	const cfg_obj_t *zlist = NULL;
3046 	char nameb[DNS_NAME_FORMATSIZE];
3047 	cfg_obj_t *zoneconf = NULL;
3048 	cfg_obj_t *zoneobj = NULL;
3049 	ns_cfgctx_t *cfg = NULL;
3050 	dns_zone_t *zone = NULL;
3051 	isc_result_t result;
3052 
3053 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
3054 	dns_name_totext(dns_catz_entry_getname(entry), DNS_NAME_OMITFINALDOT,
3055 			&namebuf);
3056 	isc_buffer_putuint8(&namebuf, 0);
3057 
3058 	result = dns_view_findzone(view, dns_catz_entry_getname(entry), &zone);
3059 	if (result != ISC_R_SUCCESS) {
3060 		return;
3061 	}
3062 
3063 	/*
3064 	 * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
3065 	 * is true, so this is expected to be non-NULL.
3066 	 */
3067 	cfg = (ns_cfgctx_t *)view->new_zone_config;
3068 	if (cfg == NULL) {
3069 		CHECK(ISC_R_FAILURE);
3070 	}
3071 
3072 	result = dns_catz_generate_zonecfg(data->catz, entry, &confbuf);
3073 	if (result == ISC_R_SUCCESS) {
3074 		cfg_parser_reset(cfg->add_parser);
3075 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
3076 					  &cfg_type_addzoneconf, 0, &zoneconf);
3077 		isc_buffer_free(&confbuf);
3078 	}
3079 	/*
3080 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer()
3081 	 * failed.
3082 	 */
3083 	if (result != ISC_R_SUCCESS) {
3084 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3085 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3086 			      "catz_reconfigure: error \"%s\" while trying to "
3087 			      "generate config for member zone '%s'",
3088 			      isc_result_totext(result), nameb);
3089 		goto cleanup;
3090 	}
3091 
3092 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
3093 	if (!cfg_obj_islist(zlist)) {
3094 		CHECK(ISC_R_FAILURE);
3095 	}
3096 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
3097 
3098 	result = configure_zone(data->config, zoneobj, cfg->vconfig,
3099 				data->cbd->server->mctx, view,
3100 				&data->cbd->server->viewlist,
3101 				&data->cbd->server->kasplist, cfg->actx, true,
3102 				false, true, true);
3103 	if (result != ISC_R_SUCCESS) {
3104 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3105 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3106 			      "catz_reconfigure : error \"%s\" while trying to "
3107 			      "reconfigure member zone '%s'",
3108 			      isc_result_totext(result), nameb);
3109 		goto cleanup;
3110 	}
3111 
3112 cleanup:
3113 	if (zoneconf != NULL) {
3114 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
3115 	}
3116 
3117 	dns_zone_detach(&zone);
3118 }
3119 
3120 static isc_result_t
3121 configure_catz_zone(dns_view_t *view, dns_view_t *pview,
3122 		    const cfg_obj_t *config, const cfg_listelt_t *element) {
3123 	const cfg_obj_t *catz_obj, *obj;
3124 	dns_catz_zone_t *zone = NULL;
3125 	const char *str;
3126 	isc_result_t result;
3127 	dns_name_t origin;
3128 	dns_catz_options_t *opts;
3129 
3130 	dns_name_init(&origin, NULL);
3131 	catz_obj = cfg_listelt_value(element);
3132 
3133 	str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
3134 
3135 	result = dns_name_fromstring(&origin, str, DNS_NAME_DOWNCASE,
3136 				     view->mctx);
3137 	if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname)) {
3138 		result = DNS_R_EMPTYLABEL;
3139 	}
3140 
3141 	if (result != ISC_R_SUCCESS) {
3142 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3143 			    "catz: invalid zone name '%s'", str);
3144 		goto cleanup;
3145 	}
3146 
3147 	result = dns_catz_add_zone(view->catzs, &origin, &zone);
3148 	if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
3149 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3150 			    "catz: unable to create catalog zone '%s', "
3151 			    "error %s",
3152 			    str, isc_result_totext(result));
3153 		goto cleanup;
3154 	}
3155 
3156 	if (result == ISC_R_EXISTS) {
3157 		isc_ht_iter_t *it = NULL;
3158 		catz_reconfig_data_t data = {
3159 			.catz = zone,
3160 			.config = config,
3161 			.cbd = (catz_cb_data_t *)dns_catz_zones_get_udata(
3162 				view->catzs),
3163 		};
3164 
3165 		RUNTIME_CHECK(pview != NULL);
3166 
3167 		/*
3168 		 * We have to walk through all the member zones, attach
3169 		 * them to the current view and reconfigure
3170 		 */
3171 		dns_catz_get_iterator(zone, &it);
3172 
3173 		for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
3174 		     result = isc_ht_iter_next(it))
3175 		{
3176 			dns_name_t *name = NULL;
3177 			dns_zone_t *dnszone = NULL;
3178 			dns_catz_entry_t *entry = NULL;
3179 			isc_result_t tresult;
3180 
3181 			isc_ht_iter_current(it, (void **)&entry);
3182 			name = dns_catz_entry_getname(entry);
3183 
3184 			tresult = dns_view_findzone(pview, name, &dnszone);
3185 			if (tresult != ISC_R_SUCCESS) {
3186 				continue;
3187 			}
3188 
3189 			dns_zone_setview(dnszone, view);
3190 			dns_view_addzone(view, dnszone);
3191 
3192 			catz_reconfigure(entry, view, &data);
3193 
3194 			/*
3195 			 * The dns_view_findzone() call above increments the
3196 			 * zone's reference count, which we need to decrement
3197 			 * back.  However, as dns_zone_detach() sets the
3198 			 * supplied pointer to NULL, calling it is deferred
3199 			 * until the dnszone variable is no longer used.
3200 			 */
3201 			dns_zone_detach(&dnszone);
3202 		}
3203 
3204 		isc_ht_iter_destroy(&it);
3205 
3206 		result = ISC_R_SUCCESS;
3207 	}
3208 
3209 	dns_catz_zone_resetdefoptions(zone);
3210 	opts = dns_catz_zone_getdefoptions(zone);
3211 
3212 	obj = cfg_tuple_get(catz_obj, "default-masters");
3213 	if (obj == NULL || !cfg_obj_istuple(obj)) {
3214 		obj = cfg_tuple_get(catz_obj, "default-primaries");
3215 	}
3216 	if (obj != NULL && cfg_obj_istuple(obj)) {
3217 		result = named_config_getipandkeylist(
3218 			config, "primaries", obj, view->mctx, &opts->masters);
3219 	}
3220 
3221 	obj = cfg_tuple_get(catz_obj, "in-memory");
3222 	if (obj != NULL && cfg_obj_isboolean(obj)) {
3223 		opts->in_memory = cfg_obj_asboolean(obj);
3224 	}
3225 
3226 	obj = cfg_tuple_get(catz_obj, "zone-directory");
3227 	if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) {
3228 		opts->zonedir = isc_mem_strdup(view->mctx,
3229 					       cfg_obj_asstring(obj));
3230 		if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) {
3231 			cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3232 				    "catz: zone-directory '%s' "
3233 				    "not found; zone files will not be "
3234 				    "saved",
3235 				    opts->zonedir);
3236 			opts->in_memory = true;
3237 		}
3238 	}
3239 
3240 	obj = cfg_tuple_get(catz_obj, "min-update-interval");
3241 	if (obj != NULL && cfg_obj_isduration(obj)) {
3242 		opts->min_update_interval = cfg_obj_asduration(obj);
3243 	}
3244 
3245 cleanup:
3246 	dns_name_free(&origin, view->mctx);
3247 
3248 	return (result);
3249 }
3250 
3251 static catz_cb_data_t ns_catz_cbdata;
3252 static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
3253 	catz_addzone, catz_modzone, catz_delzone, &ns_catz_cbdata
3254 };
3255 
3256 static isc_result_t
3257 configure_catz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t *config,
3258 	       const cfg_obj_t *catz_obj) {
3259 	const cfg_listelt_t *zone_element = NULL;
3260 	const dns_catz_zones_t *old = NULL;
3261 	bool pview_must_detach = false;
3262 	isc_result_t result;
3263 
3264 	/* xxxwpk TODO do it cleaner, once, somewhere */
3265 	ns_catz_cbdata.server = named_g_server;
3266 
3267 	zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
3268 	if (zone_element == NULL) {
3269 		return (ISC_R_SUCCESS);
3270 	}
3271 
3272 	CHECK(dns_catz_new_zones(view->mctx, named_g_taskmgr, named_g_timermgr,
3273 				 &view->catzs, &ns_catz_zonemodmethods));
3274 
3275 	if (pview != NULL) {
3276 		old = pview->catzs;
3277 	} else {
3278 		result = dns_viewlist_find(&named_g_server->viewlist,
3279 					   view->name, view->rdclass, &pview);
3280 		if (result == ISC_R_SUCCESS) {
3281 			pview_must_detach = true;
3282 			old = pview->catzs;
3283 		}
3284 	}
3285 
3286 	if (old != NULL) {
3287 		dns_catz_shutdown_catzs(view->catzs);
3288 		dns_catz_detach_catzs(&view->catzs);
3289 		dns_catz_attach_catzs(pview->catzs, &view->catzs);
3290 		dns_catz_detach_catzs(&pview->catzs);
3291 		dns_catz_prereconfig(view->catzs);
3292 	}
3293 
3294 	while (zone_element != NULL) {
3295 		CHECK(configure_catz_zone(view, pview, config, zone_element));
3296 		zone_element = cfg_list_next(zone_element);
3297 	}
3298 
3299 	if (old != NULL) {
3300 		dns_catz_postreconfig(view->catzs);
3301 	}
3302 
3303 	result = ISC_R_SUCCESS;
3304 
3305 cleanup:
3306 	if (pview_must_detach) {
3307 		dns_view_detach(&pview);
3308 	}
3309 
3310 	return (result);
3311 }
3312 
3313 #define CHECK_RRL(cond, pat, val1, val2)                                   \
3314 	do {                                                               \
3315 		if (!(cond)) {                                             \
3316 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, pat, \
3317 				    val1, val2);                           \
3318 			result = ISC_R_RANGE;                              \
3319 			goto cleanup;                                      \
3320 		}                                                          \
3321 	} while (0)
3322 
3323 #define CHECK_RRL_RATE(rate, def, max_rate, name)                           \
3324 	do {                                                                \
3325 		obj = NULL;                                                 \
3326 		rrl->rate.str = name;                                       \
3327 		result = cfg_map_get(map, name, &obj);                      \
3328 		if (result == ISC_R_SUCCESS) {                              \
3329 			rrl->rate.r = cfg_obj_asuint32(obj);                \
3330 			CHECK_RRL(rrl->rate.r <= max_rate, name " %d > %d", \
3331 				  rrl->rate.r, max_rate);                   \
3332 		} else {                                                    \
3333 			rrl->rate.r = def;                                  \
3334 		}                                                           \
3335 		rrl->rate.scaled = rrl->rate.r;                             \
3336 	} while (0)
3337 
3338 static isc_result_t
3339 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
3340 	const cfg_obj_t *obj;
3341 	dns_rrl_t *rrl;
3342 	isc_result_t result;
3343 	int min_entries, i, j;
3344 
3345 	/*
3346 	 * Most DNS servers have few clients, but intentinally open
3347 	 * recursive and authoritative servers often have many.
3348 	 * So start with a small number of entries unless told otherwise
3349 	 * to reduce cold-start costs.
3350 	 */
3351 	min_entries = 500;
3352 	obj = NULL;
3353 	result = cfg_map_get(map, "min-table-size", &obj);
3354 	if (result == ISC_R_SUCCESS) {
3355 		min_entries = cfg_obj_asuint32(obj);
3356 		if (min_entries < 1) {
3357 			min_entries = 1;
3358 		}
3359 	}
3360 	result = dns_rrl_init(&rrl, view, min_entries);
3361 	if (result != ISC_R_SUCCESS) {
3362 		return (result);
3363 	}
3364 
3365 	i = ISC_MAX(20000, min_entries);
3366 	obj = NULL;
3367 	result = cfg_map_get(map, "max-table-size", &obj);
3368 	if (result == ISC_R_SUCCESS) {
3369 		i = cfg_obj_asuint32(obj);
3370 		CHECK_RRL(i >= min_entries,
3371 			  "max-table-size %d < min-table-size %d", i,
3372 			  min_entries);
3373 	}
3374 	rrl->max_entries = i;
3375 
3376 	CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
3377 		       "responses-per-second");
3378 	CHECK_RRL_RATE(referrals_per_second, rrl->responses_per_second.r,
3379 		       DNS_RRL_MAX_RATE, "referrals-per-second");
3380 	CHECK_RRL_RATE(nodata_per_second, rrl->responses_per_second.r,
3381 		       DNS_RRL_MAX_RATE, "nodata-per-second");
3382 	CHECK_RRL_RATE(nxdomains_per_second, rrl->responses_per_second.r,
3383 		       DNS_RRL_MAX_RATE, "nxdomains-per-second");
3384 	CHECK_RRL_RATE(errors_per_second, rrl->responses_per_second.r,
3385 		       DNS_RRL_MAX_RATE, "errors-per-second");
3386 
3387 	CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
3388 
3389 	CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
3390 
3391 	i = 15;
3392 	obj = NULL;
3393 	result = cfg_map_get(map, "window", &obj);
3394 	if (result == ISC_R_SUCCESS) {
3395 		i = cfg_obj_asuint32(obj);
3396 		CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
3397 			  "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
3398 	}
3399 	rrl->window = i;
3400 
3401 	i = 0;
3402 	obj = NULL;
3403 	result = cfg_map_get(map, "qps-scale", &obj);
3404 	if (result == ISC_R_SUCCESS) {
3405 		i = cfg_obj_asuint32(obj);
3406 		CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
3407 	}
3408 	rrl->qps_scale = i;
3409 	rrl->qps = 1.0;
3410 
3411 	i = 24;
3412 	obj = NULL;
3413 	result = cfg_map_get(map, "ipv4-prefix-length", &obj);
3414 	if (result == ISC_R_SUCCESS) {
3415 		i = cfg_obj_asuint32(obj);
3416 		CHECK_RRL(i >= 8 && i <= 32,
3417 			  "invalid 'ipv4-prefix-length %d'%s", i, "");
3418 	}
3419 	rrl->ipv4_prefixlen = i;
3420 	if (i == 32) {
3421 		rrl->ipv4_mask = 0xffffffff;
3422 	} else {
3423 		rrl->ipv4_mask = htonl(0xffffffff << (32 - i));
3424 	}
3425 
3426 	i = 56;
3427 	obj = NULL;
3428 	result = cfg_map_get(map, "ipv6-prefix-length", &obj);
3429 	if (result == ISC_R_SUCCESS) {
3430 		i = cfg_obj_asuint32(obj);
3431 		CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
3432 			  "ipv6-prefix-length %d < 16 or > %d", i,
3433 			  DNS_RRL_MAX_PREFIX);
3434 	}
3435 	rrl->ipv6_prefixlen = i;
3436 	for (j = 0; j < 4; ++j) {
3437 		if (i <= 0) {
3438 			rrl->ipv6_mask[j] = 0;
3439 		} else if (i < 32) {
3440 			rrl->ipv6_mask[j] = htonl(0xffffffff << (32 - i));
3441 		} else {
3442 			rrl->ipv6_mask[j] = 0xffffffff;
3443 		}
3444 		i -= 32;
3445 	}
3446 
3447 	obj = NULL;
3448 	result = cfg_map_get(map, "exempt-clients", &obj);
3449 	if (result == ISC_R_SUCCESS) {
3450 		result = cfg_acl_fromconfig(obj, config, named_g_lctx,
3451 					    named_g_aclconfctx, named_g_mctx, 0,
3452 					    &rrl->exempt);
3453 		CHECK_RRL(result == ISC_R_SUCCESS, "invalid %s%s",
3454 			  "address match list", "");
3455 	}
3456 
3457 	obj = NULL;
3458 	result = cfg_map_get(map, "log-only", &obj);
3459 	if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) {
3460 		rrl->log_only = true;
3461 	} else {
3462 		rrl->log_only = false;
3463 	}
3464 
3465 	return (ISC_R_SUCCESS);
3466 
3467 cleanup:
3468 	dns_rrl_view_destroy(view);
3469 	return (result);
3470 }
3471 
3472 static isc_result_t
3473 add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3474 	const dns_name_t *origin, const dns_name_t *contact) {
3475 	dns_dbnode_t *node = NULL;
3476 	dns_rdata_t rdata = DNS_RDATA_INIT;
3477 	dns_rdatalist_t rdatalist;
3478 	dns_rdataset_t rdataset;
3479 	isc_result_t result;
3480 	unsigned char buf[DNS_SOA_BUFFERSIZE];
3481 
3482 	CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 0, 28800,
3483 				 7200, 604800, 86400, buf, &rdata));
3484 
3485 	dns_rdatalist_init(&rdatalist);
3486 	rdatalist.type = rdata.type;
3487 	rdatalist.rdclass = rdata.rdclass;
3488 	rdatalist.ttl = 86400;
3489 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3490 
3491 	dns_rdataset_init(&rdataset);
3492 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3493 	CHECK(dns_db_findnode(db, name, true, &node));
3494 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3495 
3496 cleanup:
3497 	if (node != NULL) {
3498 		dns_db_detachnode(db, &node);
3499 	}
3500 	return (result);
3501 }
3502 
3503 static isc_result_t
3504 add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3505        const dns_name_t *nsname) {
3506 	dns_dbnode_t *node = NULL;
3507 	dns_rdata_ns_t ns;
3508 	dns_rdata_t rdata = DNS_RDATA_INIT;
3509 	dns_rdatalist_t rdatalist;
3510 	dns_rdataset_t rdataset;
3511 	isc_result_t result;
3512 	isc_buffer_t b;
3513 	unsigned char buf[DNS_NAME_MAXWIRE];
3514 
3515 	isc_buffer_init(&b, buf, sizeof(buf));
3516 
3517 	ns.common.rdtype = dns_rdatatype_ns;
3518 	ns.common.rdclass = dns_db_class(db);
3519 	ns.mctx = NULL;
3520 	dns_name_init(&ns.name, NULL);
3521 	dns_name_clone(nsname, &ns.name);
3522 	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
3523 				   &ns, &b));
3524 
3525 	dns_rdatalist_init(&rdatalist);
3526 	rdatalist.type = rdata.type;
3527 	rdatalist.rdclass = rdata.rdclass;
3528 	rdatalist.ttl = 86400;
3529 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3530 
3531 	dns_rdataset_init(&rdataset);
3532 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3533 	CHECK(dns_db_findnode(db, name, true, &node));
3534 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3535 
3536 cleanup:
3537 	if (node != NULL) {
3538 		dns_db_detachnode(db, &node);
3539 	}
3540 	return (result);
3541 }
3542 
3543 static isc_result_t
3544 create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
3545 		  const cfg_obj_t *zonelist, const char **empty_dbtype,
3546 		  int empty_dbtypec, dns_zonestat_level_t statlevel) {
3547 	char namebuf[DNS_NAME_FORMATSIZE];
3548 	const cfg_listelt_t *element;
3549 	const cfg_obj_t *obj;
3550 	const cfg_obj_t *zconfig;
3551 	const cfg_obj_t *zoptions;
3552 	const char *rbt_dbtype[4] = { "rbt" };
3553 	const char *sep = ": view ";
3554 	const char *str;
3555 	const char *viewname = view->name;
3556 	dns_db_t *db = NULL;
3557 	dns_dbversion_t *version = NULL;
3558 	dns_fixedname_t cfixed;
3559 	dns_fixedname_t fixed;
3560 	dns_fixedname_t nsfixed;
3561 	dns_name_t *contact;
3562 	dns_name_t *ns;
3563 	dns_name_t *zname;
3564 	dns_zone_t *zone = NULL;
3565 	int rbt_dbtypec = 1;
3566 	isc_result_t result;
3567 	dns_namereln_t namereln;
3568 	int order;
3569 	unsigned int nlabels;
3570 
3571 	zname = dns_fixedname_initname(&fixed);
3572 	ns = dns_fixedname_initname(&nsfixed);
3573 	contact = dns_fixedname_initname(&cfixed);
3574 
3575 	/*
3576 	 * Look for forward "zones" beneath this empty zone and if so
3577 	 * create a custom db for the empty zone.
3578 	 */
3579 	for (element = cfg_list_first(zonelist); element != NULL;
3580 	     element = cfg_list_next(element))
3581 	{
3582 		zconfig = cfg_listelt_value(element);
3583 		str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3584 		CHECK(dns_name_fromstring(zname, str, 0, NULL));
3585 		namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
3586 		if (namereln != dns_namereln_subdomain) {
3587 			continue;
3588 		}
3589 
3590 		zoptions = cfg_tuple_get(zconfig, "options");
3591 
3592 		obj = NULL;
3593 		(void)cfg_map_get(zoptions, "type", &obj);
3594 		if (obj != NULL &&
3595 		    strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
3596 		{
3597 			obj = NULL;
3598 			(void)cfg_map_get(zoptions, "forward", &obj);
3599 			if (obj == NULL) {
3600 				continue;
3601 			}
3602 			if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) {
3603 				continue;
3604 			}
3605 		}
3606 		if (db == NULL) {
3607 			CHECK(dns_db_create(view->mctx, "rbt", name,
3608 					    dns_dbtype_zone, view->rdclass, 0,
3609 					    NULL, &db));
3610 			CHECK(dns_db_newversion(db, &version));
3611 			if (strcmp(empty_dbtype[2], "@") == 0) {
3612 				dns_name_clone(name, ns);
3613 			} else {
3614 				CHECK(dns_name_fromstring(ns, empty_dbtype[2],
3615 							  0, NULL));
3616 			}
3617 			CHECK(dns_name_fromstring(contact, empty_dbtype[3], 0,
3618 						  NULL));
3619 			CHECK(add_soa(db, version, name, ns, contact));
3620 			CHECK(add_ns(db, version, name, ns));
3621 		}
3622 		CHECK(add_ns(db, version, zname, dns_rootname));
3623 	}
3624 
3625 	/*
3626 	 * Is the existing zone the ok to use?
3627 	 */
3628 	if (pzone != NULL) {
3629 		unsigned int typec;
3630 		const char **dbargv;
3631 
3632 		if (db != NULL) {
3633 			typec = rbt_dbtypec;
3634 			dbargv = rbt_dbtype;
3635 		} else {
3636 			typec = empty_dbtypec;
3637 			dbargv = empty_dbtype;
3638 		}
3639 
3640 		result = check_dbtype(pzone, typec, dbargv, view->mctx);
3641 		if (result != ISC_R_SUCCESS) {
3642 			pzone = NULL;
3643 		}
3644 
3645 		if (pzone != NULL &&
3646 		    dns_zone_gettype(pzone) != dns_zone_primary)
3647 		{
3648 			pzone = NULL;
3649 		}
3650 		if (pzone != NULL && dns_zone_getfile(pzone) != NULL) {
3651 			pzone = NULL;
3652 		}
3653 		if (pzone != NULL) {
3654 			dns_zone_getraw(pzone, &zone);
3655 			if (zone != NULL) {
3656 				dns_zone_detach(&zone);
3657 				pzone = NULL;
3658 			}
3659 		}
3660 	}
3661 
3662 	if (pzone == NULL) {
3663 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
3664 		CHECK(dns_zone_setorigin(zone, name));
3665 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3666 		if (db == NULL) {
3667 			dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype);
3668 		}
3669 		dns_zone_setclass(zone, view->rdclass);
3670 		dns_zone_settype(zone, dns_zone_primary);
3671 		dns_zone_setstats(zone, named_g_server->zonestats);
3672 	} else {
3673 		dns_zone_attach(pzone, &zone);
3674 	}
3675 
3676 	dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
3677 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3678 	dns_zone_setnotifytype(zone, dns_notifytype_no);
3679 	dns_zone_setdialup(zone, dns_dialuptype_no);
3680 	dns_zone_setautomatic(zone, true);
3681 	if (view->queryacl != NULL) {
3682 		dns_zone_setqueryacl(zone, view->queryacl);
3683 	} else {
3684 		dns_zone_clearqueryacl(zone);
3685 	}
3686 	if (view->queryonacl != NULL) {
3687 		dns_zone_setqueryonacl(zone, view->queryonacl);
3688 	} else {
3689 		dns_zone_clearqueryonacl(zone);
3690 	}
3691 	dns_zone_clearupdateacl(zone);
3692 	if (view->transferacl != NULL) {
3693 		dns_zone_setxfracl(zone, view->transferacl);
3694 	} else {
3695 		dns_zone_clearxfracl(zone);
3696 	}
3697 
3698 	CHECK(setquerystats(zone, view->mctx, statlevel));
3699 	if (db != NULL) {
3700 		dns_db_closeversion(db, &version, true);
3701 		CHECK(dns_zone_replacedb(zone, db, false));
3702 	}
3703 	dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true);
3704 	dns_zone_setview(zone, view);
3705 	CHECK(dns_view_addzone(view, zone));
3706 
3707 	if (!strcmp(viewname, "_default")) {
3708 		sep = "";
3709 		viewname = "";
3710 	}
3711 	dns_name_format(name, namebuf, sizeof(namebuf));
3712 	isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD,
3713 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3714 		      "automatic empty zone%s%s: %s", sep, viewname, namebuf);
3715 
3716 cleanup:
3717 	if (zone != NULL) {
3718 		dns_zone_detach(&zone);
3719 	}
3720 	if (version != NULL) {
3721 		dns_db_closeversion(db, &version, false);
3722 	}
3723 	if (db != NULL) {
3724 		dns_db_detach(&db);
3725 	}
3726 
3727 	INSIST(version == NULL);
3728 
3729 	return (result);
3730 }
3731 
3732 static isc_result_t
3733 create_ipv4only_zone(dns_zone_t *pzone, dns_view_t *view,
3734 		     const dns_name_t *name, const char *type, isc_mem_t *mctx,
3735 		     const char *server, const char *contact) {
3736 	char namebuf[DNS_NAME_FORMATSIZE];
3737 	const char *dbtype[4] = { "_builtin", NULL, "@", "." };
3738 	const char *sep = ": view ";
3739 	const char *viewname = view->name;
3740 	dns_zone_t *zone = NULL;
3741 	int dbtypec = 4;
3742 	isc_result_t result;
3743 
3744 	REQUIRE(type != NULL);
3745 
3746 	if (!strcmp(viewname, "_default")) {
3747 		sep = "";
3748 		viewname = "";
3749 	}
3750 
3751 	dbtype[1] = type;
3752 	if (server != NULL) {
3753 		dbtype[2] = server;
3754 	}
3755 	if (contact != NULL) {
3756 		dbtype[3] = contact;
3757 	}
3758 
3759 	if (pzone != NULL) {
3760 		result = check_dbtype(pzone, dbtypec, dbtype, view->mctx);
3761 		if (result != ISC_R_SUCCESS) {
3762 			pzone = NULL;
3763 		}
3764 	}
3765 
3766 	if (pzone == NULL) {
3767 		/*
3768 		 * Create the actual zone.
3769 		 */
3770 		CHECK(dns_zone_create(&zone, mctx));
3771 		CHECK(dns_zone_setorigin(zone, name));
3772 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3773 		dns_zone_setclass(zone, view->rdclass);
3774 		dns_zone_settype(zone, dns_zone_primary);
3775 		dns_zone_setstats(zone, named_g_server->zonestats);
3776 		dns_zone_setdbtype(zone, dbtypec, dbtype);
3777 		dns_zone_setdialup(zone, dns_dialuptype_no);
3778 		dns_zone_setnotifytype(zone, dns_notifytype_no);
3779 		dns_zone_setautomatic(zone, true);
3780 		dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3781 	} else {
3782 		dns_zone_attach(pzone, &zone);
3783 	}
3784 	if (view->queryacl != NULL) {
3785 		dns_zone_setqueryacl(zone, view->queryacl);
3786 	} else {
3787 		dns_zone_clearqueryacl(zone);
3788 	}
3789 	if (view->queryonacl != NULL) {
3790 		dns_zone_setqueryonacl(zone, view->queryonacl);
3791 	} else {
3792 		dns_zone_clearqueryonacl(zone);
3793 	}
3794 	dns_zone_setview(zone, view);
3795 	CHECK(dns_view_addzone(view, zone));
3796 
3797 	dns_name_format(name, namebuf, sizeof(namebuf));
3798 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3799 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3800 		      "automatic ipv4only zone%s%s: %s", sep, viewname,
3801 		      namebuf);
3802 
3803 cleanup:
3804 	if (zone != NULL) {
3805 		dns_zone_detach(&zone);
3806 	}
3807 	return (result);
3808 }
3809 
3810 #ifdef HAVE_DNSTAP
3811 static isc_result_t
3812 configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
3813 	isc_result_t result;
3814 	const cfg_obj_t *obj, *obj2;
3815 	const cfg_listelt_t *element;
3816 	const char *dpath;
3817 	const cfg_obj_t *dlist = NULL;
3818 	dns_dtmsgtype_t dttypes = 0;
3819 	unsigned int i;
3820 	struct fstrm_iothr_options *fopt = NULL;
3821 
3822 	result = named_config_get(maps, "dnstap", &dlist);
3823 	if (result != ISC_R_SUCCESS) {
3824 		return (ISC_R_SUCCESS);
3825 	}
3826 
3827 	for (element = cfg_list_first(dlist); element != NULL;
3828 	     element = cfg_list_next(element))
3829 	{
3830 		const char *str;
3831 		dns_dtmsgtype_t dt = 0;
3832 
3833 		obj = cfg_listelt_value(element);
3834 		obj2 = cfg_tuple_get(obj, "type");
3835 		str = cfg_obj_asstring(obj2);
3836 		if (strcasecmp(str, "client") == 0) {
3837 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR;
3838 		} else if (strcasecmp(str, "auth") == 0) {
3839 			dt |= DNS_DTTYPE_AQ | DNS_DTTYPE_AR;
3840 		} else if (strcasecmp(str, "resolver") == 0) {
3841 			dt |= DNS_DTTYPE_RQ | DNS_DTTYPE_RR;
3842 		} else if (strcasecmp(str, "forwarder") == 0) {
3843 			dt |= DNS_DTTYPE_FQ | DNS_DTTYPE_FR;
3844 		} else if (strcasecmp(str, "update") == 0) {
3845 			dt |= DNS_DTTYPE_UQ | DNS_DTTYPE_UR;
3846 		} else if (strcasecmp(str, "all") == 0) {
3847 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR | DNS_DTTYPE_AQ |
3848 			      DNS_DTTYPE_AR | DNS_DTTYPE_RQ | DNS_DTTYPE_RR |
3849 			      DNS_DTTYPE_FQ | DNS_DTTYPE_FR | DNS_DTTYPE_UQ |
3850 			      DNS_DTTYPE_UR;
3851 		}
3852 
3853 		obj2 = cfg_tuple_get(obj, "mode");
3854 		if (obj2 == NULL || cfg_obj_isvoid(obj2)) {
3855 			dttypes |= dt;
3856 			continue;
3857 		}
3858 
3859 		str = cfg_obj_asstring(obj2);
3860 		if (strcasecmp(str, "query") == 0) {
3861 			dt &= ~DNS_DTTYPE_RESPONSE;
3862 		} else if (strcasecmp(str, "response") == 0) {
3863 			dt &= ~DNS_DTTYPE_QUERY;
3864 		}
3865 
3866 		dttypes |= dt;
3867 	}
3868 
3869 	if (named_g_server->dtenv == NULL && dttypes != 0) {
3870 		dns_dtmode_t dmode;
3871 		uint64_t max_size = 0;
3872 		uint32_t rolls = 0;
3873 		isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment;
3874 
3875 		obj = NULL;
3876 		CHECKM(named_config_get(maps, "dnstap-output", &obj),
3877 		       "'dnstap-output' must be set if 'dnstap' is set");
3878 
3879 		obj2 = cfg_tuple_get(obj, "mode");
3880 		if (obj2 == NULL) {
3881 			CHECKM(ISC_R_FAILURE, "dnstap-output mode not found");
3882 		}
3883 		if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) {
3884 			dmode = dns_dtmode_file;
3885 		} else {
3886 			dmode = dns_dtmode_unix;
3887 		}
3888 
3889 		obj2 = cfg_tuple_get(obj, "path");
3890 		if (obj2 == NULL) {
3891 			CHECKM(ISC_R_FAILURE, "dnstap-output path not found");
3892 		}
3893 
3894 		dpath = cfg_obj_asstring(obj2);
3895 
3896 		obj2 = cfg_tuple_get(obj, "size");
3897 		if (obj2 != NULL && cfg_obj_isuint64(obj2)) {
3898 			max_size = cfg_obj_asuint64(obj2);
3899 			if (max_size > SIZE_MAX) {
3900 				cfg_obj_log(obj2, named_g_lctx, ISC_LOG_WARNING,
3901 					    "'dnstap-output size "
3902 					    "%" PRIu64 "' "
3903 					    "is too large for this "
3904 					    "system; reducing to %lu",
3905 					    max_size, (unsigned long)SIZE_MAX);
3906 				max_size = SIZE_MAX;
3907 			}
3908 		}
3909 
3910 		obj2 = cfg_tuple_get(obj, "versions");
3911 		if (obj2 != NULL && cfg_obj_isuint32(obj2)) {
3912 			rolls = cfg_obj_asuint32(obj2);
3913 		} else {
3914 			rolls = ISC_LOG_ROLLINFINITE;
3915 		}
3916 
3917 		obj2 = cfg_tuple_get(obj, "suffix");
3918 		if (obj2 != NULL && cfg_obj_isstring(obj2) &&
3919 		    strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0)
3920 		{
3921 			suffix = isc_log_rollsuffix_timestamp;
3922 		}
3923 
3924 		fopt = fstrm_iothr_options_init();
3925 		/*
3926 		 * Both network threads and worker threads may log dnstap data.
3927 		 */
3928 		fstrm_iothr_options_set_num_input_queues(fopt,
3929 							 2 * named_g_cpus);
3930 		fstrm_iothr_options_set_queue_model(
3931 			fopt, FSTRM_IOTHR_QUEUE_MODEL_MPSC);
3932 
3933 		obj = NULL;
3934 		result = named_config_get(maps, "fstrm-set-buffer-hint", &obj);
3935 		if (result == ISC_R_SUCCESS) {
3936 			i = cfg_obj_asuint32(obj);
3937 			fstrm_iothr_options_set_buffer_hint(fopt, i);
3938 		}
3939 
3940 		obj = NULL;
3941 		result = named_config_get(maps, "fstrm-set-flush-timeout",
3942 					  &obj);
3943 		if (result == ISC_R_SUCCESS) {
3944 			i = cfg_obj_asuint32(obj);
3945 			fstrm_iothr_options_set_flush_timeout(fopt, i);
3946 		}
3947 
3948 		obj = NULL;
3949 		result = named_config_get(maps, "fstrm-set-input-queue-size",
3950 					  &obj);
3951 		if (result == ISC_R_SUCCESS) {
3952 			i = cfg_obj_asuint32(obj);
3953 			fstrm_iothr_options_set_input_queue_size(fopt, i);
3954 		}
3955 
3956 		obj = NULL;
3957 		result = named_config_get(
3958 			maps, "fstrm-set-output-notify-threshold", &obj);
3959 		if (result == ISC_R_SUCCESS) {
3960 			i = cfg_obj_asuint32(obj);
3961 			fstrm_iothr_options_set_queue_notify_threshold(fopt, i);
3962 		}
3963 
3964 		obj = NULL;
3965 		result = named_config_get(maps, "fstrm-set-output-queue-model",
3966 					  &obj);
3967 		if (result == ISC_R_SUCCESS) {
3968 			if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0) {
3969 				i = FSTRM_IOTHR_QUEUE_MODEL_SPSC;
3970 			} else {
3971 				i = FSTRM_IOTHR_QUEUE_MODEL_MPSC;
3972 			}
3973 			fstrm_iothr_options_set_queue_model(fopt, i);
3974 		}
3975 
3976 		obj = NULL;
3977 		result = named_config_get(maps, "fstrm-set-output-queue-size",
3978 					  &obj);
3979 		if (result == ISC_R_SUCCESS) {
3980 			i = cfg_obj_asuint32(obj);
3981 			fstrm_iothr_options_set_output_queue_size(fopt, i);
3982 		}
3983 
3984 		obj = NULL;
3985 		result = named_config_get(maps, "fstrm-set-reopen-interval",
3986 					  &obj);
3987 		if (result == ISC_R_SUCCESS) {
3988 			i = cfg_obj_asduration(obj);
3989 			fstrm_iothr_options_set_reopen_interval(fopt, i);
3990 		}
3991 
3992 		CHECKM(dns_dt_create(named_g_mctx, dmode, dpath, &fopt,
3993 				     named_g_server->task,
3994 				     &named_g_server->dtenv),
3995 		       "unable to create dnstap environment");
3996 
3997 		CHECKM(dns_dt_setupfile(named_g_server->dtenv, max_size, rolls,
3998 					suffix),
3999 		       "unable to set up dnstap logfile");
4000 	}
4001 
4002 	if (named_g_server->dtenv == NULL) {
4003 		return (ISC_R_SUCCESS);
4004 	}
4005 
4006 	obj = NULL;
4007 	result = named_config_get(maps, "dnstap-version", &obj);
4008 	if (result != ISC_R_SUCCESS) {
4009 		/* not specified; use the product and version */
4010 		dns_dt_setversion(named_g_server->dtenv, PACKAGE_STRING);
4011 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
4012 		/* Quoted string */
4013 		dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj));
4014 	}
4015 
4016 	obj = NULL;
4017 	result = named_config_get(maps, "dnstap-identity", &obj);
4018 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
4019 		/* "hostname" is interpreted as boolean true */
4020 		char buf[256];
4021 		if (gethostname(buf, sizeof(buf)) == 0) {
4022 			dns_dt_setidentity(named_g_server->dtenv, buf);
4023 		}
4024 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
4025 		/* Quoted string */
4026 		dns_dt_setidentity(named_g_server->dtenv,
4027 				   cfg_obj_asstring(obj));
4028 	}
4029 
4030 	dns_dt_attach(named_g_server->dtenv, &view->dtenv);
4031 	view->dttypes = dttypes;
4032 
4033 	result = ISC_R_SUCCESS;
4034 
4035 cleanup:
4036 	if (fopt != NULL) {
4037 		fstrm_iothr_options_destroy(&fopt);
4038 	}
4039 
4040 	return (result);
4041 }
4042 #endif /* HAVE_DNSTAP */
4043 
4044 static isc_result_t
4045 create_mapped_acl(void) {
4046 	isc_result_t result;
4047 	dns_acl_t *acl = NULL;
4048 	struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT;
4049 	isc_netaddr_t addr;
4050 
4051 	isc_netaddr_fromin6(&addr, &in6);
4052 
4053 	result = dns_acl_create(named_g_mctx, 1, &acl);
4054 	if (result != ISC_R_SUCCESS) {
4055 		return (result);
4056 	}
4057 
4058 	result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
4059 	if (result == ISC_R_SUCCESS) {
4060 		dns_acl_attach(acl, &named_g_mapped);
4061 	}
4062 	dns_acl_detach(&acl);
4063 	return (result);
4064 }
4065 
4066 /*%
4067  * A callback for the cfg_pluginlist_foreach() call in configure_view() below.
4068  * If registering any plugin fails, registering subsequent ones is not
4069  * attempted.
4070  */
4071 static isc_result_t
4072 register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
4073 		    const char *plugin_path, const char *parameters,
4074 		    void *callback_data) {
4075 	dns_view_t *view = callback_data;
4076 	char full_path[PATH_MAX];
4077 	isc_result_t result;
4078 
4079 	result = ns_plugin_expandpath(plugin_path, full_path,
4080 				      sizeof(full_path));
4081 	if (result != ISC_R_SUCCESS) {
4082 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4083 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4084 			      "%s: plugin configuration failed: "
4085 			      "unable to get full plugin path: %s",
4086 			      plugin_path, isc_result_totext(result));
4087 		return (result);
4088 	}
4089 
4090 	result = ns_plugin_register(full_path, parameters, config,
4091 				    cfg_obj_file(obj), cfg_obj_line(obj),
4092 				    named_g_mctx, named_g_lctx,
4093 				    named_g_aclconfctx, view);
4094 	if (result != ISC_R_SUCCESS) {
4095 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4096 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4097 			      "%s: plugin configuration failed: %s", full_path,
4098 			      isc_result_totext(result));
4099 	}
4100 
4101 	return (result);
4102 }
4103 
4104 /*
4105  * Determine if a minimal-sized cache can be used for a given view, according
4106  * to 'maps' (implicit defaults, global options, view options) and 'optionmaps'
4107  * (global options, view options).  This is only allowed for views which have
4108  * recursion disabled and do not have "max-cache-size" set explicitly.  Using
4109  * minimal-sized caches prevents a situation in which all explicitly configured
4110  * and built-in views inherit the default "max-cache-size 90%;" setting, which
4111  * could lead to memory exhaustion with multiple views configured.
4112  */
4113 static bool
4114 minimal_cache_allowed(const cfg_obj_t *maps[4],
4115 		      const cfg_obj_t *optionmaps[3]) {
4116 	const cfg_obj_t *obj;
4117 
4118 	/*
4119 	 * Do not use a minimal-sized cache for a view with recursion enabled.
4120 	 */
4121 	obj = NULL;
4122 	(void)named_config_get(maps, "recursion", &obj);
4123 	INSIST(obj != NULL);
4124 	if (cfg_obj_asboolean(obj)) {
4125 		return (false);
4126 	}
4127 
4128 	/*
4129 	 * Do not use a minimal-sized cache if a specific size was requested.
4130 	 */
4131 	obj = NULL;
4132 	(void)named_config_get(optionmaps, "max-cache-size", &obj);
4133 	if (obj != NULL) {
4134 		return (false);
4135 	}
4136 
4137 	return (true);
4138 }
4139 
4140 static const char *const response_synonyms[] = { "response", NULL };
4141 
4142 static const dns_name_t *
4143 algorithm_name(unsigned int alg) {
4144 	switch (alg) {
4145 	case DST_ALG_HMACMD5:
4146 		return (dns_tsig_hmacmd5_name);
4147 	case DST_ALG_HMACSHA1:
4148 		return (dns_tsig_hmacsha1_name);
4149 	case DST_ALG_HMACSHA224:
4150 		return (dns_tsig_hmacsha224_name);
4151 	case DST_ALG_HMACSHA256:
4152 		return (dns_tsig_hmacsha256_name);
4153 	case DST_ALG_HMACSHA384:
4154 		return (dns_tsig_hmacsha384_name);
4155 	case DST_ALG_HMACSHA512:
4156 		return (dns_tsig_hmacsha512_name);
4157 	case DST_ALG_GSSAPI:
4158 		return (dns_tsig_gssapi_name);
4159 	default:
4160 		UNREACHABLE();
4161 	}
4162 }
4163 
4164 /*
4165  * Configure 'view' according to 'vconfig', taking defaults from
4166  * 'config' where values are missing in 'vconfig'.
4167  *
4168  * When configuring the default view, 'vconfig' will be NULL and the
4169  * global defaults in 'config' used exclusively.
4170  */
4171 static isc_result_t
4172 configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
4173 	       cfg_obj_t *vconfig, named_cachelist_t *cachelist,
4174 	       dns_kasplist_t *kasplist, const cfg_obj_t *bindkeys,
4175 	       isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints) {
4176 	const cfg_obj_t *maps[4];
4177 	const cfg_obj_t *cfgmaps[3];
4178 	const cfg_obj_t *optionmaps[3];
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_tsig_keyring_t *ring = NULL;
4206 	dns_transport_list_t *transports = NULL;
4207 	dns_view_t *pview = NULL; /* Production view */
4208 	isc_mem_t *cmctx = NULL, *hmctx = NULL;
4209 	dns_dispatch_t *dispatch4 = NULL;
4210 	dns_dispatch_t *dispatch6 = NULL;
4211 	bool rpz_configured = false;
4212 	bool catz_configured = false;
4213 	bool shared_cache = false;
4214 	int i = 0, j = 0, k = 0;
4215 	const char *str;
4216 	const char *cachename = NULL;
4217 	dns_order_t *order = NULL;
4218 	uint32_t udpsize;
4219 	uint32_t maxbits;
4220 	unsigned int resopts = 0;
4221 	dns_zone_t *zone = NULL;
4222 	uint32_t max_clients_per_query;
4223 	bool empty_zones_enable;
4224 	const cfg_obj_t *disablelist = NULL;
4225 	isc_stats_t *resstats = NULL;
4226 	dns_stats_t *resquerystats = NULL;
4227 	bool auto_root = false;
4228 	named_cache_t *nsc;
4229 	bool zero_no_soattl;
4230 	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
4231 	unsigned int query_timeout, ndisp;
4232 	bool old_rpz_ok = false;
4233 	dns_dyndbctx_t *dctx = NULL;
4234 	unsigned int resolver_param;
4235 	dns_ntatable_t *ntatable = NULL;
4236 	const char *qminmode = NULL;
4237 
4238 	REQUIRE(DNS_VIEW_VALID(view));
4239 
4240 	if (config != NULL) {
4241 		(void)cfg_map_get(config, "options", &options);
4242 	}
4243 
4244 	/*
4245 	 * maps: view options, options, defaults
4246 	 * cfgmaps: view options, config
4247 	 * optionmaps: view options, options
4248 	 */
4249 	if (vconfig != NULL) {
4250 		voptions = cfg_tuple_get(vconfig, "options");
4251 		maps[i++] = voptions;
4252 		optionmaps[j++] = voptions;
4253 		cfgmaps[k++] = voptions;
4254 	}
4255 	if (options != NULL) {
4256 		maps[i++] = options;
4257 		optionmaps[j++] = options;
4258 	}
4259 
4260 	maps[i++] = named_g_defaults;
4261 	maps[i] = NULL;
4262 	optionmaps[j] = NULL;
4263 	if (config != NULL) {
4264 		cfgmaps[k++] = config;
4265 	}
4266 	cfgmaps[k] = NULL;
4267 
4268 	/*
4269 	 * Set the view's port number for outgoing queries.
4270 	 */
4271 	CHECKM(named_config_getport(config, "port", &port), "port");
4272 	dns_view_setdstport(view, port);
4273 
4274 	/*
4275 	 * Make the list of response policy zone names for a view that
4276 	 * is used for real lookups and so cares about hints.
4277 	 */
4278 	obj = NULL;
4279 	if (view->rdclass == dns_rdataclass_in && need_hints &&
4280 	    named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS)
4281 	{
4282 		CHECK(configure_rpz(view, NULL, maps, obj, &old_rpz_ok));
4283 		rpz_configured = true;
4284 	}
4285 
4286 	obj = NULL;
4287 	if (view->rdclass != dns_rdataclass_in && need_hints &&
4288 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
4289 	{
4290 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4291 			    "'catalog-zones' option is only supported "
4292 			    "for views with class IN");
4293 	}
4294 
4295 	obj = NULL;
4296 	if (view->rdclass == dns_rdataclass_in && need_hints &&
4297 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
4298 	{
4299 		CHECK(configure_catz(view, NULL, config, obj));
4300 		catz_configured = true;
4301 	}
4302 
4303 	/*
4304 	 * Configure the zones.
4305 	 */
4306 	zonelist = NULL;
4307 	if (voptions != NULL) {
4308 		(void)cfg_map_get(voptions, "zone", &zonelist);
4309 	} else {
4310 		(void)cfg_map_get(config, "zone", &zonelist);
4311 	}
4312 
4313 	/*
4314 	 * Load zone configuration
4315 	 */
4316 	for (element = cfg_list_first(zonelist); element != NULL;
4317 	     element = cfg_list_next(element))
4318 	{
4319 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
4320 		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
4321 				     viewlist, kasplist, actx, false,
4322 				     old_rpz_ok, false, false));
4323 		zone_element_latest = element;
4324 	}
4325 
4326 	/*
4327 	 * Check that a primary or secondary zone was found for each
4328 	 * zone named in the response policy statement, unless we are
4329 	 * using RPZ service interface.
4330 	 */
4331 	if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
4332 		dns_rpz_num_t n;
4333 
4334 		for (n = 0; n < view->rpzs->p.num_zones; ++n) {
4335 			if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
4336 				char namebuf[DNS_NAME_FORMATSIZE];
4337 
4338 				dns_name_format(&view->rpzs->zones[n]->origin,
4339 						namebuf, sizeof(namebuf));
4340 				isc_log_write(named_g_lctx,
4341 					      NAMED_LOGCATEGORY_GENERAL,
4342 					      NAMED_LOGMODULE_SERVER,
4343 					      DNS_RPZ_ERROR_LEVEL,
4344 					      "rpz '%s' is not a primary or a "
4345 					      "secondary zone",
4346 					      namebuf);
4347 				result = ISC_R_NOTFOUND;
4348 				goto cleanup;
4349 			}
4350 		}
4351 	}
4352 
4353 	/*
4354 	 * If we're allowing added zones, then load zone configuration
4355 	 * from the newzone file for zones that were added during previous
4356 	 * runs.
4357 	 */
4358 	CHECK(configure_newzones(view, config, vconfig, mctx, actx));
4359 
4360 	/*
4361 	 * Create Dynamically Loadable Zone driver.
4362 	 */
4363 	dlzlist = NULL;
4364 	if (voptions != NULL) {
4365 		(void)cfg_map_get(voptions, "dlz", &dlzlist);
4366 	} else {
4367 		(void)cfg_map_get(config, "dlz", &dlzlist);
4368 	}
4369 
4370 	for (element = cfg_list_first(dlzlist); element != NULL;
4371 	     element = cfg_list_next(element))
4372 	{
4373 		dlz = cfg_listelt_value(element);
4374 
4375 		obj = NULL;
4376 		(void)cfg_map_get(dlz, "database", &obj);
4377 		if (obj != NULL) {
4378 			dns_dlzdb_t *dlzdb = NULL;
4379 			const cfg_obj_t *name, *search = NULL;
4380 			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
4381 
4382 			if (s == NULL) {
4383 				result = ISC_R_NOMEMORY;
4384 				goto cleanup;
4385 			}
4386 
4387 			result = isc_commandline_strtoargv(mctx, s, &dlzargc,
4388 							   &dlzargv, 0);
4389 			if (result != ISC_R_SUCCESS) {
4390 				isc_mem_free(mctx, s);
4391 				goto cleanup;
4392 			}
4393 
4394 			name = cfg_map_getname(dlz);
4395 			result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
4396 					       dlzargv[0], dlzargc, dlzargv,
4397 					       &dlzdb);
4398 			isc_mem_free(mctx, s);
4399 			isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
4400 			if (result != ISC_R_SUCCESS) {
4401 				goto cleanup;
4402 			}
4403 
4404 			/*
4405 			 * If the DLZ backend supports configuration,
4406 			 * and is searchable, then call its configure
4407 			 * method now.  If not searchable, we'll take
4408 			 * care of it when we process the zone statement.
4409 			 */
4410 			(void)cfg_map_get(dlz, "search", &search);
4411 			if (search == NULL || cfg_obj_asboolean(search)) {
4412 				dlzdb->search = true;
4413 				result = dns_dlzconfigure(
4414 					view, dlzdb, dlzconfigure_callback);
4415 				if (result != ISC_R_SUCCESS) {
4416 					goto cleanup;
4417 				}
4418 				ISC_LIST_APPEND(view->dlz_searched, dlzdb,
4419 						link);
4420 			} else {
4421 				dlzdb->search = false;
4422 				ISC_LIST_APPEND(view->dlz_unsearched, dlzdb,
4423 						link);
4424 			}
4425 		}
4426 	}
4427 
4428 	/*
4429 	 * Obtain configuration parameters that affect the decision of whether
4430 	 * we can reuse/share an existing cache.
4431 	 */
4432 	obj = NULL;
4433 	result = named_config_get(maps, "max-cache-size", &obj);
4434 	INSIST(result == ISC_R_SUCCESS);
4435 	/*
4436 	 * If "-T maxcachesize=..." is in effect, it overrides any other
4437 	 * "max-cache-size" setting found in configuration, either implicit or
4438 	 * explicit.  For simplicity, the value passed to that command line
4439 	 * option is always treated as the number of bytes to set
4440 	 * "max-cache-size" to.
4441 	 */
4442 	if (named_g_maxcachesize != 0) {
4443 		max_cache_size = named_g_maxcachesize;
4444 	} else if (minimal_cache_allowed(maps, optionmaps)) {
4445 		/*
4446 		 * dns_cache_setcachesize() will adjust this to the smallest
4447 		 * allowed value.
4448 		 */
4449 		max_cache_size = 1;
4450 	} else if (cfg_obj_isstring(obj)) {
4451 		str = cfg_obj_asstring(obj);
4452 		INSIST(strcasecmp(str, "unlimited") == 0);
4453 		max_cache_size = 0;
4454 	} else if (cfg_obj_ispercentage(obj)) {
4455 		max_cache_size = SIZE_AS_PERCENT;
4456 		max_cache_size_percent = cfg_obj_aspercentage(obj);
4457 	} else {
4458 		isc_resourcevalue_t value;
4459 		value = cfg_obj_asuint64(obj);
4460 		if (value > SIZE_MAX) {
4461 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4462 				    "'max-cache-size "
4463 				    "%" PRIu64 "' "
4464 				    "is too large for this "
4465 				    "system; reducing to %lu",
4466 				    value, (unsigned long)SIZE_MAX);
4467 			value = SIZE_MAX;
4468 		}
4469 		max_cache_size = (size_t)value;
4470 	}
4471 
4472 	if (max_cache_size == SIZE_AS_PERCENT) {
4473 		uint64_t totalphys = isc_meminfo_totalphys();
4474 
4475 		max_cache_size =
4476 			(size_t)(totalphys * max_cache_size_percent / 100);
4477 		if (totalphys == 0) {
4478 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4479 				    "Unable to determine amount of physical "
4480 				    "memory, setting 'max-cache-size' to "
4481 				    "unlimited");
4482 		} else {
4483 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
4484 				    "'max-cache-size %d%%' "
4485 				    "- setting to %" PRIu64 "MB "
4486 				    "(out of %" PRIu64 "MB)",
4487 				    max_cache_size_percent,
4488 				    (uint64_t)(max_cache_size / (1024 * 1024)),
4489 				    totalphys / (1024 * 1024));
4490 		}
4491 	}
4492 
4493 	/* Check-names. */
4494 	obj = NULL;
4495 	result = named_checknames_get(maps, response_synonyms, &obj);
4496 	INSIST(result == ISC_R_SUCCESS);
4497 
4498 	str = cfg_obj_asstring(obj);
4499 	if (strcasecmp(str, "fail") == 0) {
4500 		resopts |= DNS_RESOLVER_CHECKNAMES |
4501 			   DNS_RESOLVER_CHECKNAMESFAIL;
4502 		view->checknames = true;
4503 	} else if (strcasecmp(str, "warn") == 0) {
4504 		resopts |= DNS_RESOLVER_CHECKNAMES;
4505 		view->checknames = false;
4506 	} else if (strcasecmp(str, "ignore") == 0) {
4507 		view->checknames = false;
4508 	} else {
4509 		UNREACHABLE();
4510 	}
4511 
4512 	obj = NULL;
4513 	result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj);
4514 	INSIST(result == ISC_R_SUCCESS);
4515 	zero_no_soattl = cfg_obj_asboolean(obj);
4516 
4517 	obj = NULL;
4518 	result = named_config_get(maps, "dns64", &obj);
4519 	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
4520 	    strcmp(view->name, "_meta"))
4521 	{
4522 		isc_netaddr_t na, suffix, *sp;
4523 		unsigned int prefixlen;
4524 		const char *server, *contact;
4525 		const cfg_obj_t *myobj;
4526 
4527 		myobj = NULL;
4528 		result = named_config_get(maps, "dns64-server", &myobj);
4529 		if (result == ISC_R_SUCCESS) {
4530 			server = cfg_obj_asstring(myobj);
4531 		} else {
4532 			server = NULL;
4533 		}
4534 
4535 		myobj = NULL;
4536 		result = named_config_get(maps, "dns64-contact", &myobj);
4537 		if (result == ISC_R_SUCCESS) {
4538 			contact = cfg_obj_asstring(myobj);
4539 		} else {
4540 			contact = NULL;
4541 		}
4542 
4543 		for (element = cfg_list_first(obj); element != NULL;
4544 		     element = cfg_list_next(element))
4545 		{
4546 			const cfg_obj_t *map = cfg_listelt_value(element);
4547 			dns_dns64_t *dns64 = NULL;
4548 			unsigned int dns64options = 0;
4549 
4550 			cfg_obj_asnetprefix(cfg_map_getname(map), &na,
4551 					    &prefixlen);
4552 
4553 			obj = NULL;
4554 			(void)cfg_map_get(map, "suffix", &obj);
4555 			if (obj != NULL) {
4556 				sp = &suffix;
4557 				isc_netaddr_fromsockaddr(
4558 					sp, cfg_obj_assockaddr(obj));
4559 			} else {
4560 				sp = NULL;
4561 			}
4562 
4563 			clients = mapped = excluded = NULL;
4564 			obj = NULL;
4565 			(void)cfg_map_get(map, "clients", &obj);
4566 			if (obj != NULL) {
4567 				result = cfg_acl_fromconfig(obj, config,
4568 							    named_g_lctx, actx,
4569 							    mctx, 0, &clients);
4570 				if (result != ISC_R_SUCCESS) {
4571 					goto cleanup;
4572 				}
4573 			}
4574 			obj = NULL;
4575 			(void)cfg_map_get(map, "mapped", &obj);
4576 			if (obj != NULL) {
4577 				result = cfg_acl_fromconfig(obj, config,
4578 							    named_g_lctx, actx,
4579 							    mctx, 0, &mapped);
4580 				if (result != ISC_R_SUCCESS) {
4581 					goto cleanup;
4582 				}
4583 			}
4584 			obj = NULL;
4585 			(void)cfg_map_get(map, "exclude", &obj);
4586 			if (obj != NULL) {
4587 				result = cfg_acl_fromconfig(obj, config,
4588 							    named_g_lctx, actx,
4589 							    mctx, 0, &excluded);
4590 				if (result != ISC_R_SUCCESS) {
4591 					goto cleanup;
4592 				}
4593 			} else {
4594 				if (named_g_mapped == NULL) {
4595 					result = create_mapped_acl();
4596 					if (result != ISC_R_SUCCESS) {
4597 						goto cleanup;
4598 					}
4599 				}
4600 				dns_acl_attach(named_g_mapped, &excluded);
4601 			}
4602 
4603 			obj = NULL;
4604 			(void)cfg_map_get(map, "recursive-only", &obj);
4605 			if (obj != NULL && cfg_obj_asboolean(obj)) {
4606 				dns64options |= DNS_DNS64_RECURSIVE_ONLY;
4607 			}
4608 
4609 			obj = NULL;
4610 			(void)cfg_map_get(map, "break-dnssec", &obj);
4611 			if (obj != NULL && cfg_obj_asboolean(obj)) {
4612 				dns64options |= DNS_DNS64_BREAK_DNSSEC;
4613 			}
4614 
4615 			result = dns_dns64_create(mctx, &na, prefixlen, sp,
4616 						  clients, mapped, excluded,
4617 						  dns64options, &dns64);
4618 			if (result != ISC_R_SUCCESS) {
4619 				goto cleanup;
4620 			}
4621 			dns_dns64_append(&view->dns64, dns64);
4622 			view->dns64cnt++;
4623 			result = dns64_reverse(view, mctx, &na, prefixlen,
4624 					       server, contact);
4625 			if (result != ISC_R_SUCCESS) {
4626 				goto cleanup;
4627 			}
4628 			if (clients != NULL) {
4629 				dns_acl_detach(&clients);
4630 			}
4631 			if (mapped != NULL) {
4632 				dns_acl_detach(&mapped);
4633 			}
4634 			if (excluded != NULL) {
4635 				dns_acl_detach(&excluded);
4636 			}
4637 		}
4638 	}
4639 
4640 	obj = NULL;
4641 	result = named_config_get(maps, "dnssec-accept-expired", &obj);
4642 	INSIST(result == ISC_R_SUCCESS);
4643 	view->acceptexpired = cfg_obj_asboolean(obj);
4644 
4645 	obj = NULL;
4646 	/* 'optionmaps', not 'maps': don't check named_g_defaults yet */
4647 	(void)named_config_get(optionmaps, "dnssec-validation", &obj);
4648 	if (obj == NULL) {
4649 		/*
4650 		 * Default to VALIDATION_DEFAULT as set in config.c.
4651 		 */
4652 		(void)cfg_map_get(named_g_defaults, "dnssec-validation", &obj);
4653 		INSIST(obj != NULL);
4654 	}
4655 	if (obj != NULL) {
4656 		if (cfg_obj_isboolean(obj)) {
4657 			view->enablevalidation = cfg_obj_asboolean(obj);
4658 		} else {
4659 			/*
4660 			 * If dnssec-validation is set but not boolean,
4661 			 * then it must be "auto"
4662 			 */
4663 			view->enablevalidation = true;
4664 			auto_root = true;
4665 		}
4666 	}
4667 
4668 	obj = NULL;
4669 	result = named_config_get(maps, "max-cache-ttl", &obj);
4670 	INSIST(result == ISC_R_SUCCESS);
4671 	view->maxcachettl = cfg_obj_asduration(obj);
4672 
4673 	obj = NULL;
4674 	result = named_config_get(maps, "max-ncache-ttl", &obj);
4675 	INSIST(result == ISC_R_SUCCESS);
4676 	view->maxncachettl = cfg_obj_asduration(obj);
4677 
4678 	obj = NULL;
4679 	result = named_config_get(maps, "min-cache-ttl", &obj);
4680 	INSIST(result == ISC_R_SUCCESS);
4681 	view->mincachettl = cfg_obj_asduration(obj);
4682 
4683 	obj = NULL;
4684 	result = named_config_get(maps, "min-ncache-ttl", &obj);
4685 	INSIST(result == ISC_R_SUCCESS);
4686 	view->minncachettl = cfg_obj_asduration(obj);
4687 
4688 	obj = NULL;
4689 	result = named_config_get(maps, "synth-from-dnssec", &obj);
4690 	INSIST(result == ISC_R_SUCCESS);
4691 	view->synthfromdnssec = cfg_obj_asboolean(obj);
4692 
4693 	obj = NULL;
4694 	result = named_config_get(maps, "stale-cache-enable", &obj);
4695 	INSIST(result == ISC_R_SUCCESS);
4696 	if (cfg_obj_asboolean(obj)) {
4697 		obj = NULL;
4698 		result = named_config_get(maps, "max-stale-ttl", &obj);
4699 		INSIST(result == ISC_R_SUCCESS);
4700 		max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4701 	}
4702 	/*
4703 	 * If 'stale-cache-enable' is false, max_stale_ttl is set to 0,
4704 	 * meaning keeping stale RRsets in cache is disabled.
4705 	 */
4706 
4707 	obj = NULL;
4708 	result = named_config_get(maps, "stale-answer-enable", &obj);
4709 	INSIST(result == ISC_R_SUCCESS);
4710 	view->staleanswersenable = cfg_obj_asboolean(obj);
4711 
4712 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
4713 				   view->rdclass, &pview);
4714 	if (result == ISC_R_SUCCESS) {
4715 		view->staleanswersok = pview->staleanswersok;
4716 		dns_view_detach(&pview);
4717 	} else {
4718 		view->staleanswersok = dns_stale_answer_conf;
4719 	}
4720 
4721 	obj = NULL;
4722 	result = named_config_get(maps, "stale-answer-client-timeout", &obj);
4723 	INSIST(result == ISC_R_SUCCESS);
4724 	if (cfg_obj_isstring(obj)) {
4725 		/*
4726 		 * The only string values available for this option
4727 		 * are "disabled" and "off".
4728 		 * We use (uint32_t) -1 to represent disabled since
4729 		 * a value of zero means that stale data can be used
4730 		 * to promptly answer the query, while an attempt to
4731 		 * refresh the RRset will still be made in background.
4732 		 */
4733 		view->staleanswerclienttimeout = (uint32_t)-1;
4734 	} else {
4735 		view->staleanswerclienttimeout = cfg_obj_asuint32(obj);
4736 	}
4737 
4738 	obj = NULL;
4739 	result = named_config_get(maps, "stale-refresh-time", &obj);
4740 	INSIST(result == ISC_R_SUCCESS);
4741 	stale_refresh_time = cfg_obj_asduration(obj);
4742 
4743 	/*
4744 	 * Configure the view's cache.
4745 	 *
4746 	 * First, check to see if there are any attach-cache options.  If yes,
4747 	 * attempt to lookup an existing cache at attach it to the view.  If
4748 	 * there is not one, then try to reuse an existing cache if possible;
4749 	 * otherwise create a new cache.
4750 	 *
4751 	 * Note that the ADB is not preserved or shared in either case.
4752 	 *
4753 	 * When a matching view is found, the associated statistics are also
4754 	 * retrieved and reused.
4755 	 *
4756 	 * XXX Determining when it is safe to reuse or share a cache is tricky.
4757 	 * When the view's configuration changes, the cached data may become
4758 	 * invalid because it reflects our old view of the world.  We check
4759 	 * some of the configuration parameters that could invalidate the cache
4760 	 * or otherwise make it unshareable, but there are other configuration
4761 	 * options that should be checked.  For example, if a view uses a
4762 	 * forwarder, changes in the forwarder configuration may invalidate
4763 	 * the cache.  At the moment, it's the administrator's responsibility to
4764 	 * ensure these configuration options don't invalidate reusing/sharing.
4765 	 */
4766 	obj = NULL;
4767 	result = named_config_get(maps, "attach-cache", &obj);
4768 	if (result == ISC_R_SUCCESS) {
4769 		cachename = cfg_obj_asstring(obj);
4770 	} else {
4771 		cachename = view->name;
4772 	}
4773 	cache = NULL;
4774 	nsc = cachelist_find(cachelist, cachename, view->rdclass);
4775 	if (nsc != NULL) {
4776 		if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
4777 				    max_cache_size, max_stale_ttl,
4778 				    stale_refresh_time))
4779 		{
4780 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4781 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4782 				      "views %s and %s can't share the cache "
4783 				      "due to configuration parameter mismatch",
4784 				      nsc->primaryview->name, view->name);
4785 			result = ISC_R_FAILURE;
4786 			goto cleanup;
4787 		}
4788 		dns_cache_attach(nsc->cache, &cache);
4789 		shared_cache = true;
4790 	} else {
4791 		if (strcmp(cachename, view->name) == 0) {
4792 			result = dns_viewlist_find(&named_g_server->viewlist,
4793 						   cachename, view->rdclass,
4794 						   &pview);
4795 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4796 			{
4797 				goto cleanup;
4798 			}
4799 			if (pview != NULL) {
4800 				if (!cache_reusable(pview, view,
4801 						    zero_no_soattl))
4802 				{
4803 					isc_log_write(named_g_lctx,
4804 						      NAMED_LOGCATEGORY_GENERAL,
4805 						      NAMED_LOGMODULE_SERVER,
4806 						      ISC_LOG_DEBUG(1),
4807 						      "cache cannot be reused "
4808 						      "for view %s due to "
4809 						      "configuration parameter "
4810 						      "mismatch",
4811 						      view->name);
4812 				} else {
4813 					INSIST(pview->cache != NULL);
4814 					isc_log_write(named_g_lctx,
4815 						      NAMED_LOGCATEGORY_GENERAL,
4816 						      NAMED_LOGMODULE_SERVER,
4817 						      ISC_LOG_DEBUG(3),
4818 						      "reusing existing cache");
4819 					dns_cache_attach(pview->cache, &cache);
4820 				}
4821 				dns_view_getresstats(pview, &resstats);
4822 				dns_view_getresquerystats(pview,
4823 							  &resquerystats);
4824 				dns_view_detach(&pview);
4825 			}
4826 		}
4827 		if (cache == NULL) {
4828 			/*
4829 			 * Create a cache with the desired name.  This normally
4830 			 * equals the view name, but may also be a forward
4831 			 * reference to a view that share the cache with this
4832 			 * view but is not yet configured.  If it is not the
4833 			 * view name but not a forward reference either, then it
4834 			 * is simply a named cache that is not shared.
4835 			 */
4836 			CHECK(dns_cache_create(mctx, named_g_taskmgr,
4837 					       named_g_timermgr, view->rdclass,
4838 					       cachename, "rbt", 0, NULL,
4839 					       &cache));
4840 		}
4841 		nsc = isc_mem_get(mctx, sizeof(*nsc));
4842 		nsc->cache = NULL;
4843 		dns_cache_attach(cache, &nsc->cache);
4844 		nsc->primaryview = view;
4845 		nsc->needflush = false;
4846 		nsc->adbsizeadjusted = false;
4847 		nsc->rdclass = view->rdclass;
4848 		ISC_LINK_INIT(nsc, link);
4849 		ISC_LIST_APPEND(*cachelist, nsc, link);
4850 	}
4851 	dns_view_setcache(view, cache, shared_cache);
4852 
4853 	dns_cache_setcachesize(cache, max_cache_size);
4854 	dns_cache_setservestalettl(cache, max_stale_ttl);
4855 	dns_cache_setservestalerefresh(cache, stale_refresh_time);
4856 
4857 	dns_cache_detach(&cache);
4858 
4859 	obj = NULL;
4860 	result = named_config_get(maps, "stale-answer-ttl", &obj);
4861 	INSIST(result == ISC_R_SUCCESS);
4862 	view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4863 
4864 	/*
4865 	 * Resolver.
4866 	 */
4867 	CHECK(get_view_querysource_dispatch(
4868 		maps, AF_INET, &dispatch4,
4869 		(ISC_LIST_PREV(view, link) == NULL)));
4870 	CHECK(get_view_querysource_dispatch(
4871 		maps, AF_INET6, &dispatch6,
4872 		(ISC_LIST_PREV(view, link) == NULL)));
4873 	if (dispatch4 == NULL && dispatch6 == NULL) {
4874 		UNEXPECTED_ERROR("unable to obtain either an IPv4 or"
4875 				 " an IPv6 dispatch");
4876 		result = ISC_R_UNEXPECTED;
4877 		goto cleanup;
4878 	}
4879 
4880 	if (resstats == NULL) {
4881 		CHECK(isc_stats_create(mctx, &resstats,
4882 				       dns_resstatscounter_max));
4883 	}
4884 	dns_view_setresstats(view, resstats);
4885 	if (resquerystats == NULL) {
4886 		CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
4887 	}
4888 	dns_view_setresquerystats(view, resquerystats);
4889 
4890 	ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH);
4891 	CHECK(dns_view_createresolver(
4892 		view, named_g_taskmgr, RESOLVER_NTASKS_PERCPU * named_g_cpus,
4893 		ndisp, named_g_netmgr, named_g_timermgr, resopts,
4894 		named_g_dispatchmgr, dispatch4, dispatch6));
4895 
4896 	/*
4897 	 * Set the ADB cache size to 1/8th of the max-cache-size or
4898 	 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
4899 	 */
4900 	max_adb_size = 0;
4901 	if (max_cache_size != 0U) {
4902 		max_adb_size = max_cache_size / 8;
4903 		if (max_adb_size == 0U) {
4904 			max_adb_size = 1; /* Force minimum. */
4905 		}
4906 		if (view != nsc->primaryview &&
4907 		    max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE)
4908 		{
4909 			max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
4910 			if (!nsc->adbsizeadjusted) {
4911 				dns_adb_setadbsize(nsc->primaryview->adb,
4912 						   MAX_ADB_SIZE_FOR_CACHESHARE);
4913 				nsc->adbsizeadjusted = true;
4914 			}
4915 		}
4916 	}
4917 	dns_adb_setadbsize(view->adb, max_adb_size);
4918 
4919 	/*
4920 	 * Set up ADB quotas
4921 	 */
4922 	{
4923 		uint32_t fps, freq;
4924 		double low, high, discount;
4925 
4926 		obj = NULL;
4927 		result = named_config_get(maps, "fetches-per-server", &obj);
4928 		INSIST(result == ISC_R_SUCCESS);
4929 		obj2 = cfg_tuple_get(obj, "fetches");
4930 		fps = cfg_obj_asuint32(obj2);
4931 		obj2 = cfg_tuple_get(obj, "response");
4932 		if (!cfg_obj_isvoid(obj2)) {
4933 			const char *resp = cfg_obj_asstring(obj2);
4934 			isc_result_t r = DNS_R_SERVFAIL;
4935 
4936 			if (strcasecmp(resp, "drop") == 0) {
4937 				r = DNS_R_DROP;
4938 			} else if (strcasecmp(resp, "fail") == 0) {
4939 				r = DNS_R_SERVFAIL;
4940 			} else {
4941 				UNREACHABLE();
4942 			}
4943 
4944 			dns_resolver_setquotaresponse(view->resolver,
4945 						      dns_quotatype_server, r);
4946 		}
4947 
4948 		obj = NULL;
4949 		result = named_config_get(maps, "fetch-quota-params", &obj);
4950 		INSIST(result == ISC_R_SUCCESS);
4951 
4952 		obj2 = cfg_tuple_get(obj, "frequency");
4953 		freq = cfg_obj_asuint32(obj2);
4954 
4955 		obj2 = cfg_tuple_get(obj, "low");
4956 		low = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4957 
4958 		obj2 = cfg_tuple_get(obj, "high");
4959 		high = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4960 
4961 		obj2 = cfg_tuple_get(obj, "discount");
4962 		discount = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4963 
4964 		dns_adb_setquota(view->adb, fps, freq, low, high, discount);
4965 	}
4966 
4967 	/*
4968 	 * Set resolver's lame-ttl.
4969 	 */
4970 	obj = NULL;
4971 	result = named_config_get(maps, "lame-ttl", &obj);
4972 	INSIST(result == ISC_R_SUCCESS);
4973 	lame_ttl = cfg_obj_asduration(obj);
4974 	if (lame_ttl > 0) {
4975 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4976 			    "disabling lame cache despite lame-ttl > 0 as it "
4977 			    "may cause performance issues");
4978 		lame_ttl = 0;
4979 	}
4980 	dns_resolver_setlamettl(view->resolver, lame_ttl);
4981 
4982 	/*
4983 	 * Set the resolver's query timeout.
4984 	 */
4985 	obj = NULL;
4986 	result = named_config_get(maps, "resolver-query-timeout", &obj);
4987 	INSIST(result == ISC_R_SUCCESS);
4988 	query_timeout = cfg_obj_asuint32(obj);
4989 	dns_resolver_settimeout(view->resolver, query_timeout);
4990 
4991 	/*
4992 	 * Adjust stale-answer-client-timeout upper bound
4993 	 * to be resolver-query-timeout - 1s.
4994 	 * This assignment is safe as dns_resolver_settimeout()
4995 	 * ensures that resolver->querytimeout value will be in the
4996 	 * [MINIMUM_QUERY_TIMEOUT, MAXIMUM_QUERY_TIMEOUT] range and
4997 	 * MINIMUM_QUERY_TIMEOUT is > 1000 (in ms).
4998 	 */
4999 	if (view->staleanswerclienttimeout != (uint32_t)-1 &&
5000 	    view->staleanswerclienttimeout >
5001 		    (dns_resolver_gettimeout(view->resolver) - 1000))
5002 	{
5003 		view->staleanswerclienttimeout =
5004 			dns_resolver_gettimeout(view->resolver) - 1000;
5005 		isc_log_write(
5006 			named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
5007 			NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
5008 			"stale-answer-client-timeout adjusted to %" PRIu32,
5009 			view->staleanswerclienttimeout);
5010 	}
5011 
5012 	/* Specify whether to use 0-TTL for negative response for SOA query */
5013 	dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
5014 
5015 	/*
5016 	 * Set the resolver's EDNS UDP size.
5017 	 */
5018 	obj = NULL;
5019 	result = named_config_get(maps, "edns-udp-size", &obj);
5020 	INSIST(result == ISC_R_SUCCESS);
5021 	udpsize = cfg_obj_asuint32(obj);
5022 	if (udpsize < 512) {
5023 		udpsize = 512;
5024 	}
5025 	if (udpsize > 4096) {
5026 		udpsize = 4096;
5027 	}
5028 	dns_resolver_setudpsize(view->resolver, (uint16_t)udpsize);
5029 
5030 	/*
5031 	 * Set the maximum UDP response size.
5032 	 */
5033 	obj = NULL;
5034 	result = named_config_get(maps, "max-udp-size", &obj);
5035 	INSIST(result == ISC_R_SUCCESS);
5036 	udpsize = cfg_obj_asuint32(obj);
5037 	if (udpsize < 512) {
5038 		udpsize = 512;
5039 	}
5040 	if (udpsize > 4096) {
5041 		udpsize = 4096;
5042 	}
5043 	view->maxudp = udpsize;
5044 
5045 	/*
5046 	 * Set the maximum UDP when a COOKIE is not provided.
5047 	 */
5048 	obj = NULL;
5049 	result = named_config_get(maps, "nocookie-udp-size", &obj);
5050 	INSIST(result == ISC_R_SUCCESS);
5051 	udpsize = cfg_obj_asuint32(obj);
5052 	if (udpsize < 128) {
5053 		udpsize = 128;
5054 	}
5055 	if (udpsize > view->maxudp) {
5056 		udpsize = view->maxudp;
5057 	}
5058 	view->nocookieudp = udpsize;
5059 
5060 	/*
5061 	 * Set the maximum rsa exponent bits.
5062 	 */
5063 	obj = NULL;
5064 	result = named_config_get(maps, "max-rsa-exponent-size", &obj);
5065 	INSIST(result == ISC_R_SUCCESS);
5066 	maxbits = cfg_obj_asuint32(obj);
5067 	if (maxbits != 0 && maxbits < 35) {
5068 		maxbits = 35;
5069 	}
5070 	if (maxbits > 4096) {
5071 		maxbits = 4096;
5072 	}
5073 	view->maxbits = maxbits;
5074 
5075 	/*
5076 	 * Set resolver retry parameters.
5077 	 */
5078 	obj = NULL;
5079 	CHECK(named_config_get(maps, "resolver-retry-interval", &obj));
5080 	resolver_param = cfg_obj_asuint32(obj);
5081 	if (resolver_param > 0) {
5082 		dns_resolver_setretryinterval(view->resolver, resolver_param);
5083 	}
5084 
5085 	obj = NULL;
5086 	CHECK(named_config_get(maps, "resolver-nonbackoff-tries", &obj));
5087 	resolver_param = cfg_obj_asuint32(obj);
5088 	if (resolver_param > 0) {
5089 		dns_resolver_setnonbackofftries(view->resolver, resolver_param);
5090 	}
5091 
5092 	/*
5093 	 * Set supported DNSSEC algorithms.
5094 	 */
5095 	dns_resolver_reset_algorithms(view->resolver);
5096 	disabled = NULL;
5097 	(void)named_config_get(maps, "disable-algorithms", &disabled);
5098 	if (disabled != NULL) {
5099 		for (element = cfg_list_first(disabled); element != NULL;
5100 		     element = cfg_list_next(element))
5101 		{
5102 			CHECK(disable_algorithms(cfg_listelt_value(element),
5103 						 view->resolver));
5104 		}
5105 	}
5106 
5107 	/*
5108 	 * Set supported DS digest types.
5109 	 */
5110 	dns_resolver_reset_ds_digests(view->resolver);
5111 	disabled = NULL;
5112 	(void)named_config_get(maps, "disable-ds-digests", &disabled);
5113 	if (disabled != NULL) {
5114 		for (element = cfg_list_first(disabled); element != NULL;
5115 		     element = cfg_list_next(element))
5116 		{
5117 			CHECK(disable_ds_digests(cfg_listelt_value(element),
5118 						 view->resolver));
5119 		}
5120 	}
5121 
5122 	/*
5123 	 * A global or view "forwarders" option, if present,
5124 	 * creates an entry for "." in the forwarding table.
5125 	 */
5126 	forwardtype = NULL;
5127 	forwarders = NULL;
5128 	(void)named_config_get(maps, "forward", &forwardtype);
5129 	(void)named_config_get(maps, "forwarders", &forwarders);
5130 	if (forwarders != NULL) {
5131 		CHECK(configure_forward(config, view, dns_rootname, forwarders,
5132 					forwardtype));
5133 	}
5134 
5135 	/*
5136 	 * Dual Stack Servers.
5137 	 */
5138 	alternates = NULL;
5139 	(void)named_config_get(maps, "dual-stack-servers", &alternates);
5140 	if (alternates != NULL) {
5141 		CHECK(configure_alternates(config, view, alternates));
5142 	}
5143 
5144 	/*
5145 	 * We have default hints for class IN if we need them.
5146 	 */
5147 	if (view->rdclass == dns_rdataclass_in && view->hints == NULL) {
5148 		dns_view_sethints(view, named_g_server->in_roothints);
5149 	}
5150 
5151 	/*
5152 	 * If we still have no hints, this is a non-IN view with no
5153 	 * "hints zone" configured.  Issue a warning, except if this
5154 	 * is a root server.  Root servers never need to consult
5155 	 * their hints, so it's no point requiring users to configure
5156 	 * them.
5157 	 */
5158 	if (view->hints == NULL) {
5159 		dns_zone_t *rootzone = NULL;
5160 		(void)dns_view_findzone(view, dns_rootname, &rootzone);
5161 		if (rootzone != NULL) {
5162 			dns_zone_detach(&rootzone);
5163 			need_hints = false;
5164 		}
5165 		if (need_hints) {
5166 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
5167 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
5168 				      "no root hints for view '%s'",
5169 				      view->name);
5170 		}
5171 	}
5172 
5173 	/*
5174 	 * Configure the view's transports (DoT/DoH)
5175 	 */
5176 	CHECK(named_transports_fromconfig(config, vconfig, view->mctx,
5177 					  &transports));
5178 	dns_view_settransports(view, transports);
5179 	dns_transport_list_detach(&transports);
5180 
5181 	/*
5182 	 * Configure the view's TSIG keys.
5183 	 */
5184 	CHECK(named_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
5185 	if (named_g_server->sessionkey != NULL) {
5186 		dns_tsigkey_t *tsigkey = NULL;
5187 		result = dns_tsigkey_createfromkey(
5188 			named_g_server->session_keyname,
5189 			algorithm_name(named_g_server->session_keyalg),
5190 			named_g_server->sessionkey, false, NULL, 0, 0, mctx,
5191 			NULL, &tsigkey);
5192 		if (result == ISC_R_SUCCESS) {
5193 			result = dns_tsigkeyring_add(
5194 				ring, named_g_server->session_keyname, tsigkey);
5195 			dns_tsigkey_detach(&tsigkey);
5196 		}
5197 		CHECK(result);
5198 	}
5199 	dns_view_setkeyring(view, ring);
5200 	dns_tsigkeyring_detach(&ring);
5201 
5202 	/*
5203 	 * See if we can re-use a dynamic key ring.
5204 	 */
5205 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
5206 				   view->rdclass, &pview);
5207 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
5208 		goto cleanup;
5209 	}
5210 	if (pview != NULL) {
5211 		dns_view_getdynamickeyring(pview, &ring);
5212 		if (ring != NULL) {
5213 			dns_view_setdynamickeyring(view, ring);
5214 		}
5215 		dns_tsigkeyring_detach(&ring);
5216 		dns_view_detach(&pview);
5217 	} else {
5218 		dns_view_restorekeyring(view);
5219 	}
5220 
5221 	/*
5222 	 * Configure the view's peer list.
5223 	 */
5224 	{
5225 		const cfg_obj_t *peers = NULL;
5226 		dns_peerlist_t *newpeers = NULL;
5227 
5228 		(void)named_config_get(cfgmaps, "server", &peers);
5229 		CHECK(dns_peerlist_new(mctx, &newpeers));
5230 		for (element = cfg_list_first(peers); element != NULL;
5231 		     element = cfg_list_next(element))
5232 		{
5233 			const cfg_obj_t *cpeer = cfg_listelt_value(element);
5234 			dns_peer_t *peer;
5235 
5236 			CHECK(configure_peer(cpeer, mctx, &peer));
5237 			dns_peerlist_addpeer(newpeers, peer);
5238 			dns_peer_detach(&peer);
5239 		}
5240 		dns_peerlist_detach(&view->peers);
5241 		view->peers = newpeers; /* Transfer ownership. */
5242 	}
5243 
5244 	/*
5245 	 *	Configure the views rrset-order.
5246 	 */
5247 	{
5248 		const cfg_obj_t *rrsetorder = NULL;
5249 
5250 		(void)named_config_get(maps, "rrset-order", &rrsetorder);
5251 		CHECK(dns_order_create(mctx, &order));
5252 		for (element = cfg_list_first(rrsetorder); element != NULL;
5253 		     element = cfg_list_next(element))
5254 		{
5255 			const cfg_obj_t *ent = cfg_listelt_value(element);
5256 
5257 			CHECK(configure_order(order, ent));
5258 		}
5259 		if (view->order != NULL) {
5260 			dns_order_detach(&view->order);
5261 		}
5262 		dns_order_attach(order, &view->order);
5263 		dns_order_detach(&order);
5264 	}
5265 	/*
5266 	 * Copy the aclenv object.
5267 	 */
5268 	dns_aclenv_copy(view->aclenv, ns_interfacemgr_getaclenv(
5269 					      named_g_server->interfacemgr));
5270 
5271 	/*
5272 	 * Configure the "match-clients" and "match-destinations" ACL.
5273 	 * (These are only meaningful at the view level, but 'config'
5274 	 * must be passed so that named ACLs defined at the global level
5275 	 * can be retrieved.)
5276 	 */
5277 	CHECK(configure_view_acl(vconfig, config, NULL, "match-clients", NULL,
5278 				 actx, named_g_mctx, &view->matchclients));
5279 	CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations",
5280 				 NULL, actx, named_g_mctx,
5281 				 &view->matchdestinations));
5282 
5283 	/*
5284 	 * Configure the "match-recursive-only" option.
5285 	 */
5286 	obj = NULL;
5287 	(void)named_config_get(maps, "match-recursive-only", &obj);
5288 	if (obj != NULL && cfg_obj_asboolean(obj)) {
5289 		view->matchrecursiveonly = true;
5290 	} else {
5291 		view->matchrecursiveonly = false;
5292 	}
5293 
5294 	/*
5295 	 * Configure other configurable data.
5296 	 */
5297 	obj = NULL;
5298 	result = named_config_get(maps, "recursion", &obj);
5299 	INSIST(result == ISC_R_SUCCESS);
5300 	view->recursion = cfg_obj_asboolean(obj);
5301 
5302 	obj = NULL;
5303 	result = named_config_get(maps, "qname-minimization", &obj);
5304 	INSIST(result == ISC_R_SUCCESS);
5305 	qminmode = cfg_obj_asstring(obj);
5306 	INSIST(qminmode != NULL);
5307 	if (!strcmp(qminmode, "strict")) {
5308 		view->qminimization = true;
5309 		view->qmin_strict = true;
5310 	} else if (!strcmp(qminmode, "relaxed")) {
5311 		view->qminimization = true;
5312 		view->qmin_strict = false;
5313 	} else { /* "disabled" or "off" */
5314 		view->qminimization = false;
5315 		view->qmin_strict = false;
5316 	}
5317 
5318 	obj = NULL;
5319 	result = named_config_get(maps, "auth-nxdomain", &obj);
5320 	INSIST(result == ISC_R_SUCCESS);
5321 	view->auth_nxdomain = cfg_obj_asboolean(obj);
5322 
5323 	/* deprecated */
5324 	obj = NULL;
5325 	result = named_config_get(maps, "glue-cache", &obj);
5326 	INSIST(result == ISC_R_SUCCESS);
5327 	view->use_glue_cache = cfg_obj_asboolean(obj);
5328 
5329 	obj = NULL;
5330 	result = named_config_get(maps, "minimal-any", &obj);
5331 	INSIST(result == ISC_R_SUCCESS);
5332 	view->minimal_any = cfg_obj_asboolean(obj);
5333 
5334 	obj = NULL;
5335 	result = named_config_get(maps, "minimal-responses", &obj);
5336 	INSIST(result == ISC_R_SUCCESS);
5337 	if (cfg_obj_isboolean(obj)) {
5338 		if (cfg_obj_asboolean(obj)) {
5339 			view->minimalresponses = dns_minimal_yes;
5340 		} else {
5341 			view->minimalresponses = dns_minimal_no;
5342 		}
5343 	} else {
5344 		str = cfg_obj_asstring(obj);
5345 		if (strcasecmp(str, "no-auth") == 0) {
5346 			view->minimalresponses = dns_minimal_noauth;
5347 		} else if (strcasecmp(str, "no-auth-recursive") == 0) {
5348 			view->minimalresponses = dns_minimal_noauthrec;
5349 		} else {
5350 			UNREACHABLE();
5351 		}
5352 	}
5353 
5354 	obj = NULL;
5355 	result = named_config_get(maps, "transfer-format", &obj);
5356 	INSIST(result == ISC_R_SUCCESS);
5357 	str = cfg_obj_asstring(obj);
5358 	if (strcasecmp(str, "many-answers") == 0) {
5359 		view->transfer_format = dns_many_answers;
5360 	} else if (strcasecmp(str, "one-answer") == 0) {
5361 		view->transfer_format = dns_one_answer;
5362 	} else {
5363 		UNREACHABLE();
5364 	}
5365 
5366 	obj = NULL;
5367 	result = named_config_get(maps, "trust-anchor-telemetry", &obj);
5368 	INSIST(result == ISC_R_SUCCESS);
5369 	view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
5370 
5371 	obj = NULL;
5372 	result = named_config_get(maps, "root-key-sentinel", &obj);
5373 	INSIST(result == ISC_R_SUCCESS);
5374 	view->root_key_sentinel = cfg_obj_asboolean(obj);
5375 
5376 	/*
5377 	 * Set the "allow-query", "allow-query-cache", "allow-recursion",
5378 	 * "allow-recursion-on" and "allow-query-cache-on" ACLs if
5379 	 * configured in named.conf, but NOT from the global defaults.
5380 	 * This is done by leaving the third argument to configure_view_acl()
5381 	 * NULL.
5382 	 *
5383 	 * We ignore the global defaults here because these ACLs
5384 	 * can inherit from each other.  If any are still unset after
5385 	 * applying the inheritance rules, we'll look up the defaults at
5386 	 * that time.
5387 	 */
5388 
5389 	/* named.conf only */
5390 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query", NULL,
5391 				 actx, named_g_mctx, &view->queryacl));
5392 
5393 	/* named.conf only */
5394 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache",
5395 				 NULL, actx, named_g_mctx, &view->cacheacl));
5396 	/* named.conf only */
5397 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
5398 				 NULL, actx, named_g_mctx, &view->cacheonacl));
5399 
5400 	if (strcmp(view->name, "_bind") != 0 &&
5401 	    view->rdclass != dns_rdataclass_chaos)
5402 	{
5403 		/* named.conf only */
5404 		CHECK(configure_view_acl(vconfig, config, NULL,
5405 					 "allow-recursion", NULL, actx,
5406 					 named_g_mctx, &view->recursionacl));
5407 		/* named.conf only */
5408 		CHECK(configure_view_acl(vconfig, config, NULL,
5409 					 "allow-recursion-on", NULL, actx,
5410 					 named_g_mctx, &view->recursiononacl));
5411 	}
5412 
5413 	if (view->recursion) {
5414 		/*
5415 		 * "allow-query-cache" inherits from "allow-recursion" if set,
5416 		 * otherwise from "allow-query" if set.
5417 		 */
5418 		if (view->cacheacl == NULL) {
5419 			if (view->recursionacl != NULL) {
5420 				dns_acl_attach(view->recursionacl,
5421 					       &view->cacheacl);
5422 			} else if (view->queryacl != NULL) {
5423 				dns_acl_attach(view->queryacl, &view->cacheacl);
5424 			}
5425 		}
5426 
5427 		/*
5428 		 * "allow-recursion" inherits from "allow-query-cache" if set,
5429 		 * otherwise from "allow-query" if set.
5430 		 */
5431 		if (view->recursionacl == NULL) {
5432 			if (view->cacheacl != NULL) {
5433 				dns_acl_attach(view->cacheacl,
5434 					       &view->recursionacl);
5435 			} else if (view->queryacl != NULL) {
5436 				dns_acl_attach(view->queryacl,
5437 					       &view->recursionacl);
5438 			}
5439 		}
5440 
5441 		/*
5442 		 * "allow-query-cache-on" inherits from "allow-recursion-on"
5443 		 * if set.
5444 		 */
5445 		if (view->cacheonacl == NULL) {
5446 			if (view->recursiononacl != NULL) {
5447 				dns_acl_attach(view->recursiononacl,
5448 					       &view->cacheonacl);
5449 			}
5450 		}
5451 
5452 		/*
5453 		 * "allow-recursion-on" inherits from "allow-query-cache-on"
5454 		 * if set.
5455 		 */
5456 		if (view->recursiononacl == NULL) {
5457 			if (view->cacheonacl != NULL) {
5458 				dns_acl_attach(view->cacheonacl,
5459 					       &view->recursiononacl);
5460 			}
5461 		}
5462 
5463 		/*
5464 		 * If any are still unset at this point, we now get default
5465 		 * values for from the global config.
5466 		 */
5467 
5468 		if (view->recursionacl == NULL) {
5469 			/* global default only */
5470 			CHECK(configure_view_acl(
5471 				NULL, NULL, named_g_config, "allow-recursion",
5472 				NULL, actx, named_g_mctx, &view->recursionacl));
5473 		}
5474 		if (view->recursiononacl == NULL) {
5475 			/* global default only */
5476 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5477 						 "allow-recursion-on", NULL,
5478 						 actx, named_g_mctx,
5479 						 &view->recursiononacl));
5480 		}
5481 		if (view->cacheacl == NULL) {
5482 			/* global default only */
5483 			CHECK(configure_view_acl(
5484 				NULL, NULL, named_g_config, "allow-query-cache",
5485 				NULL, actx, named_g_mctx, &view->cacheacl));
5486 		}
5487 		if (view->cacheonacl == NULL) {
5488 			/* global default only */
5489 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5490 						 "allow-query-cache-on", NULL,
5491 						 actx, named_g_mctx,
5492 						 &view->cacheonacl));
5493 		}
5494 	} else {
5495 		/*
5496 		 * We're not recursive; if the query-cache ACLs haven't
5497 		 * been set at the options/view level, set them to none.
5498 		 */
5499 		if (view->cacheacl == NULL) {
5500 			CHECK(dns_acl_none(mctx, &view->cacheacl));
5501 		}
5502 		if (view->cacheonacl == NULL) {
5503 			CHECK(dns_acl_none(mctx, &view->cacheonacl));
5504 		}
5505 	}
5506 
5507 	/*
5508 	 * Finished setting recursion and query-cache ACLs, so now we
5509 	 * can get the allow-query default if it wasn't set in named.conf
5510 	 */
5511 	if (view->queryacl == NULL) {
5512 		/* global default only */
5513 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5514 					 "allow-query", NULL, actx,
5515 					 named_g_mctx, &view->queryacl));
5516 	}
5517 
5518 	/*
5519 	 * Ignore case when compressing responses to the specified
5520 	 * clients. This causes case not always to be preserved,
5521 	 * and is needed by some broken clients.
5522 	 */
5523 	CHECK(configure_view_acl(vconfig, config, named_g_config,
5524 				 "no-case-compress", NULL, actx, named_g_mctx,
5525 				 &view->nocasecompress));
5526 
5527 	/*
5528 	 * Disable name compression completely, this is a tradeoff
5529 	 * between CPU and network usage.
5530 	 */
5531 	obj = NULL;
5532 	result = named_config_get(maps, "message-compression", &obj);
5533 	INSIST(result == ISC_R_SUCCESS);
5534 	view->msgcompression = cfg_obj_asboolean(obj);
5535 
5536 	/*
5537 	 * Filter setting on addresses in the answer section.
5538 	 */
5539 	CHECK(configure_view_acl(vconfig, config, named_g_config,
5540 				 "deny-answer-addresses", "acl", actx,
5541 				 named_g_mctx, &view->denyansweracl));
5542 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
5543 				       "except-from", named_g_mctx,
5544 				       &view->answeracl_exclude));
5545 
5546 	/*
5547 	 * Filter setting on names (CNAME/DNAME targets) in the answer section.
5548 	 */
5549 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5550 				       "name", named_g_mctx,
5551 				       &view->denyanswernames));
5552 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5553 				       "except-from", named_g_mctx,
5554 				       &view->answernames_exclude));
5555 
5556 	/*
5557 	 * Configure sortlist, if set
5558 	 */
5559 	CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx,
5560 				      &view->sortlist));
5561 
5562 	/*
5563 	 * Configure default allow-update and allow-update-forwarding ACLs,
5564 	 * so they can be inherited by zones. (XXX: These are not
5565 	 * read from the options/view level here. However, they may be
5566 	 * read from there in zoneconf.c:configure_zone_acl() later.)
5567 	 */
5568 	if (view->updateacl == NULL) {
5569 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5570 					 "allow-update", NULL, actx,
5571 					 named_g_mctx, &view->updateacl));
5572 	}
5573 	if (view->upfwdacl == NULL) {
5574 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5575 					 "allow-update-forwarding", NULL, actx,
5576 					 named_g_mctx, &view->upfwdacl));
5577 	}
5578 
5579 	/*
5580 	 * Configure default allow-transfer and allow-notify ACLs so they
5581 	 * can be inherited by zones.
5582 	 */
5583 	if (view->transferacl == NULL) {
5584 		CHECK(configure_view_acl(vconfig, config, named_g_config,
5585 					 "allow-transfer", NULL, actx,
5586 					 named_g_mctx, &view->transferacl));
5587 	}
5588 	if (view->notifyacl == NULL) {
5589 		CHECK(configure_view_acl(vconfig, config, named_g_config,
5590 					 "allow-notify", NULL, actx,
5591 					 named_g_mctx, &view->notifyacl));
5592 	}
5593 
5594 	obj = NULL;
5595 	result = named_config_get(maps, "provide-ixfr", &obj);
5596 	INSIST(result == ISC_R_SUCCESS);
5597 	view->provideixfr = cfg_obj_asboolean(obj);
5598 
5599 	obj = NULL;
5600 	result = named_config_get(maps, "request-nsid", &obj);
5601 	INSIST(result == ISC_R_SUCCESS);
5602 	view->requestnsid = cfg_obj_asboolean(obj);
5603 
5604 	obj = NULL;
5605 	result = named_config_get(maps, "send-cookie", &obj);
5606 	INSIST(result == ISC_R_SUCCESS);
5607 	view->sendcookie = cfg_obj_asboolean(obj);
5608 
5609 	obj = NULL;
5610 	if (view->pad_acl != NULL) {
5611 		dns_acl_detach(&view->pad_acl);
5612 	}
5613 	result = named_config_get(optionmaps, "response-padding", &obj);
5614 	if (result == ISC_R_SUCCESS) {
5615 		const cfg_obj_t *padobj = cfg_tuple_get(obj, "block-size");
5616 		const cfg_obj_t *aclobj = cfg_tuple_get(obj, "acl");
5617 		uint32_t padding = cfg_obj_asuint32(padobj);
5618 
5619 		if (padding > 512U) {
5620 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
5621 				    "response-padding block-size cannot "
5622 				    "exceed 512: lowering");
5623 			padding = 512U;
5624 		}
5625 		view->padding = (uint16_t)padding;
5626 		CHECK(cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx,
5627 					 named_g_mctx, 0, &view->pad_acl));
5628 	}
5629 
5630 	obj = NULL;
5631 	result = named_config_get(maps, "require-server-cookie", &obj);
5632 	INSIST(result == ISC_R_SUCCESS);
5633 	view->requireservercookie = cfg_obj_asboolean(obj);
5634 
5635 	obj = NULL;
5636 	result = named_config_get(maps, "v6-bias", &obj);
5637 	INSIST(result == ISC_R_SUCCESS);
5638 	view->v6bias = cfg_obj_asuint32(obj) * 1000;
5639 
5640 	obj = NULL;
5641 	result = named_config_get(maps, "max-clients-per-query", &obj);
5642 	INSIST(result == ISC_R_SUCCESS);
5643 	max_clients_per_query = cfg_obj_asuint32(obj);
5644 
5645 	obj = NULL;
5646 	result = named_config_get(maps, "clients-per-query", &obj);
5647 	INSIST(result == ISC_R_SUCCESS);
5648 	dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj),
5649 					max_clients_per_query);
5650 
5651 	/*
5652 	 * This is used for the cache and also as a default value
5653 	 * for zone databases.
5654 	 */
5655 	obj = NULL;
5656 	result = named_config_get(maps, "max-records-per-type", &obj);
5657 	INSIST(result == ISC_R_SUCCESS);
5658 	dns_view_setmaxrrperset(view, cfg_obj_asuint32(obj));
5659 
5660 	/*
5661 	 * This is used for the cache and also as a default value
5662 	 * for zone databases.
5663 	 */
5664 	obj = NULL;
5665 	result = named_config_get(maps, "max-types-per-name", &obj);
5666 	INSIST(result == ISC_R_SUCCESS);
5667 	dns_view_setmaxtypepername(view, cfg_obj_asuint32(obj));
5668 
5669 	obj = NULL;
5670 	result = named_config_get(maps, "max-recursion-depth", &obj);
5671 	INSIST(result == ISC_R_SUCCESS);
5672 	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
5673 
5674 	obj = NULL;
5675 	result = named_config_get(maps, "max-recursion-queries", &obj);
5676 	INSIST(result == ISC_R_SUCCESS);
5677 	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
5678 
5679 	obj = NULL;
5680 	result = named_config_get(maps, "max-query-restarts", &obj);
5681 	INSIST(result == ISC_R_SUCCESS);
5682 	dns_view_setmaxrestarts(view, cfg_obj_asuint32(obj));
5683 
5684 	obj = NULL;
5685 	result = named_config_get(maps, "fetches-per-zone", &obj);
5686 	INSIST(result == ISC_R_SUCCESS);
5687 	obj2 = cfg_tuple_get(obj, "fetches");
5688 	dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
5689 	obj2 = cfg_tuple_get(obj, "response");
5690 	if (!cfg_obj_isvoid(obj2)) {
5691 		const char *resp = cfg_obj_asstring(obj2);
5692 		isc_result_t r = DNS_R_SERVFAIL;
5693 
5694 		if (strcasecmp(resp, "drop") == 0) {
5695 			r = DNS_R_DROP;
5696 		} else if (strcasecmp(resp, "fail") == 0) {
5697 			r = DNS_R_SERVFAIL;
5698 		} else {
5699 			UNREACHABLE();
5700 		}
5701 
5702 		dns_resolver_setquotaresponse(view->resolver,
5703 					      dns_quotatype_zone, r);
5704 	}
5705 
5706 	obj = NULL;
5707 	result = named_config_get(maps, "prefetch", &obj);
5708 	INSIST(result == ISC_R_SUCCESS);
5709 	prefetch_trigger = cfg_tuple_get(obj, "trigger");
5710 	view->prefetch_trigger = cfg_obj_asuint32(prefetch_trigger);
5711 	if (view->prefetch_trigger > 10) {
5712 		view->prefetch_trigger = 10;
5713 	}
5714 	prefetch_eligible = cfg_tuple_get(obj, "eligible");
5715 	if (cfg_obj_isvoid(prefetch_eligible)) {
5716 		int m;
5717 		for (m = 1; maps[m] != NULL; m++) {
5718 			obj = NULL;
5719 			result = named_config_get(&maps[m], "prefetch", &obj);
5720 			INSIST(result == ISC_R_SUCCESS);
5721 			prefetch_eligible = cfg_tuple_get(obj, "eligible");
5722 			if (cfg_obj_isuint32(prefetch_eligible)) {
5723 				break;
5724 			}
5725 		}
5726 		INSIST(cfg_obj_isuint32(prefetch_eligible));
5727 	}
5728 	view->prefetch_eligible = cfg_obj_asuint32(prefetch_eligible);
5729 	if (view->prefetch_eligible < view->prefetch_trigger + 6) {
5730 		view->prefetch_eligible = view->prefetch_trigger + 6;
5731 	}
5732 
5733 	/*
5734 	 * For now, there is only one kind of trusted keys, the
5735 	 * "security roots".
5736 	 */
5737 	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
5738 					auto_root, mctx));
5739 	dns_resolver_resetmustbesecure(view->resolver);
5740 	obj = NULL;
5741 	result = named_config_get(maps, "dnssec-must-be-secure", &obj);
5742 	if (result == ISC_R_SUCCESS) {
5743 		CHECK(mustbesecure(obj, view->resolver));
5744 	}
5745 
5746 	obj = NULL;
5747 	result = named_config_get(maps, "nta-recheck", &obj);
5748 	INSIST(result == ISC_R_SUCCESS);
5749 	view->nta_recheck = cfg_obj_asduration(obj);
5750 
5751 	obj = NULL;
5752 	result = named_config_get(maps, "nta-lifetime", &obj);
5753 	INSIST(result == ISC_R_SUCCESS);
5754 	view->nta_lifetime = cfg_obj_asduration(obj);
5755 
5756 	obj = NULL;
5757 	result = named_config_get(maps, "preferred-glue", &obj);
5758 	if (result == ISC_R_SUCCESS) {
5759 		str = cfg_obj_asstring(obj);
5760 		if (strcasecmp(str, "a") == 0) {
5761 			view->preferred_glue = dns_rdatatype_a;
5762 		} else if (strcasecmp(str, "aaaa") == 0) {
5763 			view->preferred_glue = dns_rdatatype_aaaa;
5764 		} else {
5765 			view->preferred_glue = 0;
5766 		}
5767 	} else {
5768 		view->preferred_glue = 0;
5769 	}
5770 
5771 	obj = NULL;
5772 	result = named_config_get(maps, "root-delegation-only", &obj);
5773 	if (result == ISC_R_SUCCESS) {
5774 		dns_view_setrootdelonly(view, true);
5775 	}
5776 	if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
5777 		const cfg_obj_t *exclude;
5778 		dns_fixedname_t fixed;
5779 		dns_name_t *name;
5780 
5781 		name = dns_fixedname_initname(&fixed);
5782 		for (element = cfg_list_first(obj); element != NULL;
5783 		     element = cfg_list_next(element))
5784 		{
5785 			exclude = cfg_listelt_value(element);
5786 			CHECK(dns_name_fromstring(
5787 				name, cfg_obj_asstring(exclude), 0, NULL));
5788 			dns_view_excludedelegationonly(view, name);
5789 		}
5790 	} else {
5791 		dns_view_setrootdelonly(view, false);
5792 	}
5793 
5794 	/*
5795 	 * Load DynDB modules.
5796 	 */
5797 	dyndb_list = NULL;
5798 	if (voptions != NULL) {
5799 		(void)cfg_map_get(voptions, "dyndb", &dyndb_list);
5800 	} else {
5801 		(void)cfg_map_get(config, "dyndb", &dyndb_list);
5802 	}
5803 
5804 	for (element = cfg_list_first(dyndb_list); element != NULL;
5805 	     element = cfg_list_next(element))
5806 	{
5807 		const cfg_obj_t *dyndb = cfg_listelt_value(element);
5808 
5809 		if (dctx == NULL) {
5810 			const void *hashinit = isc_hash_get_initializer();
5811 			CHECK(dns_dyndb_createctx(mctx, hashinit, named_g_lctx,
5812 						  view, named_g_server->zonemgr,
5813 						  named_g_server->task,
5814 						  named_g_timermgr, &dctx));
5815 		}
5816 
5817 		CHECK(configure_dyndb(dyndb, mctx, dctx));
5818 	}
5819 
5820 	/*
5821 	 * Load plugins.
5822 	 */
5823 	plugin_list = NULL;
5824 	if (voptions != NULL) {
5825 		(void)cfg_map_get(voptions, "plugin", &plugin_list);
5826 	} else {
5827 		(void)cfg_map_get(config, "plugin", &plugin_list);
5828 	}
5829 
5830 	if (plugin_list != NULL) {
5831 		INSIST(view->hooktable == NULL);
5832 		CHECK(ns_hooktable_create(view->mctx,
5833 					  (ns_hooktable_t **)&view->hooktable));
5834 		view->hooktable_free = ns_hooktable_free;
5835 
5836 		ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
5837 		view->plugins_free = ns_plugins_free;
5838 
5839 		CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
5840 					     register_one_plugin, view));
5841 	}
5842 
5843 	/*
5844 	 * Setup automatic empty zones.  If recursion is off then
5845 	 * they are disabled by default.
5846 	 */
5847 	obj = NULL;
5848 	(void)named_config_get(maps, "empty-zones-enable", &obj);
5849 	(void)named_config_get(maps, "disable-empty-zone", &disablelist);
5850 	if (obj == NULL && disablelist == NULL &&
5851 	    view->rdclass == dns_rdataclass_in)
5852 	{
5853 		empty_zones_enable = view->recursion;
5854 	} else if (view->rdclass == dns_rdataclass_in) {
5855 		if (obj != NULL) {
5856 			empty_zones_enable = cfg_obj_asboolean(obj);
5857 		} else {
5858 			empty_zones_enable = view->recursion;
5859 		}
5860 	} else {
5861 		empty_zones_enable = false;
5862 	}
5863 
5864 	if (empty_zones_enable) {
5865 		const char *empty;
5866 		int empty_zone = 0;
5867 		dns_fixedname_t fixed;
5868 		dns_name_t *name;
5869 		isc_buffer_t buffer;
5870 		char server[DNS_NAME_FORMATSIZE + 1];
5871 		char contact[DNS_NAME_FORMATSIZE + 1];
5872 		const char *empty_dbtype[4] = { "_builtin", "empty", NULL,
5873 						NULL };
5874 		int empty_dbtypec = 4;
5875 		dns_zonestat_level_t statlevel = dns_zonestat_none;
5876 
5877 		name = dns_fixedname_initname(&fixed);
5878 
5879 		obj = NULL;
5880 		result = named_config_get(maps, "empty-server", &obj);
5881 		if (result == ISC_R_SUCCESS) {
5882 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5883 						  0, NULL));
5884 			isc_buffer_init(&buffer, server, sizeof(server) - 1);
5885 			CHECK(dns_name_totext(name, false, &buffer));
5886 			server[isc_buffer_usedlength(&buffer)] = 0;
5887 			empty_dbtype[2] = server;
5888 		} else {
5889 			empty_dbtype[2] = "@";
5890 		}
5891 
5892 		obj = NULL;
5893 		result = named_config_get(maps, "empty-contact", &obj);
5894 		if (result == ISC_R_SUCCESS) {
5895 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5896 						  0, NULL));
5897 			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
5898 			CHECK(dns_name_totext(name, false, &buffer));
5899 			contact[isc_buffer_usedlength(&buffer)] = 0;
5900 			empty_dbtype[3] = contact;
5901 		} else {
5902 			empty_dbtype[3] = ".";
5903 		}
5904 
5905 		obj = NULL;
5906 		result = named_config_get(maps, "zone-statistics", &obj);
5907 		INSIST(result == ISC_R_SUCCESS);
5908 		if (cfg_obj_isboolean(obj)) {
5909 			if (cfg_obj_asboolean(obj)) {
5910 				statlevel = dns_zonestat_full;
5911 			} else {
5912 				statlevel = dns_zonestat_none;
5913 			}
5914 		} else {
5915 			const char *levelstr = cfg_obj_asstring(obj);
5916 			if (strcasecmp(levelstr, "full") == 0) {
5917 				statlevel = dns_zonestat_full;
5918 			} else if (strcasecmp(levelstr, "terse") == 0) {
5919 				statlevel = dns_zonestat_terse;
5920 			} else if (strcasecmp(levelstr, "none") == 0) {
5921 				statlevel = dns_zonestat_none;
5922 			} else {
5923 				UNREACHABLE();
5924 			}
5925 		}
5926 
5927 		for (empty = empty_zones[empty_zone]; empty != NULL;
5928 		     empty = empty_zones[++empty_zone])
5929 		{
5930 			dns_forwarders_t *dnsforwarders = NULL;
5931 
5932 			/*
5933 			 * Look for zone on drop list.
5934 			 */
5935 			CHECK(dns_name_fromstring(name, empty, 0, NULL));
5936 			if (disablelist != NULL &&
5937 			    on_disable_list(disablelist, name))
5938 			{
5939 				continue;
5940 			}
5941 
5942 			/*
5943 			 * This zone already exists.
5944 			 */
5945 			(void)dns_view_findzone(view, name, &zone);
5946 			if (zone != NULL) {
5947 				dns_zone_detach(&zone);
5948 				continue;
5949 			}
5950 
5951 			/*
5952 			 * If we would forward this name don't add a
5953 			 * empty zone for it.
5954 			 */
5955 			result = dns_fwdtable_find(view->fwdtable, name, NULL,
5956 						   &dnsforwarders);
5957 			if ((result == ISC_R_SUCCESS ||
5958 			     result == DNS_R_PARTIALMATCH) &&
5959 			    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
5960 			{
5961 				continue;
5962 			}
5963 
5964 			/*
5965 			 * See if we can re-use a existing zone.
5966 			 */
5967 			result = dns_viewlist_find(&named_g_server->viewlist,
5968 						   view->name, view->rdclass,
5969 						   &pview);
5970 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
5971 			{
5972 				goto cleanup;
5973 			}
5974 
5975 			if (pview != NULL) {
5976 				(void)dns_view_findzone(pview, name, &zone);
5977 				dns_view_detach(&pview);
5978 			}
5979 
5980 			CHECK(create_empty_zone(zone, name, view, zonelist,
5981 						empty_dbtype, empty_dbtypec,
5982 						statlevel));
5983 			if (zone != NULL) {
5984 				dns_zone_detach(&zone);
5985 			}
5986 		}
5987 	}
5988 
5989 	obj = NULL;
5990 	if (view->rdclass == dns_rdataclass_in) {
5991 		(void)named_config_get(maps, "ipv4only-enable", &obj);
5992 	}
5993 	if (view->rdclass == dns_rdataclass_in && (obj != NULL)
5994 		    ? cfg_obj_asboolean(obj)
5995 		    : !ISC_LIST_EMPTY(view->dns64))
5996 	{
5997 		const char *server, *contact;
5998 		dns_fixedname_t fixed;
5999 		dns_name_t *name;
6000 		struct {
6001 			const char *name;
6002 			const char *type;
6003 		} zones[] = {
6004 			{ "ipv4only.arpa", "ipv4only" },
6005 			{ "170.0.0.192.in-addr.arpa", "ipv4reverse" },
6006 			{ "171.0.0.192.in-addr.arpa", "ipv4reverse" },
6007 		};
6008 		size_t ipv4only_zone;
6009 
6010 		obj = NULL;
6011 		result = named_config_get(maps, "ipv4only-server", &obj);
6012 		if (result == ISC_R_SUCCESS) {
6013 			server = cfg_obj_asstring(obj);
6014 		} else {
6015 			server = NULL;
6016 		}
6017 
6018 		obj = NULL;
6019 		result = named_config_get(maps, "ipv4only-contact", &obj);
6020 		if (result == ISC_R_SUCCESS) {
6021 			contact = cfg_obj_asstring(obj);
6022 		} else {
6023 			contact = NULL;
6024 		}
6025 
6026 		name = dns_fixedname_initname(&fixed);
6027 		for (ipv4only_zone = 0; ipv4only_zone < ARRAY_SIZE(zones);
6028 		     ipv4only_zone++)
6029 		{
6030 			dns_forwarders_t *dnsforwarders = NULL;
6031 
6032 			CHECK(dns_name_fromstring(
6033 				name, zones[ipv4only_zone].name, 0, NULL));
6034 
6035 			(void)dns_view_findzone(view, name, &zone);
6036 			if (zone != NULL) {
6037 				dns_zone_detach(&zone);
6038 				continue;
6039 			}
6040 
6041 			/*
6042 			 * If we would forward this name don't add it.
6043 			 */
6044 			result = dns_fwdtable_find(view->fwdtable, name, NULL,
6045 						   &dnsforwarders);
6046 			if ((result == ISC_R_SUCCESS ||
6047 			     result == DNS_R_PARTIALMATCH) &&
6048 			    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
6049 			{
6050 				continue;
6051 			}
6052 
6053 			/*
6054 			 * See if we can re-use a existing zone.
6055 			 */
6056 			result = dns_viewlist_find(&named_g_server->viewlist,
6057 						   view->name, view->rdclass,
6058 						   &pview);
6059 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
6060 			{
6061 				goto cleanup;
6062 			}
6063 
6064 			if (pview != NULL) {
6065 				(void)dns_view_findzone(pview, name, &zone);
6066 				dns_view_detach(&pview);
6067 			}
6068 
6069 			CHECK(create_ipv4only_zone(zone, view, name,
6070 						   zones[ipv4only_zone].type,
6071 						   mctx, server, contact));
6072 			if (zone != NULL) {
6073 				dns_zone_detach(&zone);
6074 			}
6075 		}
6076 	}
6077 
6078 	obj = NULL;
6079 	result = named_config_get(maps, "rate-limit", &obj);
6080 	if (result == ISC_R_SUCCESS) {
6081 		result = configure_rrl(view, config, obj);
6082 		if (result != ISC_R_SUCCESS) {
6083 			goto cleanup;
6084 		}
6085 	}
6086 
6087 	/*
6088 	 * Set the servfail-ttl.
6089 	 */
6090 	obj = NULL;
6091 	result = named_config_get(maps, "servfail-ttl", &obj);
6092 	INSIST(result == ISC_R_SUCCESS);
6093 	fail_ttl = cfg_obj_asduration(obj);
6094 	if (fail_ttl > 30) {
6095 		fail_ttl = 30;
6096 	}
6097 	dns_view_setfailttl(view, fail_ttl);
6098 
6099 	/*
6100 	 * Name space to look up redirect information in.
6101 	 */
6102 	obj = NULL;
6103 	result = named_config_get(maps, "nxdomain-redirect", &obj);
6104 	if (result == ISC_R_SUCCESS) {
6105 		dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
6106 		CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0,
6107 					  NULL));
6108 		view->redirectzone = name;
6109 	} else {
6110 		view->redirectzone = NULL;
6111 	}
6112 
6113 	/*
6114 	 * Exceptions to DNSSEC validation.
6115 	 */
6116 	obj = NULL;
6117 	result = named_config_get(maps, "validate-except", &obj);
6118 	if (result == ISC_R_SUCCESS) {
6119 		result = dns_view_getntatable(view, &ntatable);
6120 	}
6121 	if (result == ISC_R_SUCCESS) {
6122 		for (element = cfg_list_first(obj); element != NULL;
6123 		     element = cfg_list_next(element))
6124 		{
6125 			dns_fixedname_t fntaname;
6126 			dns_name_t *ntaname;
6127 
6128 			ntaname = dns_fixedname_initname(&fntaname);
6129 			obj = cfg_listelt_value(element);
6130 			CHECK(dns_name_fromstring(
6131 				ntaname, cfg_obj_asstring(obj), 0, NULL));
6132 			CHECK(dns_ntatable_add(ntatable, ntaname, true, 0,
6133 					       0xffffffffU));
6134 		}
6135 	}
6136 
6137 #ifdef HAVE_DNSTAP
6138 	/*
6139 	 * Set up the dnstap environment and configure message
6140 	 * types to log.
6141 	 */
6142 	CHECK(configure_dnstap(maps, view));
6143 #endif /* HAVE_DNSTAP */
6144 
6145 	result = ISC_R_SUCCESS;
6146 
6147 cleanup:
6148 	/*
6149 	 * Revert to the old view if there was an error.
6150 	 */
6151 	if (result != ISC_R_SUCCESS) {
6152 		isc_result_t result2;
6153 
6154 		result2 = dns_viewlist_find(&named_g_server->viewlist,
6155 					    view->name, view->rdclass, &pview);
6156 		if (result2 == ISC_R_SUCCESS) {
6157 			dns_view_thaw(pview);
6158 
6159 			obj = NULL;
6160 			if (rpz_configured &&
6161 			    pview->rdclass == dns_rdataclass_in && need_hints &&
6162 			    named_config_get(maps, "response-policy", &obj) ==
6163 				    ISC_R_SUCCESS)
6164 			{
6165 				/*
6166 				 * We are swapping the places of the `view` and
6167 				 * `pview` in the function's parameters list
6168 				 * because we are reverting the same operation
6169 				 * done previously in the "correct" order.
6170 				 */
6171 				result2 = configure_rpz(pview, view, maps, obj,
6172 							&old_rpz_ok);
6173 				if (result2 != ISC_R_SUCCESS) {
6174 					isc_log_write(named_g_lctx,
6175 						      NAMED_LOGCATEGORY_GENERAL,
6176 						      NAMED_LOGMODULE_SERVER,
6177 						      ISC_LOG_ERROR,
6178 						      "rpz configuration "
6179 						      "revert failed for view "
6180 						      "'%s'",
6181 						      pview->name);
6182 				}
6183 			}
6184 
6185 			obj = NULL;
6186 			if (catz_configured &&
6187 			    pview->rdclass == dns_rdataclass_in && need_hints &&
6188 			    named_config_get(maps, "catalog-zones", &obj) ==
6189 				    ISC_R_SUCCESS)
6190 			{
6191 				/*
6192 				 * We are swapping the places of the `view` and
6193 				 * `pview` in the function's parameters list
6194 				 * because we are reverting the same operation
6195 				 * done previously in the "correct" order.
6196 				 */
6197 				result2 = configure_catz(pview, view, config,
6198 							 obj);
6199 				if (result2 != ISC_R_SUCCESS) {
6200 					isc_log_write(named_g_lctx,
6201 						      NAMED_LOGCATEGORY_GENERAL,
6202 						      NAMED_LOGMODULE_SERVER,
6203 						      ISC_LOG_ERROR,
6204 						      "catz configuration "
6205 						      "revert failed for view "
6206 						      "'%s'",
6207 						      pview->name);
6208 				}
6209 			}
6210 
6211 			dns_view_freeze(pview);
6212 		}
6213 
6214 		if (pview != NULL) {
6215 			dns_view_detach(&pview);
6216 		}
6217 
6218 		if (zone_element_latest != NULL) {
6219 			for (element = cfg_list_first(zonelist);
6220 			     element != NULL; element = cfg_list_next(element))
6221 			{
6222 				const cfg_obj_t *zconfig =
6223 					cfg_listelt_value(element);
6224 				configure_zone_setviewcommit(result, zconfig,
6225 							     view);
6226 				if (element == zone_element_latest) {
6227 					/*
6228 					 * This was the latest element that was
6229 					 * successfully configured earlier.
6230 					 */
6231 					break;
6232 				}
6233 			}
6234 		}
6235 	}
6236 
6237 	if (ntatable != NULL) {
6238 		dns_ntatable_detach(&ntatable);
6239 	}
6240 	if (clients != NULL) {
6241 		dns_acl_detach(&clients);
6242 	}
6243 	if (mapped != NULL) {
6244 		dns_acl_detach(&mapped);
6245 	}
6246 	if (excluded != NULL) {
6247 		dns_acl_detach(&excluded);
6248 	}
6249 	if (ring != NULL) {
6250 		dns_tsigkeyring_detach(&ring);
6251 	}
6252 	if (zone != NULL) {
6253 		dns_zone_detach(&zone);
6254 	}
6255 	if (dispatch4 != NULL) {
6256 		dns_dispatch_detach(&dispatch4);
6257 	}
6258 	if (dispatch6 != NULL) {
6259 		dns_dispatch_detach(&dispatch6);
6260 	}
6261 	if (resstats != NULL) {
6262 		isc_stats_detach(&resstats);
6263 	}
6264 	if (resquerystats != NULL) {
6265 		dns_stats_detach(&resquerystats);
6266 	}
6267 	if (order != NULL) {
6268 		dns_order_detach(&order);
6269 	}
6270 	if (cmctx != NULL) {
6271 		isc_mem_detach(&cmctx);
6272 	}
6273 	if (hmctx != NULL) {
6274 		isc_mem_detach(&hmctx);
6275 	}
6276 	if (cache != NULL) {
6277 		dns_cache_detach(&cache);
6278 	}
6279 	if (dctx != NULL) {
6280 		dns_dyndb_destroyctx(&dctx);
6281 	}
6282 
6283 	return (result);
6284 }
6285 
6286 static isc_result_t
6287 configure_hints(dns_view_t *view, const char *filename) {
6288 	isc_result_t result;
6289 	dns_db_t *db;
6290 
6291 	db = NULL;
6292 	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
6293 	if (result == ISC_R_SUCCESS) {
6294 		dns_view_sethints(view, db);
6295 		dns_db_detach(&db);
6296 	}
6297 
6298 	return (result);
6299 }
6300 
6301 static isc_result_t
6302 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
6303 		     const cfg_obj_t *alternates) {
6304 	const cfg_obj_t *portobj;
6305 	const cfg_obj_t *addresses;
6306 	const cfg_listelt_t *element;
6307 	isc_result_t result = ISC_R_SUCCESS;
6308 	in_port_t port;
6309 
6310 	/*
6311 	 * Determine which port to send requests to.
6312 	 */
6313 	CHECKM(named_config_getport(config, "port", &port), "port");
6314 
6315 	if (alternates != NULL) {
6316 		portobj = cfg_tuple_get(alternates, "port");
6317 		if (cfg_obj_isuint32(portobj)) {
6318 			uint32_t val = cfg_obj_asuint32(portobj);
6319 			if (val > UINT16_MAX) {
6320 				cfg_obj_log(portobj, named_g_lctx,
6321 					    ISC_LOG_ERROR,
6322 					    "port '%u' out of range", val);
6323 				return (ISC_R_RANGE);
6324 			}
6325 			port = (in_port_t)val;
6326 		}
6327 	}
6328 
6329 	addresses = NULL;
6330 	if (alternates != NULL) {
6331 		addresses = cfg_tuple_get(alternates, "addresses");
6332 	}
6333 
6334 	for (element = cfg_list_first(addresses); element != NULL;
6335 	     element = cfg_list_next(element))
6336 	{
6337 		const cfg_obj_t *alternate = cfg_listelt_value(element);
6338 		isc_sockaddr_t sa;
6339 
6340 		if (!cfg_obj_issockaddr(alternate)) {
6341 			dns_fixedname_t fixed;
6342 			dns_name_t *name;
6343 			const char *str = cfg_obj_asstring(
6344 				cfg_tuple_get(alternate, "name"));
6345 			isc_buffer_t buffer;
6346 			in_port_t myport = port;
6347 
6348 			isc_buffer_constinit(&buffer, str, strlen(str));
6349 			isc_buffer_add(&buffer, strlen(str));
6350 			name = dns_fixedname_initname(&fixed);
6351 			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
6352 						NULL));
6353 
6354 			portobj = cfg_tuple_get(alternate, "port");
6355 			if (cfg_obj_isuint32(portobj)) {
6356 				uint32_t val = cfg_obj_asuint32(portobj);
6357 				if (val > UINT16_MAX) {
6358 					cfg_obj_log(portobj, named_g_lctx,
6359 						    ISC_LOG_ERROR,
6360 						    "port '%u' out of range",
6361 						    val);
6362 					return (ISC_R_RANGE);
6363 				}
6364 				myport = (in_port_t)val;
6365 			}
6366 			dns_resolver_addalternate(view->resolver, NULL, name,
6367 						  myport);
6368 			continue;
6369 		}
6370 
6371 		sa = *cfg_obj_assockaddr(alternate);
6372 		if (isc_sockaddr_getport(&sa) == 0) {
6373 			isc_sockaddr_setport(&sa, port);
6374 		}
6375 		dns_resolver_addalternate(view->resolver, &sa, NULL, 0);
6376 	}
6377 
6378 cleanup:
6379 	return (result);
6380 }
6381 
6382 static isc_result_t
6383 configure_forward(const cfg_obj_t *config, dns_view_t *view,
6384 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
6385 		  const cfg_obj_t *forwardtype) {
6386 	const cfg_obj_t *portobj = NULL;
6387 	const cfg_obj_t *faddresses = NULL;
6388 	const cfg_listelt_t *element = NULL;
6389 	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
6390 	dns_forwarderlist_t fwdlist;
6391 	dns_forwarder_t *fwd = NULL;
6392 	isc_result_t result;
6393 	in_port_t port;
6394 
6395 	ISC_LIST_INIT(fwdlist);
6396 
6397 	/*
6398 	 * Determine which port to send forwarded requests to.
6399 	 */
6400 	CHECKM(named_config_getport(config, "port", &port), "port");
6401 
6402 	if (forwarders != NULL) {
6403 		portobj = cfg_tuple_get(forwarders, "port");
6404 		if (cfg_obj_isuint32(portobj)) {
6405 			uint32_t val = cfg_obj_asuint32(portobj);
6406 			if (val > UINT16_MAX) {
6407 				cfg_obj_log(portobj, named_g_lctx,
6408 					    ISC_LOG_ERROR,
6409 					    "port '%u' out of range", val);
6410 				return (ISC_R_RANGE);
6411 			}
6412 			port = (in_port_t)val;
6413 		}
6414 	}
6415 
6416 	faddresses = NULL;
6417 	if (forwarders != NULL) {
6418 		faddresses = cfg_tuple_get(forwarders, "addresses");
6419 	}
6420 
6421 	for (element = cfg_list_first(faddresses); element != NULL;
6422 	     element = cfg_list_next(element))
6423 	{
6424 		const cfg_obj_t *forwarder = cfg_listelt_value(element);
6425 		fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
6426 		fwd->addr = *cfg_obj_assockaddr(forwarder);
6427 		if (isc_sockaddr_getport(&fwd->addr) == 0) {
6428 			isc_sockaddr_setport(&fwd->addr, port);
6429 		}
6430 		ISC_LINK_INIT(fwd, link);
6431 		ISC_LIST_APPEND(fwdlist, fwd, link);
6432 	}
6433 
6434 	if (ISC_LIST_EMPTY(fwdlist)) {
6435 		if (forwardtype != NULL) {
6436 			cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING,
6437 				    "no forwarders seen; disabling "
6438 				    "forwarding");
6439 		}
6440 		fwdpolicy = dns_fwdpolicy_none;
6441 	} else {
6442 		if (forwardtype == NULL) {
6443 			fwdpolicy = dns_fwdpolicy_first;
6444 		} else {
6445 			const char *forwardstr = cfg_obj_asstring(forwardtype);
6446 			if (strcasecmp(forwardstr, "first") == 0) {
6447 				fwdpolicy = dns_fwdpolicy_first;
6448 			} else if (strcasecmp(forwardstr, "only") == 0) {
6449 				fwdpolicy = dns_fwdpolicy_only;
6450 			} else {
6451 				UNREACHABLE();
6452 			}
6453 		}
6454 	}
6455 
6456 	result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
6457 				     fwdpolicy);
6458 	if (result != ISC_R_SUCCESS) {
6459 		char namebuf[DNS_NAME_FORMATSIZE];
6460 		dns_name_format(origin, namebuf, sizeof(namebuf));
6461 		cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING,
6462 			    "could not set up forwarding for domain '%s': %s",
6463 			    namebuf, isc_result_totext(result));
6464 		goto cleanup;
6465 	}
6466 
6467 	if (fwdpolicy == dns_fwdpolicy_only) {
6468 		dns_view_sfd_add(view, origin);
6469 	}
6470 
6471 	result = ISC_R_SUCCESS;
6472 
6473 cleanup:
6474 
6475 	while (!ISC_LIST_EMPTY(fwdlist)) {
6476 		fwd = ISC_LIST_HEAD(fwdlist);
6477 		ISC_LIST_UNLINK(fwdlist, fwd, link);
6478 		isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
6479 	}
6480 
6481 	return (result);
6482 }
6483 
6484 static isc_result_t
6485 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
6486 	     dns_rdataclass_t *classp) {
6487 	isc_result_t result = ISC_R_SUCCESS;
6488 	const char *viewname;
6489 	dns_rdataclass_t viewclass;
6490 
6491 	REQUIRE(namep != NULL && *namep == NULL);
6492 	REQUIRE(classp != NULL);
6493 
6494 	if (vconfig != NULL) {
6495 		const cfg_obj_t *classobj = NULL;
6496 
6497 		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
6498 		classobj = cfg_tuple_get(vconfig, "class");
6499 		CHECK(named_config_getclass(classobj, dns_rdataclass_in,
6500 					    &viewclass));
6501 		if (dns_rdataclass_ismeta(viewclass)) {
6502 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6503 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6504 				      "view '%s': class must not be meta",
6505 				      viewname);
6506 			CHECK(ISC_R_FAILURE);
6507 		}
6508 	} else {
6509 		viewname = "_default";
6510 		viewclass = dns_rdataclass_in;
6511 	}
6512 
6513 	*namep = viewname;
6514 	*classp = viewclass;
6515 
6516 cleanup:
6517 	return (result);
6518 }
6519 
6520 /*
6521  * Find a view based on its configuration info and attach to it.
6522  *
6523  * If 'vconfig' is NULL, attach to the default view.
6524  */
6525 static isc_result_t
6526 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6527 	  dns_view_t **viewp) {
6528 	isc_result_t result;
6529 	const char *viewname = NULL;
6530 	dns_rdataclass_t viewclass;
6531 	dns_view_t *view = NULL;
6532 
6533 	result = get_viewinfo(vconfig, &viewname, &viewclass);
6534 	if (result != ISC_R_SUCCESS) {
6535 		return (result);
6536 	}
6537 
6538 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6539 	if (result != ISC_R_SUCCESS) {
6540 		return (result);
6541 	}
6542 
6543 	*viewp = view;
6544 	return (ISC_R_SUCCESS);
6545 }
6546 
6547 /*
6548  * Create a new view and add it to the list.
6549  *
6550  * If 'vconfig' is NULL, create the default view.
6551  *
6552  * The view created is attached to '*viewp'.
6553  */
6554 static isc_result_t
6555 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6556 	    dns_view_t **viewp) {
6557 	isc_result_t result;
6558 	const char *viewname = NULL;
6559 	dns_rdataclass_t viewclass;
6560 	dns_view_t *view = NULL;
6561 
6562 	result = get_viewinfo(vconfig, &viewname, &viewclass);
6563 	if (result != ISC_R_SUCCESS) {
6564 		return (result);
6565 	}
6566 
6567 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6568 	if (result == ISC_R_SUCCESS) {
6569 		return (ISC_R_EXISTS);
6570 	}
6571 	if (result != ISC_R_NOTFOUND) {
6572 		return (result);
6573 	}
6574 	INSIST(view == NULL);
6575 
6576 	result = dns_view_create(named_g_mctx, viewclass, viewname, &view);
6577 	if (result != ISC_R_SUCCESS) {
6578 		return (result);
6579 	}
6580 
6581 	isc_nonce_buf(view->secret, sizeof(view->secret));
6582 
6583 	ISC_LIST_APPEND(*viewlist, view, link);
6584 	dns_view_attach(view, viewp);
6585 	return (ISC_R_SUCCESS);
6586 }
6587 
6588 /*
6589  * Configure or reconfigure a zone.
6590  */
6591 static isc_result_t
6592 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
6593 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
6594 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
6595 	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
6596 	       bool is_catz_member, bool modify) {
6597 	dns_view_t *pview = NULL; /* Production view */
6598 	dns_zone_t *zone = NULL;  /* New or reused zone */
6599 	dns_zone_t *raw = NULL;	  /* New or reused raw zone */
6600 	dns_zone_t *dupzone = NULL;
6601 	const cfg_obj_t *options = NULL;
6602 	const cfg_obj_t *zoptions = NULL;
6603 	const cfg_obj_t *typeobj = NULL;
6604 	const cfg_obj_t *forwarders = NULL;
6605 	const cfg_obj_t *forwardtype = NULL;
6606 	const cfg_obj_t *ixfrfromdiffs = NULL;
6607 	const cfg_obj_t *only = NULL;
6608 	const cfg_obj_t *viewobj = NULL;
6609 	isc_result_t result = ISC_R_SUCCESS;
6610 	isc_result_t tresult;
6611 	isc_buffer_t buffer;
6612 	dns_fixedname_t fixorigin;
6613 	dns_name_t *origin;
6614 	const char *zname;
6615 	dns_rdataclass_t zclass;
6616 	const char *ztypestr;
6617 	dns_rpz_num_t rpz_num;
6618 	bool zone_is_catz = false;
6619 	bool zone_maybe_inline = false;
6620 	bool inline_signing = false;
6621 	bool fullsign = false;
6622 
6623 	options = NULL;
6624 	(void)cfg_map_get(config, "options", &options);
6625 
6626 	zoptions = cfg_tuple_get(zconfig, "options");
6627 
6628 	/*
6629 	 * Get the zone origin as a dns_name_t.
6630 	 */
6631 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
6632 	isc_buffer_constinit(&buffer, zname, strlen(zname));
6633 	isc_buffer_add(&buffer, strlen(zname));
6634 	dns_fixedname_init(&fixorigin);
6635 	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
6636 				dns_rootname, 0, NULL));
6637 	origin = dns_fixedname_name(&fixorigin);
6638 
6639 	CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"),
6640 				    view->rdclass, &zclass));
6641 	if (zclass != view->rdclass) {
6642 		const char *vname = NULL;
6643 		if (vconfig != NULL) {
6644 			vname = cfg_obj_asstring(
6645 				cfg_tuple_get(vconfig, "name"));
6646 		} else {
6647 			vname = "<default view>";
6648 		}
6649 
6650 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6651 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6652 			      "zone '%s': wrong class for view '%s'", zname,
6653 			      vname);
6654 		result = ISC_R_FAILURE;
6655 		goto cleanup;
6656 	}
6657 
6658 	(void)cfg_map_get(zoptions, "in-view", &viewobj);
6659 	if (viewobj != NULL) {
6660 		const char *inview = cfg_obj_asstring(viewobj);
6661 		dns_view_t *otherview = NULL;
6662 
6663 		if (viewlist == NULL) {
6664 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6665 				    "'in-view' option is not permitted in "
6666 				    "dynamically added zones");
6667 			result = ISC_R_FAILURE;
6668 			goto cleanup;
6669 		}
6670 
6671 		result = dns_viewlist_find(viewlist, inview, view->rdclass,
6672 					   &otherview);
6673 		if (result != ISC_R_SUCCESS) {
6674 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6675 				    "view '%s' is not yet defined.", inview);
6676 			result = ISC_R_FAILURE;
6677 			goto cleanup;
6678 		}
6679 
6680 		result = dns_view_findzone(otherview, origin, &zone);
6681 		dns_view_detach(&otherview);
6682 		if (result != ISC_R_SUCCESS) {
6683 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6684 				    "zone '%s' not defined in view '%s'", zname,
6685 				    inview);
6686 			result = ISC_R_FAILURE;
6687 			goto cleanup;
6688 		}
6689 
6690 		CHECK(dns_view_addzone(view, zone));
6691 		dns_zone_detach(&zone);
6692 
6693 		/*
6694 		 * If the zone contains a 'forwarders' statement, configure
6695 		 * selective forwarding.  Note: this is not inherited from the
6696 		 * other view.
6697 		 */
6698 		forwarders = NULL;
6699 		result = cfg_map_get(zoptions, "forwarders", &forwarders);
6700 		if (result == ISC_R_SUCCESS) {
6701 			forwardtype = NULL;
6702 			(void)cfg_map_get(zoptions, "forward", &forwardtype);
6703 			CHECK(configure_forward(config, view, origin,
6704 						forwarders, forwardtype));
6705 		}
6706 		result = ISC_R_SUCCESS;
6707 		goto cleanup;
6708 	}
6709 
6710 	(void)cfg_map_get(zoptions, "type", &typeobj);
6711 	if (typeobj == NULL) {
6712 		cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6713 			    "zone '%s' 'type' not specified", zname);
6714 		result = ISC_R_FAILURE;
6715 		goto cleanup;
6716 	}
6717 	ztypestr = cfg_obj_asstring(typeobj);
6718 
6719 	/*
6720 	 * "hints zones" aren't zones.	If we've got one,
6721 	 * configure it and return.
6722 	 */
6723 	if (strcasecmp(ztypestr, "hint") == 0) {
6724 		const cfg_obj_t *fileobj = NULL;
6725 		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
6726 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6727 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6728 				      "zone '%s': 'file' not specified", zname);
6729 			result = ISC_R_FAILURE;
6730 			goto cleanup;
6731 		}
6732 		if (dns_name_equal(origin, dns_rootname)) {
6733 			const char *hintsfile = cfg_obj_asstring(fileobj);
6734 
6735 			CHECK(configure_hints(view, hintsfile));
6736 
6737 			/*
6738 			 * Hint zones may also refer to delegation only points.
6739 			 */
6740 			only = NULL;
6741 			tresult = cfg_map_get(zoptions, "delegation-only",
6742 					      &only);
6743 			if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
6744 			{
6745 				dns_view_adddelegationonly(view, origin);
6746 			}
6747 		} else {
6748 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6749 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
6750 				      "ignoring non-root hint zone '%s'",
6751 				      zname);
6752 			result = ISC_R_SUCCESS;
6753 		}
6754 		/* Skip ordinary zone processing. */
6755 		goto cleanup;
6756 	}
6757 
6758 	/*
6759 	 * "forward zones" aren't zones either.  Translate this syntax into
6760 	 * the appropriate selective forwarding configuration and return.
6761 	 */
6762 	if (strcasecmp(ztypestr, "forward") == 0) {
6763 		forwardtype = NULL;
6764 		forwarders = NULL;
6765 
6766 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6767 		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
6768 		CHECK(configure_forward(config, view, origin, forwarders,
6769 					forwardtype));
6770 
6771 		/*
6772 		 * Forward zones may also set delegation only.
6773 		 */
6774 		only = NULL;
6775 		tresult = cfg_map_get(zoptions, "delegation-only", &only);
6776 		if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) {
6777 			dns_view_adddelegationonly(view, origin);
6778 		}
6779 		goto cleanup;
6780 	}
6781 
6782 	/*
6783 	 * "delegation-only zones" aren't zones either.
6784 	 */
6785 	if (strcasecmp(ztypestr, "delegation-only") == 0) {
6786 		dns_view_adddelegationonly(view, origin);
6787 		goto cleanup;
6788 	}
6789 
6790 	/*
6791 	 * Redirect zones only require minimal configuration.
6792 	 */
6793 	if (strcasecmp(ztypestr, "redirect") == 0) {
6794 		if (view->redirect != NULL) {
6795 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6796 				    "redirect zone already exists");
6797 			result = ISC_R_EXISTS;
6798 			goto cleanup;
6799 		}
6800 		result = dns_viewlist_find(viewlist, view->name, view->rdclass,
6801 					   &pview);
6802 		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6803 			goto cleanup;
6804 		}
6805 		if (pview != NULL && pview->redirect != NULL) {
6806 			dns_zone_attach(pview->redirect, &zone);
6807 			dns_zone_setview(zone, view);
6808 		} else {
6809 			CHECK(dns_zonemgr_createzone(named_g_server->zonemgr,
6810 						     &zone));
6811 			CHECK(dns_zone_setorigin(zone, origin));
6812 			dns_zone_setview(zone, view);
6813 			CHECK(dns_zonemgr_managezone(named_g_server->zonemgr,
6814 						     zone));
6815 			dns_zone_setstats(zone, named_g_server->zonestats);
6816 		}
6817 		CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
6818 					   kasplist, zone, NULL));
6819 		dns_zone_attach(zone, &view->redirect);
6820 		goto cleanup;
6821 	}
6822 
6823 	if (!modify) {
6824 		/*
6825 		 * Check for duplicates in the new zone table.
6826 		 */
6827 		result = dns_view_findzone(view, origin, &dupzone);
6828 		if (result == ISC_R_SUCCESS) {
6829 			/*
6830 			 * We already have this zone!
6831 			 */
6832 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6833 				    "zone '%s' already exists", zname);
6834 			dns_zone_detach(&dupzone);
6835 			result = ISC_R_EXISTS;
6836 			goto cleanup;
6837 		}
6838 		INSIST(dupzone == NULL);
6839 	}
6840 
6841 	/*
6842 	 * Note whether this is a response policy zone and which one if so,
6843 	 * unless we are using RPZ service interface.  In that case, the
6844 	 * BIND zone database has nothing to do with rpz and so we don't care.
6845 	 */
6846 	for (rpz_num = 0;; ++rpz_num) {
6847 		if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
6848 		    view->rpzs->p.dnsrps_enabled)
6849 		{
6850 			rpz_num = DNS_RPZ_INVALID_NUM;
6851 			break;
6852 		}
6853 		if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
6854 		{
6855 			break;
6856 		}
6857 	}
6858 
6859 	if (!is_catz_member && view->catzs != NULL &&
6860 	    dns_catz_get_zone(view->catzs, origin) != NULL)
6861 	{
6862 		zone_is_catz = true;
6863 	}
6864 
6865 	/*
6866 	 * See if we can reuse an existing zone.  This is
6867 	 * only possible if all of these are true:
6868 	 *   - The zone's view exists
6869 	 *   - A zone with the right name exists in the view
6870 	 *   - The zone is compatible with the config
6871 	 *     options (e.g., an existing primary zone cannot
6872 	 *     be reused if the options specify a secondary zone)
6873 	 *   - The zone was not and is still not a response policy zone
6874 	 *     or the zone is a policy zone with an unchanged number
6875 	 *     and we are using the old policy zone summary data.
6876 	 */
6877 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6878 				   view->rdclass, &pview);
6879 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6880 		goto cleanup;
6881 	}
6882 	if (pview != NULL) {
6883 		result = dns_view_findzone(pview, origin, &zone);
6884 	}
6885 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6886 		goto cleanup;
6887 	}
6888 
6889 	if (zone != NULL && !named_zone_reusable(zone, zconfig)) {
6890 		dns_zone_detach(&zone);
6891 		fullsign = true;
6892 	}
6893 
6894 	if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
6895 			     (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
6896 	{
6897 		dns_zone_detach(&zone);
6898 	}
6899 
6900 	if (zone != NULL) {
6901 		/*
6902 		 * We found a reusable zone.  Make it use the
6903 		 * new view.
6904 		 */
6905 		dns_zone_setview(zone, view);
6906 	} else {
6907 		/*
6908 		 * We cannot reuse an existing zone, we have
6909 		 * to create a new one.
6910 		 */
6911 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6912 		CHECK(dns_zone_setorigin(zone, origin));
6913 		dns_zone_setview(zone, view);
6914 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6915 		dns_zone_setstats(zone, named_g_server->zonestats);
6916 	}
6917 	if (rpz_num != DNS_RPZ_INVALID_NUM) {
6918 		result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
6919 		if (result != ISC_R_SUCCESS) {
6920 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6921 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6922 				      "zone '%s': incompatible"
6923 				      " masterfile-format or database"
6924 				      " for a response policy zone",
6925 				      zname);
6926 			goto cleanup;
6927 		}
6928 	}
6929 
6930 	if (zone_is_catz) {
6931 		dns_zone_catz_enable(zone, view->catzs);
6932 	} else if (dns_zone_catz_is_enabled(zone)) {
6933 		dns_zone_catz_disable(zone);
6934 	}
6935 
6936 	/*
6937 	 * If the zone contains a 'forwarders' statement, configure
6938 	 * selective forwarding.
6939 	 */
6940 	forwarders = NULL;
6941 	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) {
6942 		forwardtype = NULL;
6943 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6944 		CHECK(configure_forward(config, view, origin, forwarders,
6945 					forwardtype));
6946 	}
6947 
6948 	/*
6949 	 * Stub and forward zones may also refer to delegation only points.
6950 	 */
6951 	only = NULL;
6952 	if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) {
6953 		if (cfg_obj_asboolean(only)) {
6954 			dns_view_adddelegationonly(view, origin);
6955 		}
6956 	}
6957 
6958 	/*
6959 	 * Mark whether the zone was originally added at runtime or not
6960 	 */
6961 	dns_zone_setadded(zone, added);
6962 
6963 	/*
6964 	 * Determine if we need to set up inline signing.
6965 	 */
6966 	zone_maybe_inline = ((strcasecmp(ztypestr, "primary") == 0 ||
6967 			      strcasecmp(ztypestr, "master") == 0 ||
6968 			      strcasecmp(ztypestr, "secondary") == 0 ||
6969 			      strcasecmp(ztypestr, "slave") == 0));
6970 
6971 	if (zone_maybe_inline) {
6972 		inline_signing = named_zone_inlinesigning(zconfig);
6973 	}
6974 	if (inline_signing) {
6975 		dns_zone_getraw(zone, &raw);
6976 		if (raw == NULL) {
6977 			CHECK(dns_zone_create(&raw, mctx));
6978 			CHECK(dns_zone_setorigin(raw, origin));
6979 			dns_zone_setview(raw, view);
6980 			dns_zone_setstats(raw, named_g_server->zonestats);
6981 			CHECK(dns_zone_link(zone, raw));
6982 		}
6983 		if (cfg_map_get(zoptions, "ixfr-from-differences",
6984 				&ixfrfromdiffs) == ISC_R_SUCCESS)
6985 		{
6986 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6987 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6988 				      "zone '%s': 'ixfr-from-differences' is "
6989 				      "ignored for inline-signed zones",
6990 				      zname);
6991 		}
6992 	}
6993 
6994 	/*
6995 	 * Configure the zone.
6996 	 */
6997 	CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
6998 				   zone, raw));
6999 
7000 	/*
7001 	 * Add the zone to its view in the new view list.
7002 	 */
7003 	if (!modify) {
7004 		CHECK(dns_view_addzone(view, zone));
7005 	}
7006 
7007 	if (zone_is_catz) {
7008 		/*
7009 		 * force catz reload if the zone is loaded;
7010 		 * if it's not it'll get reloaded on zone load
7011 		 */
7012 		dns_db_t *db = NULL;
7013 
7014 		tresult = dns_zone_getdb(zone, &db);
7015 		if (tresult == ISC_R_SUCCESS) {
7016 			dns_catz_dbupdate_callback(db, view->catzs);
7017 			dns_db_detach(&db);
7018 		}
7019 	}
7020 
7021 	/*
7022 	 * Ensure that zone keys are reloaded on reconfig
7023 	 */
7024 	if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) {
7025 		dns_zone_rekey(zone, fullsign);
7026 	}
7027 
7028 cleanup:
7029 	if (zone != NULL) {
7030 		dns_zone_detach(&zone);
7031 	}
7032 	if (raw != NULL) {
7033 		dns_zone_detach(&raw);
7034 	}
7035 	if (pview != NULL) {
7036 		dns_view_detach(&pview);
7037 	}
7038 
7039 	return (result);
7040 }
7041 
7042 /*
7043  * Configure built-in zone for storing managed-key data.
7044  */
7045 static isc_result_t
7046 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
7047 	isc_result_t result;
7048 	dns_view_t *pview = NULL;
7049 	dns_zone_t *zone = NULL;
7050 	dns_acl_t *none = NULL;
7051 	char filename[PATH_MAX];
7052 	bool defaultview;
7053 
7054 	REQUIRE(view != NULL);
7055 
7056 	/* See if we can re-use an existing keydata zone. */
7057 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
7058 				   view->rdclass, &pview);
7059 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
7060 		return (result);
7061 	}
7062 
7063 	if (pview != NULL) {
7064 		if (pview->managed_keys != NULL) {
7065 			dns_zone_attach(pview->managed_keys,
7066 					&view->managed_keys);
7067 			dns_zone_setview(pview->managed_keys, view);
7068 			dns_zone_setviewcommit(pview->managed_keys);
7069 			dns_view_detach(&pview);
7070 			dns_zone_synckeyzone(view->managed_keys);
7071 			return (ISC_R_SUCCESS);
7072 		}
7073 
7074 		dns_view_detach(&pview);
7075 	}
7076 
7077 	/* No existing keydata zone was found; create one */
7078 	CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
7079 	CHECK(dns_zone_setorigin(zone, dns_rootname));
7080 
7081 	defaultview = (strcmp(view->name, "_default") == 0);
7082 	CHECK(isc_file_sanitize(
7083 		directory, defaultview ? "managed-keys" : view->name,
7084 		defaultview ? "bind" : "mkeys", filename, sizeof(filename)));
7085 	CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text,
7086 			       &dns_master_style_default));
7087 
7088 	dns_zone_setview(zone, view);
7089 	dns_zone_settype(zone, dns_zone_key);
7090 	dns_zone_setclass(zone, view->rdclass);
7091 
7092 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
7093 
7094 	CHECK(dns_acl_none(mctx, &none));
7095 	dns_zone_setqueryacl(zone, none);
7096 	dns_zone_setqueryonacl(zone, none);
7097 	dns_acl_detach(&none);
7098 
7099 	dns_zone_setdialup(zone, dns_dialuptype_no);
7100 	dns_zone_setnotifytype(zone, dns_notifytype_no);
7101 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
7102 	dns_zone_setjournalsize(zone, 0);
7103 
7104 	dns_zone_setstats(zone, named_g_server->zonestats);
7105 	CHECK(setquerystats(zone, mctx, dns_zonestat_none));
7106 
7107 	if (view->managed_keys != NULL) {
7108 		dns_zone_detach(&view->managed_keys);
7109 	}
7110 	dns_zone_attach(zone, &view->managed_keys);
7111 
7112 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7113 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7114 		      "set up managed keys zone for view %s, file '%s'",
7115 		      view->name, filename);
7116 
7117 cleanup:
7118 	if (zone != NULL) {
7119 		dns_zone_detach(&zone);
7120 	}
7121 	if (none != NULL) {
7122 		dns_acl_detach(&none);
7123 	}
7124 
7125 	return (result);
7126 }
7127 
7128 /*
7129  * Configure a single server quota.
7130  */
7131 static void
7132 configure_server_quota(const cfg_obj_t **maps, const char *name,
7133 		       isc_quota_t *quota) {
7134 	const cfg_obj_t *obj = NULL;
7135 	isc_result_t result;
7136 
7137 	result = named_config_get(maps, name, &obj);
7138 	INSIST(result == ISC_R_SUCCESS);
7139 	isc_quota_max(quota, cfg_obj_asuint32(obj));
7140 }
7141 
7142 /*
7143  * This function is called as soon as the 'directory' statement has been
7144  * parsed.  This can be extended to support other options if necessary.
7145  */
7146 static isc_result_t
7147 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
7148 	isc_result_t result;
7149 	const char *directory;
7150 
7151 	REQUIRE(strcasecmp("directory", clausename) == 0);
7152 
7153 	UNUSED(arg);
7154 	UNUSED(clausename);
7155 
7156 	/*
7157 	 * Change directory.
7158 	 */
7159 	directory = cfg_obj_asstring(obj);
7160 
7161 	if (!isc_file_ischdiridempotent(directory)) {
7162 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
7163 			    "option 'directory' contains relative path '%s'",
7164 			    directory);
7165 	}
7166 
7167 #if 0
7168 	if (!isc_file_isdirwritable(directory)) {
7169 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7170 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7171 			      "directory '%s' is not writable", directory);
7172 		return (ISC_R_NOPERM);
7173 	}
7174 #endif
7175 
7176 	result = isc_dir_chdir(directory);
7177 	if (result != ISC_R_SUCCESS) {
7178 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7179 			    "change directory to '%s' failed: %s", directory,
7180 			    isc_result_totext(result));
7181 		return (result);
7182 	}
7183 
7184 	char cwd[PATH_MAX];
7185 	if (getcwd(cwd, sizeof(cwd)) == cwd) {
7186 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7187 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7188 			      "the working directory is now '%s'", cwd);
7189 	}
7190 
7191 	return (ISC_R_SUCCESS);
7192 }
7193 
7194 /*
7195  * This event callback is invoked to do periodic network interface
7196  * scanning.
7197  */
7198 
7199 static void
7200 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
7201 	named_server_t *server = (named_server_t *)event->ev_arg;
7202 	INSIST(task == server->task);
7203 	UNUSED(task);
7204 
7205 	isc_event_free(&event);
7206 	ns_interfacemgr_scan(server->interfacemgr, false, false);
7207 }
7208 
7209 static void
7210 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
7211 	named_server_t *server = (named_server_t *)event->ev_arg;
7212 	dns_view_t *view;
7213 
7214 	UNUSED(task);
7215 	isc_event_free(&event);
7216 	view = ISC_LIST_HEAD(server->viewlist);
7217 	while (view != NULL) {
7218 		dns_view_dialup(view);
7219 		view = ISC_LIST_NEXT(view, link);
7220 	}
7221 }
7222 
7223 typedef struct {
7224 	isc_mem_t *mctx;
7225 	isc_task_t *task;
7226 	dns_fetch_t *fetch;
7227 	dns_view_t *view;
7228 	dns_fixedname_t tatname;
7229 	dns_fixedname_t keyname;
7230 	dns_rdataset_t rdataset;
7231 	dns_rdataset_t sigrdataset;
7232 } ns_tat_t;
7233 
7234 static int
7235 cid(const void *a, const void *b) {
7236 	const uint16_t ida = *(const uint16_t *)a;
7237 	const uint16_t idb = *(const uint16_t *)b;
7238 	if (ida < idb) {
7239 		return (-1);
7240 	} else if (ida > idb) {
7241 		return (1);
7242 	} else {
7243 		return (0);
7244 	}
7245 }
7246 
7247 static void
7248 tat_done(isc_task_t *task, isc_event_t *event) {
7249 	dns_fetchevent_t *devent;
7250 	ns_tat_t *tat;
7251 
7252 	INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE);
7253 	INSIST(event->ev_arg != NULL);
7254 
7255 	UNUSED(task);
7256 
7257 	tat = event->ev_arg;
7258 	devent = (dns_fetchevent_t *)event;
7259 
7260 	/* Free resources which are not of interest */
7261 	if (devent->node != NULL) {
7262 		dns_db_detachnode(devent->db, &devent->node);
7263 	}
7264 	if (devent->db != NULL) {
7265 		dns_db_detach(&devent->db);
7266 	}
7267 	isc_event_free(&event);
7268 	dns_resolver_destroyfetch(&tat->fetch);
7269 	if (dns_rdataset_isassociated(&tat->rdataset)) {
7270 		dns_rdataset_disassociate(&tat->rdataset);
7271 	}
7272 	if (dns_rdataset_isassociated(&tat->sigrdataset)) {
7273 		dns_rdataset_disassociate(&tat->sigrdataset);
7274 	}
7275 	dns_view_detach(&tat->view);
7276 	isc_task_detach(&tat->task);
7277 	isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
7278 }
7279 
7280 struct dotat_arg {
7281 	dns_view_t *view;
7282 	isc_task_t *task;
7283 };
7284 
7285 /*%
7286  * Prepare the QNAME for the TAT query to be sent by processing the trust
7287  * anchors present at 'keynode' of 'keytable'.  Store the result in 'dst' and
7288  * the domain name which 'keynode' is associated with in 'origin'.
7289  *
7290  * A maximum of 12 key IDs can be reported in a single TAT query due to the
7291  * 63-octet length limit for any single label in a domain name.  If there are
7292  * more than 12 keys configured at 'keynode', only the first 12 will be
7293  * reported in the TAT query.
7294  */
7295 static isc_result_t
7296 get_tat_qname(dns_name_t *target, dns_name_t *keyname, dns_keynode_t *keynode) {
7297 	dns_rdataset_t dsset;
7298 	unsigned int i, n = 0;
7299 	uint16_t ids[12];
7300 	isc_textregion_t r;
7301 	char label[64];
7302 	int m;
7303 
7304 	dns_rdataset_init(&dsset);
7305 	if (dns_keynode_dsset(keynode, &dsset)) {
7306 		isc_result_t result;
7307 
7308 		for (result = dns_rdataset_first(&dsset);
7309 		     result == ISC_R_SUCCESS;
7310 		     result = dns_rdataset_next(&dsset))
7311 		{
7312 			dns_rdata_t rdata = DNS_RDATA_INIT;
7313 			dns_rdata_ds_t ds;
7314 
7315 			dns_rdata_reset(&rdata);
7316 			dns_rdataset_current(&dsset, &rdata);
7317 			result = dns_rdata_tostruct(&rdata, &ds, NULL);
7318 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
7319 			if (n < (sizeof(ids) / sizeof(ids[0]))) {
7320 				ids[n] = ds.key_tag;
7321 				n++;
7322 			}
7323 		}
7324 		dns_rdataset_disassociate(&dsset);
7325 	}
7326 
7327 	if (n == 0) {
7328 		return (DNS_R_EMPTYNAME);
7329 	}
7330 
7331 	if (n > 1) {
7332 		qsort(ids, n, sizeof(ids[0]), cid);
7333 	}
7334 
7335 	/*
7336 	 * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
7337 	 * of the keyid.
7338 	 */
7339 	label[0] = 0;
7340 	r.base = label;
7341 	r.length = sizeof(label);
7342 	m = snprintf(r.base, r.length, "_ta");
7343 	if (m < 0 || (unsigned)m > r.length) {
7344 		return (ISC_R_FAILURE);
7345 	}
7346 	isc_textregion_consume(&r, m);
7347 	for (i = 0; i < n; i++) {
7348 		m = snprintf(r.base, r.length, "-%04x", ids[i]);
7349 		if (m < 0 || (unsigned)m > r.length) {
7350 			return (ISC_R_FAILURE);
7351 		}
7352 		isc_textregion_consume(&r, m);
7353 	}
7354 
7355 	return (dns_name_fromstring2(target, label, keyname, 0, NULL));
7356 }
7357 
7358 static void
7359 tat_send(isc_task_t *task, isc_event_t *event) {
7360 	ns_tat_t *tat;
7361 	char namebuf[DNS_NAME_FORMATSIZE];
7362 	dns_fixedname_t fdomain;
7363 	dns_name_t *domain;
7364 	dns_rdataset_t nameservers;
7365 	isc_result_t result;
7366 	dns_name_t *keyname;
7367 	dns_name_t *tatname;
7368 
7369 	INSIST(event != NULL && event->ev_type == NAMED_EVENT_TATSEND);
7370 	INSIST(event->ev_arg != NULL);
7371 
7372 	UNUSED(task);
7373 
7374 	tat = event->ev_arg;
7375 
7376 	keyname = dns_fixedname_name(&tat->keyname);
7377 	tatname = dns_fixedname_name(&tat->tatname);
7378 
7379 	dns_name_format(tatname, namebuf, sizeof(namebuf));
7380 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7381 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7382 		      "%s: sending trust-anchor-telemetry query '%s/NULL'",
7383 		      tat->view->name, namebuf);
7384 
7385 	/*
7386 	 * TAT queries should be sent to the authoritative servers for a given
7387 	 * zone.  If this function is called for a keytable node corresponding
7388 	 * to a locally served zone, calling dns_resolver_createfetch() with
7389 	 * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be
7390 	 * resolved locally, without sending any TAT queries upstream.
7391 	 *
7392 	 * Work around this issue by calling dns_view_findzonecut() first.  If
7393 	 * the zone is served locally, the NS RRset for the given domain name
7394 	 * will be retrieved from local data; if it is not, the deepest zone
7395 	 * cut we have for it will be retrieved from cache.  In either case,
7396 	 * passing the results to dns_resolver_createfetch() will prevent it
7397 	 * from returning NXDOMAIN for 'tatname' while still allowing it to
7398 	 * chase down any potential delegations returned by upstream servers in
7399 	 * order to eventually find the destination host to send the TAT query
7400 	 * to.
7401 	 *
7402 	 * After the dns_view_findzonecut() call, 'domain' will hold the
7403 	 * deepest zone cut we can find for 'keyname' while 'nameservers' will
7404 	 * hold the NS RRset at that zone cut.
7405 	 */
7406 	domain = dns_fixedname_initname(&fdomain);
7407 	dns_rdataset_init(&nameservers);
7408 	result = dns_view_findzonecut(tat->view, keyname, domain, NULL, 0, 0,
7409 				      true, true, &nameservers, NULL);
7410 	if (result == ISC_R_SUCCESS) {
7411 		result = dns_resolver_createfetch(
7412 			tat->view->resolver, tatname, dns_rdatatype_null,
7413 			domain, &nameservers, NULL, NULL, 0, 0, 0, NULL,
7414 			tat->task, tat_done, tat, &tat->rdataset,
7415 			&tat->sigrdataset, &tat->fetch);
7416 	}
7417 
7418 	/*
7419 	 * 'domain' holds the dns_name_t pointer inside a dst_key_t structure.
7420 	 * dns_resolver_createfetch() creates its own copy of 'domain' if it
7421 	 * succeeds.  Thus, 'domain' is not freed here.
7422 	 *
7423 	 * Even if dns_view_findzonecut() returned something else than
7424 	 * ISC_R_SUCCESS, it still could have associated 'nameservers'.
7425 	 * dns_resolver_createfetch() creates its own copy of 'nameservers' if
7426 	 * it succeeds.  Thus, we need to check whether 'nameservers' is
7427 	 * associated and release it if it is.
7428 	 */
7429 	if (dns_rdataset_isassociated(&nameservers)) {
7430 		dns_rdataset_disassociate(&nameservers);
7431 	}
7432 
7433 	if (result != ISC_R_SUCCESS) {
7434 		dns_view_detach(&tat->view);
7435 		isc_task_detach(&tat->task);
7436 		isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
7437 	}
7438 	isc_event_free(&event);
7439 }
7440 
7441 static void
7442 dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, dns_name_t *keyname,
7443       void *arg) {
7444 	struct dotat_arg *dotat_arg = arg;
7445 	isc_result_t result;
7446 	dns_view_t *view;
7447 	isc_task_t *task;
7448 	ns_tat_t *tat;
7449 	isc_event_t *event;
7450 
7451 	REQUIRE(keytable != NULL);
7452 	REQUIRE(keynode != NULL);
7453 	REQUIRE(dotat_arg != NULL);
7454 
7455 	view = dotat_arg->view;
7456 	task = dotat_arg->task;
7457 
7458 	tat = isc_mem_get(dotat_arg->view->mctx, sizeof(*tat));
7459 
7460 	tat->fetch = NULL;
7461 	tat->mctx = NULL;
7462 	tat->task = NULL;
7463 	tat->view = NULL;
7464 	dns_rdataset_init(&tat->rdataset);
7465 	dns_rdataset_init(&tat->sigrdataset);
7466 	dns_name_copy(keyname, dns_fixedname_initname(&tat->keyname));
7467 	result = get_tat_qname(dns_fixedname_initname(&tat->tatname), keyname,
7468 			       keynode);
7469 	if (result != ISC_R_SUCCESS) {
7470 		isc_mem_put(dotat_arg->view->mctx, tat, sizeof(*tat));
7471 		return;
7472 	}
7473 	isc_mem_attach(dotat_arg->view->mctx, &tat->mctx);
7474 	isc_task_attach(task, &tat->task);
7475 	dns_view_attach(view, &tat->view);
7476 
7477 	/*
7478 	 * We don't want to be holding the keytable lock when calling
7479 	 * dns_view_findzonecut() as it creates a lock order loop so
7480 	 * call dns_view_findzonecut() in a event handler.
7481 	 *
7482 	 * zone->lock (dns_zone_setviewcommit) while holding view->lock
7483 	 * (dns_view_setviewcommit)
7484 	 *
7485 	 * keytable->lock (dns_keytable_find) while holding zone->lock
7486 	 * (zone_asyncload)
7487 	 *
7488 	 * view->lock (dns_view_findzonecut) while holding keytable->lock
7489 	 * (dns_keytable_forall)
7490 	 */
7491 	event = isc_event_allocate(tat->mctx, keytable, NAMED_EVENT_TATSEND,
7492 				   tat_send, tat, sizeof(isc_event_t));
7493 	isc_task_send(task, &event);
7494 }
7495 
7496 static void
7497 tat_timer_tick(isc_task_t *task, isc_event_t *event) {
7498 	isc_result_t result;
7499 	named_server_t *server = (named_server_t *)event->ev_arg;
7500 	struct dotat_arg arg;
7501 	dns_view_t *view;
7502 	dns_keytable_t *secroots = NULL;
7503 
7504 	isc_event_free(&event);
7505 
7506 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
7507 	     view = ISC_LIST_NEXT(view, link))
7508 	{
7509 		if (!view->trust_anchor_telemetry || !view->enablevalidation) {
7510 			continue;
7511 		}
7512 
7513 		result = dns_view_getsecroots(view, &secroots);
7514 		if (result != ISC_R_SUCCESS) {
7515 			continue;
7516 		}
7517 
7518 		arg.view = view;
7519 		arg.task = task;
7520 		(void)dns_keytable_forall(secroots, dotat, &arg);
7521 		dns_keytable_detach(&secroots);
7522 	}
7523 }
7524 
7525 static void
7526 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
7527 	static unsigned int oldrequests = 0;
7528 	unsigned int requests = atomic_load_relaxed(&ns_client_requests);
7529 
7530 	UNUSED(task);
7531 	isc_event_free(&event);
7532 
7533 	/*
7534 	 * Don't worry about wrapping as the overflow result will be right.
7535 	 */
7536 	dns_pps = (requests - oldrequests) / 1200;
7537 	oldrequests = requests;
7538 }
7539 
7540 /*
7541  * Replace the current value of '*field', a dynamically allocated
7542  * string or NULL, with a dynamically allocated copy of the
7543  * null-terminated string pointed to by 'value', or NULL.
7544  */
7545 static isc_result_t
7546 setstring(named_server_t *server, char **field, const char *value) {
7547 	char *copy;
7548 
7549 	if (value != NULL) {
7550 		copy = isc_mem_strdup(server->mctx, value);
7551 	} else {
7552 		copy = NULL;
7553 	}
7554 
7555 	if (*field != NULL) {
7556 		isc_mem_free(server->mctx, *field);
7557 	}
7558 
7559 	*field = copy;
7560 	return (ISC_R_SUCCESS);
7561 }
7562 
7563 /*
7564  * Replace the current value of '*field', a dynamically allocated
7565  * string or NULL, with another dynamically allocated string
7566  * or NULL if whether 'obj' is a string or void value, respectively.
7567  */
7568 static isc_result_t
7569 setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) {
7570 	if (cfg_obj_isvoid(obj)) {
7571 		return (setstring(server, field, NULL));
7572 	} else {
7573 		return (setstring(server, field, cfg_obj_asstring(obj)));
7574 	}
7575 }
7576 
7577 static void
7578 set_limit(const cfg_obj_t **maps, const char *configname,
7579 	  const char *description, isc_resource_t resourceid,
7580 	  isc_resourcevalue_t defaultvalue) {
7581 	const cfg_obj_t *obj = NULL;
7582 	const char *resource;
7583 	isc_resourcevalue_t value;
7584 	isc_result_t result;
7585 
7586 	if (named_config_get(maps, configname, &obj) != ISC_R_SUCCESS) {
7587 		return;
7588 	}
7589 
7590 	if (cfg_obj_isstring(obj)) {
7591 		resource = cfg_obj_asstring(obj);
7592 		if (strcasecmp(resource, "unlimited") == 0) {
7593 			value = ISC_RESOURCE_UNLIMITED;
7594 		} else {
7595 			INSIST(strcasecmp(resource, "default") == 0);
7596 			value = defaultvalue;
7597 		}
7598 	} else {
7599 		value = cfg_obj_asuint64(obj);
7600 	}
7601 
7602 	result = isc_resource_setlimit(resourceid, value);
7603 	isc_log_write(
7604 		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7605 		result == ISC_R_SUCCESS ? ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
7606 		"set maximum %s to %" PRIu64 ": %s", description, value,
7607 		isc_result_totext(result));
7608 }
7609 
7610 #define SETLIMIT(cfgvar, resource, description)                       \
7611 	set_limit(maps, cfgvar, description, isc_resource_##resource, \
7612 		  named_g_init##resource)
7613 
7614 static void
7615 set_limits(const cfg_obj_t **maps) {
7616 	SETLIMIT("stacksize", stacksize, "stack size");
7617 	SETLIMIT("datasize", datasize, "data size");
7618 	SETLIMIT("coresize", coresize, "core size");
7619 	SETLIMIT("files", openfiles, "open files");
7620 }
7621 
7622 static void
7623 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
7624 		 bool positive) {
7625 	const cfg_listelt_t *element;
7626 
7627 	for (element = cfg_list_first(ports); element != NULL;
7628 	     element = cfg_list_next(element))
7629 	{
7630 		const cfg_obj_t *obj = cfg_listelt_value(element);
7631 
7632 		if (cfg_obj_isuint32(obj)) {
7633 			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
7634 
7635 			if (positive) {
7636 				isc_portset_add(portset, port);
7637 			} else {
7638 				isc_portset_remove(portset, port);
7639 			}
7640 		} else {
7641 			const cfg_obj_t *obj_loport, *obj_hiport;
7642 			in_port_t loport, hiport;
7643 
7644 			obj_loport = cfg_tuple_get(obj, "loport");
7645 			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
7646 			obj_hiport = cfg_tuple_get(obj, "hiport");
7647 			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
7648 
7649 			if (positive) {
7650 				isc_portset_addrange(portset, loport, hiport);
7651 			} else {
7652 				isc_portset_removerange(portset, loport,
7653 							hiport);
7654 			}
7655 		}
7656 	}
7657 }
7658 
7659 static isc_result_t
7660 removed(dns_zone_t *zone, void *uap) {
7661 	if (dns_zone_getview(zone) != uap) {
7662 		return (ISC_R_SUCCESS);
7663 	}
7664 
7665 	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed",
7666 		     dns_zonetype_name(dns_zone_gettype(zone)));
7667 	return (ISC_R_SUCCESS);
7668 }
7669 
7670 static void
7671 cleanup_session_key(named_server_t *server, isc_mem_t *mctx) {
7672 	if (server->session_keyfile != NULL) {
7673 		isc_file_remove(server->session_keyfile);
7674 		isc_mem_free(mctx, server->session_keyfile);
7675 		server->session_keyfile = NULL;
7676 	}
7677 
7678 	if (server->session_keyname != NULL) {
7679 		if (dns_name_dynamic(server->session_keyname)) {
7680 			dns_name_free(server->session_keyname, mctx);
7681 		}
7682 		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
7683 		server->session_keyname = NULL;
7684 	}
7685 
7686 	if (server->sessionkey != NULL) {
7687 		dst_key_free(&server->sessionkey);
7688 	}
7689 
7690 	server->session_keyalg = DST_ALG_UNKNOWN;
7691 	server->session_keybits = 0;
7692 }
7693 
7694 static isc_result_t
7695 generate_session_key(const char *filename, const char *keynamestr,
7696 		     const dns_name_t *keyname, const char *algstr,
7697 		     unsigned int algtype, uint16_t bits, isc_mem_t *mctx,
7698 		     bool first_time, dst_key_t **keyp) {
7699 	isc_result_t result = ISC_R_SUCCESS;
7700 	dst_key_t *key = NULL;
7701 	isc_buffer_t key_txtbuffer;
7702 	isc_buffer_t key_rawbuffer;
7703 	char key_txtsecret[256];
7704 	char key_rawsecret[64];
7705 	isc_region_t key_rawregion;
7706 	FILE *fp = NULL;
7707 
7708 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7709 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7710 		      "generating session key for dynamic DNS");
7711 
7712 	/* generate key */
7713 	result = dst_key_generate(keyname, algtype, bits, 1, 0,
7714 				  DNS_KEYPROTO_ANY, dns_rdataclass_in, mctx,
7715 				  &key, NULL);
7716 	if (result != ISC_R_SUCCESS) {
7717 		return (result);
7718 	}
7719 
7720 	/*
7721 	 * Dump the key to the buffer for later use.
7722 	 */
7723 	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
7724 	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
7725 
7726 	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
7727 	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
7728 	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
7729 
7730 	/* Dump the key to the key file. */
7731 	fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time);
7732 	if (fp == NULL) {
7733 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7734 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7735 			      "could not create %s", filename);
7736 		result = ISC_R_NOPERM;
7737 		goto cleanup;
7738 	}
7739 
7740 	fprintf(fp,
7741 		"key \"%s\" {\n"
7742 		"\talgorithm %s;\n"
7743 		"\tsecret \"%.*s\";\n};\n",
7744 		keynamestr, algstr, (int)isc_buffer_usedlength(&key_txtbuffer),
7745 		(char *)isc_buffer_base(&key_txtbuffer));
7746 
7747 	CHECK(isc_stdio_flush(fp));
7748 	result = isc_stdio_close(fp);
7749 	fp = NULL;
7750 	if (result != ISC_R_SUCCESS) {
7751 		goto cleanup;
7752 	}
7753 
7754 	*keyp = key;
7755 	return (ISC_R_SUCCESS);
7756 
7757 cleanup:
7758 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7759 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7760 		      "failed to generate session key "
7761 		      "for dynamic DNS: %s",
7762 		      isc_result_totext(result));
7763 	if (fp != NULL) {
7764 		(void)isc_stdio_close(fp);
7765 		(void)isc_file_remove(filename);
7766 	}
7767 	if (key != NULL) {
7768 		dst_key_free(&key);
7769 	}
7770 
7771 	return (result);
7772 }
7773 
7774 static isc_result_t
7775 configure_session_key(const cfg_obj_t **maps, named_server_t *server,
7776 		      isc_mem_t *mctx, bool first_time) {
7777 	const char *keyfile, *keynamestr, *algstr;
7778 	unsigned int algtype;
7779 	dns_fixedname_t fname;
7780 	dns_name_t *keyname;
7781 	const dns_name_t *algname;
7782 	isc_buffer_t buffer;
7783 	uint16_t bits;
7784 	const cfg_obj_t *obj;
7785 	bool need_deleteold = false;
7786 	bool need_createnew = false;
7787 	isc_result_t result;
7788 
7789 	obj = NULL;
7790 	result = named_config_get(maps, "session-keyfile", &obj);
7791 	if (result == ISC_R_SUCCESS) {
7792 		if (cfg_obj_isvoid(obj)) {
7793 			keyfile = NULL; /* disable it */
7794 		} else {
7795 			keyfile = cfg_obj_asstring(obj);
7796 		}
7797 	} else {
7798 		keyfile = named_g_defaultsessionkeyfile;
7799 	}
7800 
7801 	obj = NULL;
7802 	result = named_config_get(maps, "session-keyname", &obj);
7803 	INSIST(result == ISC_R_SUCCESS);
7804 	keynamestr = cfg_obj_asstring(obj);
7805 	isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
7806 	isc_buffer_add(&buffer, strlen(keynamestr));
7807 	keyname = dns_fixedname_initname(&fname);
7808 	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
7809 	if (result != ISC_R_SUCCESS) {
7810 		return (result);
7811 	}
7812 
7813 	obj = NULL;
7814 	result = named_config_get(maps, "session-keyalg", &obj);
7815 	INSIST(result == ISC_R_SUCCESS);
7816 	algstr = cfg_obj_asstring(obj);
7817 	algname = NULL;
7818 	result = named_config_getkeyalgorithm2(algstr, &algname, &algtype,
7819 					       &bits);
7820 	if (result != ISC_R_SUCCESS) {
7821 		const char *s = " (keeping current key)";
7822 
7823 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7824 			    "session-keyalg: "
7825 			    "unsupported or unknown algorithm '%s'%s",
7826 			    algstr, server->session_keyfile != NULL ? s : "");
7827 		return (result);
7828 	}
7829 
7830 	/* See if we need to (re)generate a new key. */
7831 	if (keyfile == NULL) {
7832 		if (server->session_keyfile != NULL) {
7833 			need_deleteold = true;
7834 		}
7835 	} else if (server->session_keyfile == NULL) {
7836 		need_createnew = true;
7837 	} else if (strcmp(keyfile, server->session_keyfile) != 0 ||
7838 		   !dns_name_equal(server->session_keyname, keyname) ||
7839 		   server->session_keyalg != algtype ||
7840 		   server->session_keybits != bits)
7841 	{
7842 		need_deleteold = true;
7843 		need_createnew = true;
7844 	}
7845 
7846 	if (need_deleteold) {
7847 		INSIST(server->session_keyfile != NULL);
7848 		INSIST(server->session_keyname != NULL);
7849 		INSIST(server->sessionkey != NULL);
7850 
7851 		cleanup_session_key(server, mctx);
7852 	}
7853 
7854 	if (need_createnew) {
7855 		INSIST(server->sessionkey == NULL);
7856 		INSIST(server->session_keyfile == NULL);
7857 		INSIST(server->session_keyname == NULL);
7858 		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
7859 		INSIST(server->session_keybits == 0);
7860 
7861 		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
7862 		dns_name_init(server->session_keyname, NULL);
7863 		dns_name_dup(keyname, mctx, server->session_keyname);
7864 
7865 		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
7866 
7867 		server->session_keyalg = algtype;
7868 		server->session_keybits = bits;
7869 
7870 		CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
7871 					   algtype, bits, mctx, first_time,
7872 					   &server->sessionkey));
7873 	}
7874 
7875 	return (result);
7876 
7877 cleanup:
7878 	cleanup_session_key(server, mctx);
7879 	return (result);
7880 }
7881 
7882 #ifndef HAVE_LMDB
7883 static isc_result_t
7884 count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7885 	isc_result_t result;
7886 
7887 	/* The new zone file may not exist. That is OK. */
7888 	if (!isc_file_exists(view->new_zone_file)) {
7889 		*num_zonesp = 0;
7890 		return (ISC_R_SUCCESS);
7891 	}
7892 
7893 	/*
7894 	 * In the case of NZF files, we also parse the configuration in
7895 	 * the file at this stage.
7896 	 *
7897 	 * This may be called in multiple views, so we reset
7898 	 * the parser each time.
7899 	 */
7900 	cfg_parser_reset(named_g_addparser);
7901 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
7902 				&cfg_type_addzoneconf, &nzcfg->nzf_config);
7903 	if (result == ISC_R_SUCCESS) {
7904 		int num_zones;
7905 
7906 		num_zones = count_zones(nzcfg->nzf_config);
7907 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7908 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7909 			      "NZF file '%s' contains %d zones",
7910 			      view->new_zone_file, num_zones);
7911 		if (num_zonesp != NULL) {
7912 			*num_zonesp = num_zones;
7913 		}
7914 	} else {
7915 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7916 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7917 			      "Error parsing NZF file '%s': %s",
7918 			      view->new_zone_file, isc_result_totext(result));
7919 	}
7920 
7921 	return (result);
7922 }
7923 
7924 #else /* HAVE_LMDB */
7925 
7926 static isc_result_t
7927 count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7928 	isc_result_t result;
7929 	int n;
7930 
7931 	UNUSED(nzcfg);
7932 
7933 	REQUIRE(num_zonesp != NULL);
7934 
7935 	LOCK(&view->new_zone_lock);
7936 
7937 	CHECK(migrate_nzf(view));
7938 
7939 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7940 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7941 		      "loading NZD zone count from '%s' "
7942 		      "for view '%s'",
7943 		      view->new_zone_db, view->name);
7944 
7945 	CHECK(nzd_count(view, &n));
7946 
7947 	*num_zonesp = n;
7948 
7949 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7950 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7951 		      "NZD database '%s' contains %d zones", view->new_zone_db,
7952 		      n);
7953 
7954 cleanup:
7955 	if (result != ISC_R_SUCCESS) {
7956 		*num_zonesp = 0;
7957 	}
7958 
7959 	UNLOCK(&view->new_zone_lock);
7960 
7961 	return (ISC_R_SUCCESS);
7962 }
7963 
7964 #endif /* HAVE_LMDB */
7965 
7966 static isc_result_t
7967 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7968 	       cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx,
7969 	       int *num_zones) {
7970 	isc_result_t result = ISC_R_SUCCESS;
7971 	bool allow = false;
7972 	ns_cfgctx_t *nzcfg = NULL;
7973 	const cfg_obj_t *maps[4];
7974 	const cfg_obj_t *options = NULL, *voptions = NULL;
7975 	const cfg_obj_t *nz = NULL;
7976 	const cfg_obj_t *nzdir = NULL;
7977 	const char *dir = NULL;
7978 	const cfg_obj_t *obj = NULL;
7979 	int i = 0;
7980 	uint64_t mapsize = 0ULL;
7981 
7982 	REQUIRE(config != NULL);
7983 
7984 	if (vconfig != NULL) {
7985 		voptions = cfg_tuple_get(vconfig, "options");
7986 	}
7987 	if (voptions != NULL) {
7988 		maps[i++] = voptions;
7989 	}
7990 	result = cfg_map_get(config, "options", &options);
7991 	if (result == ISC_R_SUCCESS) {
7992 		maps[i++] = options;
7993 	}
7994 	maps[i++] = named_g_defaults;
7995 	maps[i] = NULL;
7996 
7997 	result = named_config_get(maps, "allow-new-zones", &nz);
7998 	if (result == ISC_R_SUCCESS) {
7999 		allow = cfg_obj_asboolean(nz);
8000 	}
8001 	result = named_config_get(maps, "new-zones-directory", &nzdir);
8002 	if (result == ISC_R_SUCCESS) {
8003 		dir = cfg_obj_asstring(nzdir);
8004 		result = isc_file_isdirectory(dir);
8005 		if (result != ISC_R_SUCCESS) {
8006 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
8007 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8008 				      "invalid new-zones-directory %s: %s", dir,
8009 				      isc_result_totext(result));
8010 			return (result);
8011 		}
8012 		if (!isc_file_isdirwritable(dir)) {
8013 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8014 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8015 				      "new-zones-directory '%s' "
8016 				      "is not writable",
8017 				      dir);
8018 			return (ISC_R_NOPERM);
8019 		}
8020 
8021 		dns_view_setnewzonedir(view, dir);
8022 	}
8023 
8024 #ifdef HAVE_LMDB
8025 	result = named_config_get(maps, "lmdb-mapsize", &obj);
8026 	if (result == ISC_R_SUCCESS && obj != NULL) {
8027 		mapsize = cfg_obj_asuint64(obj);
8028 		if (mapsize < (1ULL << 20)) { /* 1 megabyte */
8029 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
8030 				    "'lmdb-mapsize "
8031 				    "%" PRId64 "' "
8032 				    "is too small",
8033 				    mapsize);
8034 			return (ISC_R_FAILURE);
8035 		} else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
8036 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
8037 				    "'lmdb-mapsize "
8038 				    "%" PRId64 "' "
8039 				    "is too large",
8040 				    mapsize);
8041 			return (ISC_R_FAILURE);
8042 		}
8043 	}
8044 #else  /* ifdef HAVE_LMDB */
8045 	UNUSED(obj);
8046 #endif /* HAVE_LMDB */
8047 
8048 	/*
8049 	 * A non-empty catalog-zones statement implies allow-new-zones
8050 	 */
8051 	if (!allow) {
8052 		const cfg_obj_t *cz = NULL;
8053 		result = named_config_get(maps, "catalog-zones", &cz);
8054 		if (result == ISC_R_SUCCESS) {
8055 			const cfg_listelt_t *e =
8056 				cfg_list_first(cfg_tuple_get(cz, "zone list"));
8057 			if (e != NULL) {
8058 				allow = true;
8059 			}
8060 		}
8061 	}
8062 
8063 	if (!allow) {
8064 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
8065 		if (num_zones != NULL) {
8066 			*num_zones = 0;
8067 		}
8068 		return (ISC_R_SUCCESS);
8069 	}
8070 
8071 	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
8072 
8073 	/*
8074 	 * We attach the parser that was used for config as well
8075 	 * as the one that will be used for added zones, to avoid
8076 	 * a shutdown race later.
8077 	 */
8078 	memset(nzcfg, 0, sizeof(*nzcfg));
8079 	cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
8080 	cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
8081 	isc_mem_attach(view->mctx, &nzcfg->mctx);
8082 	cfg_aclconfctx_attach(actx, &nzcfg->actx);
8083 
8084 	result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy,
8085 				      mapsize);
8086 	if (result != ISC_R_SUCCESS) {
8087 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
8088 		return (result);
8089 	}
8090 
8091 	cfg_obj_attach(config, &nzcfg->config);
8092 	if (vconfig != NULL) {
8093 		cfg_obj_attach(vconfig, &nzcfg->vconfig);
8094 	}
8095 
8096 	result = count_newzones(view, nzcfg, num_zones);
8097 	return (result);
8098 }
8099 
8100 static void
8101 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
8102 			     dns_view_t *view) {
8103 	const char *zname;
8104 	dns_fixedname_t fixorigin;
8105 	dns_name_t *origin;
8106 	isc_result_t result2;
8107 	dns_view_t *pview = NULL;
8108 	dns_zone_t *zone = NULL;
8109 
8110 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
8111 	origin = dns_fixedname_initname(&fixorigin);
8112 
8113 	result2 = dns_name_fromstring(origin, zname, 0, NULL);
8114 	if (result2 != ISC_R_SUCCESS) {
8115 		return;
8116 	}
8117 
8118 	result2 = dns_viewlist_find(&named_g_server->viewlist, view->name,
8119 				    view->rdclass, &pview);
8120 	if (result2 != ISC_R_SUCCESS) {
8121 		return;
8122 	}
8123 
8124 	result2 = dns_view_findzone(pview, origin, &zone);
8125 	if (result2 != ISC_R_SUCCESS) {
8126 		dns_view_detach(&pview);
8127 		return;
8128 	}
8129 
8130 	if (result == ISC_R_SUCCESS) {
8131 		dns_zone_setviewcommit(zone);
8132 	} else {
8133 		dns_zone_setviewrevert(zone);
8134 	}
8135 
8136 	dns_zone_detach(&zone);
8137 	dns_view_detach(&pview);
8138 }
8139 
8140 #ifndef HAVE_LMDB
8141 
8142 static isc_result_t
8143 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
8144 		   isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
8145 	isc_result_t result;
8146 	ns_cfgctx_t *nzctx;
8147 	const cfg_obj_t *zonelist;
8148 	const cfg_listelt_t *element;
8149 
8150 	nzctx = view->new_zone_config;
8151 	if (nzctx == NULL || nzctx->nzf_config == NULL) {
8152 		return (ISC_R_SUCCESS);
8153 	}
8154 
8155 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8156 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8157 		      "loading additional zones for view '%s'", view->name);
8158 
8159 	zonelist = NULL;
8160 	cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
8161 
8162 	for (element = cfg_list_first(zonelist); element != NULL;
8163 	     element = cfg_list_next(element))
8164 	{
8165 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
8166 		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
8167 				     &named_g_server->viewlist,
8168 				     &named_g_server->kasplist, actx, true,
8169 				     false, false, false));
8170 	}
8171 
8172 	result = ISC_R_SUCCESS;
8173 
8174 cleanup:
8175 	for (element = cfg_list_first(zonelist); element != NULL;
8176 	     element = cfg_list_next(element))
8177 	{
8178 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
8179 		configure_zone_setviewcommit(result, zconfig, view);
8180 	}
8181 
8182 	return (result);
8183 }
8184 
8185 #else /* HAVE_LMDB */
8186 
8187 static isc_result_t
8188 data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text,
8189 	    cfg_obj_t **zoneconfig) {
8190 	isc_result_t result;
8191 	const char *zone_name;
8192 	size_t zone_name_len;
8193 	const char *zone_config;
8194 	size_t zone_config_len;
8195 	cfg_obj_t *zoneconf = NULL;
8196 	char bufname[DNS_NAME_FORMATSIZE];
8197 
8198 	REQUIRE(view != NULL);
8199 	REQUIRE(key != NULL);
8200 	REQUIRE(data != NULL);
8201 	REQUIRE(text != NULL);
8202 	REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
8203 
8204 	if (*text == NULL) {
8205 		isc_buffer_allocate(view->mctx, text, 256);
8206 	} else {
8207 		isc_buffer_clear(*text);
8208 	}
8209 
8210 	zone_name = (const char *)key->mv_data;
8211 	zone_name_len = key->mv_size;
8212 	INSIST(zone_name != NULL && zone_name_len > 0);
8213 
8214 	zone_config = (const char *)data->mv_data;
8215 	zone_config_len = data->mv_size;
8216 	INSIST(zone_config != NULL && zone_config_len > 0);
8217 
8218 	/* zone zonename { config; }; */
8219 	result = isc_buffer_reserve(text, 6 + zone_name_len + 2 +
8220 						  zone_config_len + 2);
8221 	if (result != ISC_R_SUCCESS) {
8222 		goto cleanup;
8223 	}
8224 
8225 	CHECK(putstr(text, "zone \""));
8226 	CHECK(putmem(text, (const void *)zone_name, zone_name_len));
8227 	CHECK(putstr(text, "\" "));
8228 	CHECK(putmem(text, (const void *)zone_config, zone_config_len));
8229 	CHECK(putstr(text, ";\n"));
8230 
8231 	snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len,
8232 		 zone_name);
8233 
8234 	cfg_parser_reset(named_g_addparser);
8235 	result = cfg_parse_buffer(named_g_addparser, *text, bufname, 0,
8236 				  &cfg_type_addzoneconf, 0, &zoneconf);
8237 	if (result != ISC_R_SUCCESS) {
8238 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8239 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8240 			      "parsing config for zone '%.*s' in "
8241 			      "NZD database '%s' failed",
8242 			      (int)zone_name_len, zone_name, view->new_zone_db);
8243 		goto cleanup;
8244 	}
8245 
8246 	*zoneconfig = zoneconf;
8247 	zoneconf = NULL;
8248 	result = ISC_R_SUCCESS;
8249 
8250 cleanup:
8251 	if (zoneconf != NULL) {
8252 		cfg_obj_destroy(named_g_addparser, &zoneconf);
8253 	}
8254 
8255 	return (result);
8256 }
8257 
8258 /*%
8259  * Prototype for a callback which can be used with for_all_newzone_cfgs().
8260  */
8261 typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
8262 					 cfg_obj_t *config, cfg_obj_t *vconfig,
8263 					 isc_mem_t *mctx, dns_view_t *view,
8264 					 cfg_aclconfctx_t *actx);
8265 
8266 /*%
8267  * For each zone found in a NZD opened by the caller, create an object
8268  * representing its configuration and invoke "callback" with the created
8269  * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all
8270  * these are non-global variables required to invoke configure_zone()).
8271  * Immediately interrupt processing if an error is encountered while
8272  * transforming NZD data into a zone configuration object or if "callback"
8273  * returns an error.
8274  *
8275  * Caller must hold 'view->new_zone_lock'.
8276  */
8277 static isc_result_t
8278 for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
8279 		     cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8280 		     cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi) {
8281 	const cfg_obj_t *zconfig, *zlist;
8282 	isc_result_t result = ISC_R_SUCCESS;
8283 	cfg_obj_t *zconfigobj = NULL;
8284 	isc_buffer_t *text = NULL;
8285 	MDB_cursor *cursor = NULL;
8286 	MDB_val data, key;
8287 	int status;
8288 
8289 	status = mdb_cursor_open(txn, dbi, &cursor);
8290 	if (status != MDB_SUCCESS) {
8291 		return (ISC_R_FAILURE);
8292 	}
8293 
8294 	for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
8295 	     status == MDB_SUCCESS;
8296 	     status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
8297 	{
8298 		/*
8299 		 * Create a configuration object from data fetched from NZD.
8300 		 */
8301 		result = data_to_cfg(view, &key, &data, &text, &zconfigobj);
8302 		if (result != ISC_R_SUCCESS) {
8303 			break;
8304 		}
8305 
8306 		/*
8307 		 * Extract zone configuration from configuration object.
8308 		 */
8309 		zlist = NULL;
8310 		result = cfg_map_get(zconfigobj, "zone", &zlist);
8311 		if (result != ISC_R_SUCCESS) {
8312 			break;
8313 		} else if (!cfg_obj_islist(zlist)) {
8314 			result = ISC_R_FAILURE;
8315 			break;
8316 		}
8317 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
8318 
8319 		/*
8320 		 * Invoke callback.
8321 		 */
8322 		result = callback(zconfig, config, vconfig, mctx, view, actx);
8323 		if (result != ISC_R_SUCCESS) {
8324 			break;
8325 		}
8326 
8327 		/*
8328 		 * Destroy the configuration object created in this iteration.
8329 		 */
8330 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8331 	}
8332 
8333 	if (text != NULL) {
8334 		isc_buffer_free(&text);
8335 	}
8336 	if (zconfigobj != NULL) {
8337 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8338 	}
8339 	mdb_cursor_close(cursor);
8340 
8341 	return (result);
8342 }
8343 
8344 /*%
8345  * Attempt to configure a zone found in NZD and return the result.
8346  */
8347 static isc_result_t
8348 configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
8349 		  cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8350 		  cfg_aclconfctx_t *actx) {
8351 	return (configure_zone(
8352 		config, zconfig, vconfig, mctx, view, &named_g_server->viewlist,
8353 		&named_g_server->kasplist, actx, true, false, false, false));
8354 }
8355 
8356 /*%
8357  * Revert new view assignment for a zone found in NZD.
8358  */
8359 static isc_result_t
8360 configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config,
8361 			 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8362 			 cfg_aclconfctx_t *actx) {
8363 	UNUSED(config);
8364 	UNUSED(vconfig);
8365 	UNUSED(mctx);
8366 	UNUSED(actx);
8367 
8368 	configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view);
8369 
8370 	return (ISC_R_SUCCESS);
8371 }
8372 
8373 static isc_result_t
8374 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
8375 		   isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
8376 	isc_result_t result;
8377 	MDB_txn *txn = NULL;
8378 	MDB_dbi dbi;
8379 
8380 	if (view->new_zone_config == NULL) {
8381 		return (ISC_R_SUCCESS);
8382 	}
8383 
8384 	LOCK(&view->new_zone_lock);
8385 
8386 	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
8387 	if (result != ISC_R_SUCCESS) {
8388 		UNLOCK(&view->new_zone_lock);
8389 		return (ISC_R_SUCCESS);
8390 	}
8391 
8392 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8393 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8394 		      "loading NZD configs from '%s' "
8395 		      "for view '%s'",
8396 		      view->new_zone_db, view->name);
8397 
8398 	result = for_all_newzone_cfgs(configure_newzone, config, vconfig, mctx,
8399 				      view, actx, txn, dbi);
8400 	if (result != ISC_R_SUCCESS) {
8401 		/*
8402 		 * An error was encountered while attempting to configure zones
8403 		 * found in NZD.  As this error may have been caused by a
8404 		 * configure_zone() failure, try restoring a sane configuration
8405 		 * by reattaching all zones found in NZD to the old view.  If
8406 		 * this also fails, too bad, there is nothing more we can do in
8407 		 * terms of trying to make things right.
8408 		 */
8409 		(void)for_all_newzone_cfgs(configure_newzone_revert, config,
8410 					   vconfig, mctx, view, actx, txn, dbi);
8411 	}
8412 
8413 	(void)nzd_close(&txn, false);
8414 
8415 	UNLOCK(&view->new_zone_lock);
8416 
8417 	return (result);
8418 }
8419 
8420 static isc_result_t
8421 get_newzone_config(dns_view_t *view, const char *zonename,
8422 		   cfg_obj_t **zoneconfig) {
8423 	isc_result_t result;
8424 	int status;
8425 	cfg_obj_t *zoneconf = NULL;
8426 	isc_buffer_t *text = NULL;
8427 	MDB_txn *txn = NULL;
8428 	MDB_dbi dbi;
8429 	MDB_val key, data;
8430 	char zname[DNS_NAME_FORMATSIZE];
8431 	dns_fixedname_t fname;
8432 	dns_name_t *name;
8433 	isc_buffer_t b;
8434 
8435 	INSIST(zoneconfig != NULL && *zoneconfig == NULL);
8436 
8437 	LOCK(&view->new_zone_lock);
8438 
8439 	CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
8440 
8441 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8442 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8443 		      "loading NZD config from '%s' "
8444 		      "for zone '%s'",
8445 		      view->new_zone_db, zonename);
8446 
8447 	/* Normalize zone name */
8448 	isc_buffer_constinit(&b, zonename, strlen(zonename));
8449 	isc_buffer_add(&b, strlen(zonename));
8450 	name = dns_fixedname_initname(&fname);
8451 	CHECK(dns_name_fromtext(name, &b, dns_rootname, DNS_NAME_DOWNCASE,
8452 				NULL));
8453 	dns_name_format(name, zname, sizeof(zname));
8454 
8455 	key.mv_data = zname;
8456 	key.mv_size = strlen(zname);
8457 
8458 	status = mdb_get(txn, dbi, &key, &data);
8459 	if (status != MDB_SUCCESS) {
8460 		CHECK(ISC_R_FAILURE);
8461 	}
8462 
8463 	CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
8464 
8465 	*zoneconfig = zoneconf;
8466 	zoneconf = NULL;
8467 	result = ISC_R_SUCCESS;
8468 
8469 cleanup:
8470 	(void)nzd_close(&txn, false);
8471 
8472 	UNLOCK(&view->new_zone_lock);
8473 
8474 	if (zoneconf != NULL) {
8475 		cfg_obj_destroy(named_g_addparser, &zoneconf);
8476 	}
8477 	if (text != NULL) {
8478 		isc_buffer_free(&text);
8479 	}
8480 
8481 	return (result);
8482 }
8483 
8484 #endif /* HAVE_LMDB */
8485 
8486 static int
8487 count_zones(const cfg_obj_t *conf) {
8488 	const cfg_obj_t *zonelist = NULL;
8489 	const cfg_listelt_t *element;
8490 	int n = 0;
8491 
8492 	REQUIRE(conf != NULL);
8493 
8494 	cfg_map_get(conf, "zone", &zonelist);
8495 	for (element = cfg_list_first(zonelist); element != NULL;
8496 	     element = cfg_list_next(element))
8497 	{
8498 		n++;
8499 	}
8500 
8501 	return (n);
8502 }
8503 
8504 static isc_result_t
8505 check_lockfile(named_server_t *server, const cfg_obj_t *config,
8506 	       bool first_time) {
8507 	isc_result_t result;
8508 	const char *filename = NULL;
8509 	const cfg_obj_t *maps[3];
8510 	const cfg_obj_t *options;
8511 	const cfg_obj_t *obj;
8512 	int i;
8513 
8514 	i = 0;
8515 	options = NULL;
8516 	result = cfg_map_get(config, "options", &options);
8517 	if (result == ISC_R_SUCCESS) {
8518 		maps[i++] = options;
8519 	}
8520 	maps[i++] = named_g_defaults;
8521 	maps[i] = NULL;
8522 
8523 	obj = NULL;
8524 	(void)named_config_get(maps, "lock-file", &obj);
8525 
8526 	if (!first_time) {
8527 		if (obj != NULL && cfg_obj_isstring(obj) &&
8528 		    server->lockfile != NULL && !named_g_forcelock &&
8529 		    strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
8530 		{
8531 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8532 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8533 				      "changing 'lock-file' "
8534 				      "has no effect until the "
8535 				      "server is restarted");
8536 		}
8537 
8538 		return (ISC_R_SUCCESS);
8539 	}
8540 
8541 	if (obj != NULL) {
8542 		if (named_g_forcelock) {
8543 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8544 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8545 				      "'lock-file' has no effect "
8546 				      "because the server was run with -X");
8547 			if (named_g_defaultlockfile != NULL) {
8548 				server->lockfile = isc_mem_strdup(
8549 					server->mctx, named_g_defaultlockfile);
8550 			}
8551 		} else if (cfg_obj_isvoid(obj)) {
8552 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8553 				      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
8554 				      "skipping lock-file check");
8555 		} else if (cfg_obj_isstring(obj)) {
8556 			filename = cfg_obj_asstring(obj);
8557 			server->lockfile = isc_mem_strdup(server->mctx,
8558 							  filename);
8559 		}
8560 	} else if (named_g_forcelock && named_g_defaultlockfile != NULL) {
8561 		server->lockfile = isc_mem_strdup(server->mctx,
8562 						  named_g_defaultlockfile);
8563 	}
8564 
8565 	if (server->lockfile == NULL) {
8566 		return (ISC_R_SUCCESS);
8567 	}
8568 
8569 	if (named_os_issingleton(server->lockfile)) {
8570 		return (ISC_R_SUCCESS);
8571 	}
8572 
8573 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8574 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8575 		      "could not lock %s; another named "
8576 		      "process may be running",
8577 		      server->lockfile);
8578 	return (ISC_R_FAILURE);
8579 }
8580 
8581 static isc_result_t
8582 load_configuration(const char *filename, named_server_t *server,
8583 		   bool first_time) {
8584 	cfg_obj_t *config = NULL, *bindkeys = NULL;
8585 	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
8586 	const cfg_listelt_t *element;
8587 	const cfg_obj_t *builtin_views;
8588 	const cfg_obj_t *maps[3];
8589 	const cfg_obj_t *obj;
8590 	const cfg_obj_t *options;
8591 	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
8592 	const cfg_obj_t *kasps;
8593 	dns_kasp_t *kasp = NULL;
8594 	dns_kasp_t *kasp_next = NULL;
8595 	dns_kasp_t *default_kasp = NULL;
8596 	dns_kasplist_t tmpkasplist, kasplist;
8597 	const cfg_obj_t *views;
8598 	dns_view_t *view = NULL;
8599 	dns_view_t *view_next = NULL;
8600 	dns_viewlist_t tmpviewlist;
8601 	dns_viewlist_t viewlist, builtin_viewlist;
8602 	in_port_t listen_port, udpport_low, udpport_high;
8603 	int i, backlog;
8604 	int num_zones = 0;
8605 	bool exclusive = false;
8606 	isc_interval_t interval;
8607 	isc_logconfig_t *logc = NULL;
8608 	isc_portset_t *v4portset = NULL;
8609 	isc_portset_t *v6portset = NULL;
8610 	isc_result_t result, tresult;
8611 	uint32_t heartbeat_interval;
8612 	uint32_t interface_interval;
8613 	uint32_t udpsize;
8614 	uint32_t transfer_message_size;
8615 	uint32_t recv_tcp_buffer_size;
8616 	uint32_t send_tcp_buffer_size;
8617 	uint32_t recv_udp_buffer_size;
8618 	uint32_t send_udp_buffer_size;
8619 	named_cache_t *nsc;
8620 	named_cachelist_t cachelist, tmpcachelist;
8621 	ns_altsecret_t *altsecret;
8622 	ns_altsecretlist_t altsecrets, tmpaltsecrets;
8623 	uint32_t softquota = 0;
8624 	uint32_t max;
8625 	uint64_t initial, idle, keepalive, advertised;
8626 	bool loadbalancesockets;
8627 	dns_aclenv_t *env =
8628 		ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
8629 
8630 	ISC_LIST_INIT(kasplist);
8631 	ISC_LIST_INIT(viewlist);
8632 	ISC_LIST_INIT(builtin_viewlist);
8633 	ISC_LIST_INIT(cachelist);
8634 	ISC_LIST_INIT(altsecrets);
8635 
8636 	/* Create the ACL configuration context */
8637 	if (named_g_aclconfctx != NULL) {
8638 		cfg_aclconfctx_detach(&named_g_aclconfctx);
8639 	}
8640 	CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx));
8641 
8642 	/*
8643 	 * Shut down all dyndb instances.
8644 	 */
8645 	dns_dyndb_cleanup(false);
8646 
8647 	/*
8648 	 * Parse the global default pseudo-config file.
8649 	 */
8650 	if (first_time) {
8651 		result = named_config_parsedefaults(named_g_parser,
8652 						    &named_g_config);
8653 		if (result != ISC_R_SUCCESS) {
8654 			named_main_earlyfatal("unable to load "
8655 					      "internal defaults: %s",
8656 					      isc_result_totext(result));
8657 		}
8658 		RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
8659 					  &named_g_defaults) == ISC_R_SUCCESS);
8660 	}
8661 
8662 	/*
8663 	 * Log the current working directory.
8664 	 */
8665 	if (first_time) {
8666 		char cwd[PATH_MAX];
8667 		if (getcwd(cwd, sizeof(cwd)) == cwd) {
8668 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8669 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8670 				      "the initial working directory is '%s'",
8671 				      cwd);
8672 		}
8673 	}
8674 
8675 	/*
8676 	 * Parse the configuration file using the new config code.
8677 	 */
8678 	config = NULL;
8679 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8680 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8681 		      "loading configuration from '%s'", filename);
8682 	CHECK(cfg_parser_create(named_g_mctx, named_g_lctx, &conf_parser));
8683 	cfg_parser_setcallback(conf_parser, directory_callback, NULL);
8684 	result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf,
8685 				&config);
8686 
8687 	CHECK(result);
8688 
8689 	/*
8690 	 * Check the validity of the configuration.
8691 	 *
8692 	 * (Ignore plugin parameters for now; they will be
8693 	 * checked later when the modules are actually loaded and
8694 	 * registered.)
8695 	 */
8696 	CHECK(bind9_check_namedconf(config, false, false, named_g_lctx,
8697 				    named_g_mctx));
8698 
8699 	/* Let's recreate the TLS context cache */
8700 	if (server->tlsctx_server_cache != NULL) {
8701 		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
8702 	}
8703 
8704 	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_server_cache);
8705 
8706 	if (server->tlsctx_client_cache != NULL) {
8707 		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
8708 	}
8709 
8710 	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_client_cache);
8711 
8712 	dns_zonemgr_set_tlsctx_cache(server->zonemgr,
8713 				     server->tlsctx_client_cache);
8714 
8715 	/*
8716 	 * Fill in the maps array, used for resolving defaults.
8717 	 */
8718 	i = 0;
8719 	options = NULL;
8720 	result = cfg_map_get(config, "options", &options);
8721 	if (result == ISC_R_SUCCESS) {
8722 		maps[i++] = options;
8723 	}
8724 	maps[i++] = named_g_defaults;
8725 	maps[i] = NULL;
8726 
8727 #if HAVE_LIBNGHTTP2
8728 	obj = NULL;
8729 	result = named_config_get(maps, "http-port", &obj);
8730 	INSIST(result == ISC_R_SUCCESS);
8731 	named_g_httpport = (in_port_t)cfg_obj_asuint32(obj);
8732 
8733 	obj = NULL;
8734 	result = named_config_get(maps, "https-port", &obj);
8735 	INSIST(result == ISC_R_SUCCESS);
8736 	named_g_httpsport = (in_port_t)cfg_obj_asuint32(obj);
8737 
8738 	obj = NULL;
8739 	result = named_config_get(maps, "http-listener-clients", &obj);
8740 	INSIST(result == ISC_R_SUCCESS);
8741 	named_g_http_listener_clients = cfg_obj_asuint32(obj);
8742 
8743 	obj = NULL;
8744 	result = named_config_get(maps, "http-streams-per-connection", &obj);
8745 	INSIST(result == ISC_R_SUCCESS);
8746 	named_g_http_streams_per_conn = cfg_obj_asuint32(obj);
8747 #endif
8748 
8749 	/*
8750 	 * If bind.keys exists, load it.  If "dnssec-validation auto"
8751 	 * is turned on, the root key found there will be used as a
8752 	 * default trust anchor.
8753 	 */
8754 	obj = NULL;
8755 	result = named_config_get(maps, "bindkeys-file", &obj);
8756 	INSIST(result == ISC_R_SUCCESS);
8757 	CHECKM(setstring(server, &server->bindkeysfile, cfg_obj_asstring(obj)),
8758 	       "strdup");
8759 	INSIST(server->bindkeysfile != NULL);
8760 
8761 	if (access(server->bindkeysfile, R_OK) == 0) {
8762 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8763 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8764 			      "reading built-in trust anchors "
8765 			      "from file '%s'",
8766 			      server->bindkeysfile);
8767 
8768 		CHECK(cfg_parser_create(named_g_mctx, named_g_lctx,
8769 					&bindkeys_parser));
8770 
8771 		result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
8772 					&cfg_type_bindkeys, &bindkeys);
8773 		if (result != ISC_R_SUCCESS) {
8774 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8775 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8776 				      "unable to parse '%s' error '%s'; using "
8777 				      "built-in keys instead",
8778 				      server->bindkeysfile,
8779 				      isc_result_totext(result));
8780 		}
8781 	} else {
8782 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8783 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8784 			      "unable to open '%s'; using built-in keys "
8785 			      "instead",
8786 			      server->bindkeysfile);
8787 	}
8788 
8789 	/* Ensure exclusive access to configuration data. */
8790 	if (!exclusive) {
8791 		result = isc_task_beginexclusive(server->task);
8792 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
8793 		exclusive = true;
8794 	}
8795 
8796 	/*
8797 	 * Set process limits, which (usually) needs to be done as root.
8798 	 */
8799 	set_limits(maps);
8800 
8801 	/*
8802 	 * Check the process lockfile.
8803 	 */
8804 	CHECK(check_lockfile(server, config, first_time));
8805 
8806 #if defined(HAVE_GEOIP2)
8807 	/*
8808 	 * Release any previously opened GeoIP2 databases.
8809 	 */
8810 	named_geoip_unload();
8811 
8812 	/*
8813 	 * Initialize GeoIP databases from the configured location.
8814 	 * This should happen before configuring any ACLs, so that we
8815 	 * know what databases are available and can reject any GeoIP
8816 	 * ACLs that can't work.
8817 	 */
8818 	obj = NULL;
8819 	result = named_config_get(maps, "geoip-directory", &obj);
8820 	INSIST(result == ISC_R_SUCCESS);
8821 	if (cfg_obj_isstring(obj)) {
8822 		char *dir;
8823 		DE_CONST(cfg_obj_asstring(obj), dir);
8824 		named_geoip_load(dir);
8825 	}
8826 	named_g_aclconfctx->geoip = named_g_geoip;
8827 #endif /* HAVE_GEOIP2 */
8828 
8829 	/*
8830 	 * Configure various server options.
8831 	 */
8832 	configure_server_quota(maps, "transfers-out",
8833 			       &server->sctx->xfroutquota);
8834 	configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
8835 	configure_server_quota(maps, "recursive-clients",
8836 			       &server->sctx->recursionquota);
8837 	configure_server_quota(maps, "update-quota", &server->sctx->updquota);
8838 
8839 	max = isc_quota_getmax(&server->sctx->recursionquota);
8840 	if (max > 1000) {
8841 		unsigned margin = ISC_MAX(100, named_g_cpus + 1);
8842 		if (margin + 100 > max) {
8843 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8844 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8845 				      "'recursive-clients %d' too low when "
8846 				      "running with %d worker threads",
8847 				      max, named_g_cpus);
8848 			CHECK(ISC_R_RANGE);
8849 		}
8850 		softquota = max - margin;
8851 	} else {
8852 		softquota = (max * 90) / 100;
8853 	}
8854 
8855 	isc_quota_soft(&server->sctx->recursionquota, softquota);
8856 
8857 	/*
8858 	 * Set "blackhole". Only legal at options level; there is
8859 	 * no default.
8860 	 */
8861 	CHECK(configure_view_acl(NULL, config, NULL, "blackhole", NULL,
8862 				 named_g_aclconfctx, named_g_mctx,
8863 				 &server->sctx->blackholeacl));
8864 	if (server->sctx->blackholeacl != NULL) {
8865 		dns_dispatchmgr_setblackhole(named_g_dispatchmgr,
8866 					     server->sctx->blackholeacl);
8867 	}
8868 
8869 	/*
8870 	 * Set "keep-response-order". Only legal at options or
8871 	 * global defaults level.
8872 	 */
8873 	CHECK(configure_view_acl(NULL, config, named_g_config,
8874 				 "keep-response-order", NULL,
8875 				 named_g_aclconfctx, named_g_mctx,
8876 				 &server->sctx->keepresporder));
8877 
8878 	obj = NULL;
8879 	result = named_config_get(maps, "match-mapped-addresses", &obj);
8880 	INSIST(result == ISC_R_SUCCESS);
8881 	env->match_mapped = cfg_obj_asboolean(obj);
8882 
8883 	CHECKM(named_statschannels_configure(named_g_server, config,
8884 					     named_g_aclconfctx),
8885 	       "configuring statistics server(s)");
8886 
8887 	/*
8888 	 * Configure the network manager
8889 	 */
8890 	obj = NULL;
8891 	result = named_config_get(maps, "tcp-initial-timeout", &obj);
8892 	INSIST(result == ISC_R_SUCCESS);
8893 	initial = cfg_obj_asuint32(obj) * 100;
8894 	if (initial > MAX_INITIAL_TIMEOUT) {
8895 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8896 			    "tcp-initial-timeout value is out of range: "
8897 			    "lowering to %" PRIu32,
8898 			    MAX_INITIAL_TIMEOUT / 100);
8899 		initial = MAX_INITIAL_TIMEOUT;
8900 	} else if (initial < MIN_INITIAL_TIMEOUT) {
8901 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8902 			    "tcp-initial-timeout value is out of range: "
8903 			    "raising to %" PRIu32,
8904 			    MIN_INITIAL_TIMEOUT / 100);
8905 		initial = MIN_INITIAL_TIMEOUT;
8906 	}
8907 
8908 	obj = NULL;
8909 	result = named_config_get(maps, "tcp-idle-timeout", &obj);
8910 	INSIST(result == ISC_R_SUCCESS);
8911 	idle = cfg_obj_asuint32(obj) * 100;
8912 	if (idle > MAX_IDLE_TIMEOUT) {
8913 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8914 			    "tcp-idle-timeout value is out of range: "
8915 			    "lowering to %" PRIu32,
8916 			    MAX_IDLE_TIMEOUT / 100);
8917 		idle = MAX_IDLE_TIMEOUT;
8918 	} else if (idle < MIN_IDLE_TIMEOUT) {
8919 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8920 			    "tcp-idle-timeout value is out of range: "
8921 			    "raising to %" PRIu32,
8922 			    MIN_IDLE_TIMEOUT / 100);
8923 		idle = MIN_IDLE_TIMEOUT;
8924 	}
8925 
8926 	obj = NULL;
8927 	result = named_config_get(maps, "tcp-keepalive-timeout", &obj);
8928 	INSIST(result == ISC_R_SUCCESS);
8929 	keepalive = cfg_obj_asuint32(obj) * 100;
8930 	if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
8931 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8932 			    "tcp-keepalive-timeout value is out of range: "
8933 			    "lowering to %" PRIu32,
8934 			    MAX_KEEPALIVE_TIMEOUT / 100);
8935 		keepalive = MAX_KEEPALIVE_TIMEOUT;
8936 	} else if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
8937 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8938 			    "tcp-keepalive-timeout value is out of range: "
8939 			    "raising to %" PRIu32,
8940 			    MIN_KEEPALIVE_TIMEOUT / 100);
8941 		keepalive = MIN_KEEPALIVE_TIMEOUT;
8942 	}
8943 
8944 	obj = NULL;
8945 	result = named_config_get(maps, "tcp-advertised-timeout", &obj);
8946 	INSIST(result == ISC_R_SUCCESS);
8947 	advertised = cfg_obj_asuint32(obj) * 100;
8948 	if (advertised > MAX_ADVERTISED_TIMEOUT) {
8949 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8950 			    "tcp-advertized-timeout value is out of range: "
8951 			    "lowering to %" PRIu32,
8952 			    MAX_ADVERTISED_TIMEOUT / 100);
8953 		advertised = MAX_ADVERTISED_TIMEOUT;
8954 	}
8955 
8956 	isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
8957 			   advertised);
8958 
8959 #define CAP_IF_NOT_ZERO(v, min, max) \
8960 	if (v > 0 && v < min) {      \
8961 		v = min;             \
8962 	} else if (v > max) {        \
8963 		v = max;             \
8964 	}
8965 
8966 	/* Set the kernel send and receive buffer sizes */
8967 	obj = NULL;
8968 	result = named_config_get(maps, "tcp-receive-buffer", &obj);
8969 	INSIST(result == ISC_R_SUCCESS);
8970 	recv_tcp_buffer_size = cfg_obj_asuint32(obj);
8971 	CAP_IF_NOT_ZERO(recv_tcp_buffer_size, 4096, INT32_MAX);
8972 
8973 	obj = NULL;
8974 	result = named_config_get(maps, "tcp-send-buffer", &obj);
8975 	INSIST(result == ISC_R_SUCCESS);
8976 	send_tcp_buffer_size = cfg_obj_asuint32(obj);
8977 	CAP_IF_NOT_ZERO(send_tcp_buffer_size, 4096, INT32_MAX);
8978 
8979 	obj = NULL;
8980 	result = named_config_get(maps, "udp-receive-buffer", &obj);
8981 	INSIST(result == ISC_R_SUCCESS);
8982 	recv_udp_buffer_size = cfg_obj_asuint32(obj);
8983 	CAP_IF_NOT_ZERO(recv_udp_buffer_size, 4096, INT32_MAX);
8984 
8985 	obj = NULL;
8986 	result = named_config_get(maps, "udp-send-buffer", &obj);
8987 	INSIST(result == ISC_R_SUCCESS);
8988 	send_udp_buffer_size = cfg_obj_asuint32(obj);
8989 	CAP_IF_NOT_ZERO(send_udp_buffer_size, 4096, INT32_MAX);
8990 
8991 	isc_nm_setnetbuffers(named_g_netmgr, recv_tcp_buffer_size,
8992 			     send_tcp_buffer_size, recv_udp_buffer_size,
8993 			     send_udp_buffer_size);
8994 
8995 #undef CAP_IF_NOT_ZERO
8996 
8997 	/*
8998 	 * Configure sets of UDP query source ports.
8999 	 */
9000 	CHECKM(isc_portset_create(named_g_mctx, &v4portset), "creating UDP "
9001 							     "port set");
9002 	CHECKM(isc_portset_create(named_g_mctx, &v6portset), "creating UDP "
9003 							     "port set");
9004 
9005 	usev4ports = NULL;
9006 	usev6ports = NULL;
9007 	avoidv4ports = NULL;
9008 	avoidv6ports = NULL;
9009 
9010 	(void)named_config_get(maps, "use-v4-udp-ports", &usev4ports);
9011 	if (usev4ports != NULL) {
9012 		portset_fromconf(v4portset, usev4ports, true);
9013 	} else {
9014 		CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
9015 					       &udpport_high),
9016 		       "get the default UDP/IPv4 port range");
9017 		if (udpport_low == udpport_high) {
9018 			isc_portset_add(v4portset, udpport_low);
9019 		} else {
9020 			isc_portset_addrange(v4portset, udpport_low,
9021 					     udpport_high);
9022 		}
9023 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) {
9024 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9025 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9026 				      "using default UDP/IPv4 port range: "
9027 				      "[%d, %d]",
9028 				      udpport_low, udpport_high);
9029 		}
9030 	}
9031 	(void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
9032 	if (avoidv4ports != NULL) {
9033 		portset_fromconf(v4portset, avoidv4ports, false);
9034 	}
9035 
9036 	(void)named_config_get(maps, "use-v6-udp-ports", &usev6ports);
9037 	if (usev6ports != NULL) {
9038 		portset_fromconf(v6portset, usev6ports, true);
9039 	} else {
9040 		CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
9041 					       &udpport_high),
9042 		       "get the default UDP/IPv6 port range");
9043 		if (udpport_low == udpport_high) {
9044 			isc_portset_add(v6portset, udpport_low);
9045 		} else {
9046 			isc_portset_addrange(v6portset, udpport_low,
9047 					     udpport_high);
9048 		}
9049 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) {
9050 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9051 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9052 				      "using default UDP/IPv6 port range: "
9053 				      "[%d, %d]",
9054 				      udpport_low, udpport_high);
9055 		}
9056 	}
9057 	(void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
9058 	if (avoidv6ports != NULL) {
9059 		portset_fromconf(v6portset, avoidv6ports, false);
9060 	}
9061 
9062 	dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset,
9063 				      v6portset);
9064 
9065 	/*
9066 	 * Set the EDNS UDP size when we don't match a view.
9067 	 */
9068 	obj = NULL;
9069 	result = named_config_get(maps, "edns-udp-size", &obj);
9070 	INSIST(result == ISC_R_SUCCESS);
9071 	udpsize = cfg_obj_asuint32(obj);
9072 	if (udpsize < 512) {
9073 		udpsize = 512;
9074 	}
9075 	if (udpsize > 4096) {
9076 		udpsize = 4096;
9077 	}
9078 	server->sctx->udpsize = (uint16_t)udpsize;
9079 
9080 	/* Set the transfer message size for TCP */
9081 	obj = NULL;
9082 	result = named_config_get(maps, "transfer-message-size", &obj);
9083 	INSIST(result == ISC_R_SUCCESS);
9084 	transfer_message_size = cfg_obj_asuint32(obj);
9085 	if (transfer_message_size < 512) {
9086 		transfer_message_size = 512;
9087 	} else if (transfer_message_size > 65535) {
9088 		transfer_message_size = 65535;
9089 	}
9090 	server->sctx->transfer_tcp_message_size =
9091 		(uint16_t)transfer_message_size;
9092 
9093 	/*
9094 	 * Configure the zone manager.
9095 	 */
9096 	obj = NULL;
9097 	result = named_config_get(maps, "transfers-in", &obj);
9098 	INSIST(result == ISC_R_SUCCESS);
9099 	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
9100 
9101 	obj = NULL;
9102 	result = named_config_get(maps, "transfers-per-ns", &obj);
9103 	INSIST(result == ISC_R_SUCCESS);
9104 	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
9105 
9106 	obj = NULL;
9107 	result = named_config_get(maps, "notify-rate", &obj);
9108 	INSIST(result == ISC_R_SUCCESS);
9109 	dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
9110 
9111 	obj = NULL;
9112 	result = named_config_get(maps, "startup-notify-rate", &obj);
9113 	INSIST(result == ISC_R_SUCCESS);
9114 	dns_zonemgr_setstartupnotifyrate(server->zonemgr,
9115 					 cfg_obj_asuint32(obj));
9116 
9117 	obj = NULL;
9118 	result = named_config_get(maps, "serial-query-rate", &obj);
9119 	INSIST(result == ISC_R_SUCCESS);
9120 	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
9121 
9122 	/*
9123 	 * Determine which port to use for listening for incoming connections.
9124 	 */
9125 	if (named_g_port != 0) {
9126 		listen_port = named_g_port;
9127 	} else {
9128 		CHECKM(named_config_getport(config, "port", &listen_port),
9129 		       "port");
9130 	}
9131 
9132 	/*
9133 	 * Find the listen queue depth.
9134 	 */
9135 	obj = NULL;
9136 	result = named_config_get(maps, "tcp-listen-queue", &obj);
9137 	INSIST(result == ISC_R_SUCCESS);
9138 	backlog = cfg_obj_asuint32(obj);
9139 	if ((backlog > 0) && (backlog < 10)) {
9140 		backlog = 10;
9141 	}
9142 	ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
9143 
9144 	obj = NULL;
9145 	result = named_config_get(maps, "reuseport", &obj);
9146 	INSIST(result == ISC_R_SUCCESS);
9147 	loadbalancesockets = cfg_obj_asboolean(obj);
9148 #if HAVE_SO_REUSEPORT_LB
9149 	if (first_time) {
9150 		isc_nm_setloadbalancesockets(named_g_netmgr,
9151 					     cfg_obj_asboolean(obj));
9152 	} else if (loadbalancesockets !=
9153 		   isc_nm_getloadbalancesockets(named_g_netmgr))
9154 	{
9155 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
9156 			    "changing reuseport value requires server restart");
9157 	}
9158 #else
9159 	if (loadbalancesockets) {
9160 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
9161 			    "reuseport has no effect on this system");
9162 	}
9163 #endif
9164 
9165 	/*
9166 	 * Configure the interface manager according to the "listen-on"
9167 	 * statement.
9168 	 */
9169 	{
9170 		const cfg_obj_t *clistenon = NULL;
9171 		ns_listenlist_t *listenon = NULL;
9172 
9173 		clistenon = NULL;
9174 		/*
9175 		 * Even though listen-on is present in the default
9176 		 * configuration, this way is easier.
9177 		 */
9178 		if (options != NULL) {
9179 			(void)cfg_map_get(options, "listen-on", &clistenon);
9180 		}
9181 		if (clistenon != NULL) {
9182 			CHECK(listenlist_fromconfig(
9183 				clistenon, config, named_g_aclconfctx,
9184 				named_g_mctx, AF_INET,
9185 				server->tlsctx_server_cache, &listenon));
9186 		} else {
9187 			/*
9188 			 * Not specified, use default.
9189 			 */
9190 			CHECK(ns_listenlist_default(named_g_mctx, listen_port,
9191 						    true, AF_INET, &listenon));
9192 		}
9193 		if (listenon != NULL) {
9194 			ns_interfacemgr_setlistenon4(server->interfacemgr,
9195 						     listenon);
9196 			ns_listenlist_detach(&listenon);
9197 		}
9198 	}
9199 	/*
9200 	 * Ditto for IPv6.
9201 	 */
9202 	{
9203 		const cfg_obj_t *clistenon = NULL;
9204 		ns_listenlist_t *listenon = NULL;
9205 
9206 		if (options != NULL) {
9207 			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
9208 		}
9209 		if (clistenon != NULL) {
9210 			CHECK(listenlist_fromconfig(
9211 				clistenon, config, named_g_aclconfctx,
9212 				named_g_mctx, AF_INET6,
9213 				server->tlsctx_server_cache, &listenon));
9214 		} else {
9215 			/*
9216 			 * Not specified, use default.
9217 			 */
9218 			CHECK(ns_listenlist_default(named_g_mctx, listen_port,
9219 						    true, AF_INET6, &listenon));
9220 		}
9221 		if (listenon != NULL) {
9222 			ns_interfacemgr_setlistenon6(server->interfacemgr,
9223 						     listenon);
9224 			ns_listenlist_detach(&listenon);
9225 		}
9226 	}
9227 
9228 	/*
9229 	 * Rescan the interface list to pick up changes in the
9230 	 * listen-on option.  It's important that we do this before we try
9231 	 * to configure the query source, since the dispatcher we use might
9232 	 * be shared with an interface.
9233 	 */
9234 	result = ns_interfacemgr_scan(server->interfacemgr, true, true);
9235 
9236 	/*
9237 	 * Check that named is able to TCP listen on at least one
9238 	 * interface. Otherwise, another named process could be running
9239 	 * and we should fail.
9240 	 */
9241 	if (first_time && (result == ISC_R_ADDRINUSE)) {
9242 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9243 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9244 			      "unable to listen on any configured interfaces");
9245 		result = ISC_R_FAILURE;
9246 		goto cleanup;
9247 	}
9248 
9249 	/*
9250 	 * Arrange for further interface scanning to occur periodically
9251 	 * as specified by the "interface-interval" option.
9252 	 */
9253 	obj = NULL;
9254 	result = named_config_get(maps, "interface-interval", &obj);
9255 	INSIST(result == ISC_R_SUCCESS);
9256 	interface_interval = cfg_obj_asduration(obj);
9257 	if (interface_interval == 0) {
9258 		CHECK(isc_timer_reset(server->interface_timer,
9259 				      isc_timertype_inactive, NULL, NULL,
9260 				      true));
9261 	} else if (server->interface_interval != interface_interval) {
9262 		isc_interval_set(&interval, interface_interval, 0);
9263 		CHECK(isc_timer_reset(server->interface_timer,
9264 				      isc_timertype_ticker, NULL, &interval,
9265 				      false));
9266 	}
9267 	server->interface_interval = interface_interval;
9268 
9269 	/*
9270 	 * Enable automatic interface scans.
9271 	 */
9272 	obj = NULL;
9273 	result = named_config_get(maps, "automatic-interface-scan", &obj);
9274 	INSIST(result == ISC_R_SUCCESS);
9275 	server->sctx->interface_auto = cfg_obj_asboolean(obj);
9276 
9277 	/*
9278 	 * Configure the dialup heartbeat timer.
9279 	 */
9280 	obj = NULL;
9281 	result = named_config_get(maps, "heartbeat-interval", &obj);
9282 	INSIST(result == ISC_R_SUCCESS);
9283 	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
9284 	if (heartbeat_interval == 0) {
9285 		CHECK(isc_timer_reset(server->heartbeat_timer,
9286 				      isc_timertype_inactive, NULL, NULL,
9287 				      true));
9288 	} else if (server->heartbeat_interval != heartbeat_interval) {
9289 		isc_interval_set(&interval, heartbeat_interval, 0);
9290 		CHECK(isc_timer_reset(server->heartbeat_timer,
9291 				      isc_timertype_ticker, NULL, &interval,
9292 				      false));
9293 	}
9294 	server->heartbeat_interval = heartbeat_interval;
9295 
9296 	isc_interval_set(&interval, 1200, 0);
9297 	CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
9298 			      &interval, false));
9299 
9300 	isc_interval_set(&interval, named_g_tat_interval, 0);
9301 	CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker, NULL,
9302 			      &interval, false));
9303 
9304 	/*
9305 	 * Write the PID file.
9306 	 */
9307 	obj = NULL;
9308 	if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) {
9309 		if (cfg_obj_isvoid(obj)) {
9310 			named_os_writepidfile(NULL, first_time);
9311 		} else {
9312 			named_os_writepidfile(cfg_obj_asstring(obj),
9313 					      first_time);
9314 		}
9315 	} else {
9316 		named_os_writepidfile(named_g_defaultpidfile, first_time);
9317 	}
9318 
9319 	/*
9320 	 * Configure the server-wide session key.  This must be done before
9321 	 * configure views because zone configuration may need to know
9322 	 * session-keyname.
9323 	 *
9324 	 * Failure of session key generation isn't fatal at this time; if it
9325 	 * turns out that a session key is really needed but doesn't exist,
9326 	 * we'll treat it as a fatal error then.
9327 	 */
9328 	(void)configure_session_key(maps, server, named_g_mctx, first_time);
9329 
9330 	/*
9331 	 * Create the built-in kasp policies ("default", "insecure").
9332 	 */
9333 	kasps = NULL;
9334 	(void)cfg_map_get(named_g_config, "dnssec-policy", &kasps);
9335 	for (element = cfg_list_first(kasps); element != NULL;
9336 	     element = cfg_list_next(element))
9337 	{
9338 		cfg_obj_t *kconfig = cfg_listelt_value(element);
9339 
9340 		kasp = NULL;
9341 		CHECK(cfg_kasp_fromconfig(kconfig, default_kasp, named_g_mctx,
9342 					  named_g_lctx, &kasplist, &kasp));
9343 		INSIST(kasp != NULL);
9344 		dns_kasp_freeze(kasp);
9345 
9346 		/* Insist that the first built-in policy is the default one. */
9347 		if (default_kasp == NULL) {
9348 			INSIST(strcmp(dns_kasp_getname(kasp), "default") == 0);
9349 			dns_kasp_attach(kasp, &default_kasp);
9350 		}
9351 
9352 		dns_kasp_detach(&kasp);
9353 	}
9354 	INSIST(default_kasp != NULL);
9355 
9356 	/*
9357 	 * Create the DNSSEC key and signing policies (KASP).
9358 	 */
9359 	kasps = NULL;
9360 	(void)cfg_map_get(config, "dnssec-policy", &kasps);
9361 	for (element = cfg_list_first(kasps); element != NULL;
9362 	     element = cfg_list_next(element))
9363 	{
9364 		cfg_obj_t *kconfig = cfg_listelt_value(element);
9365 		kasp = NULL;
9366 		CHECK(cfg_kasp_fromconfig(kconfig, default_kasp, named_g_mctx,
9367 					  named_g_lctx, &kasplist, &kasp));
9368 		INSIST(kasp != NULL);
9369 		dns_kasp_freeze(kasp);
9370 		dns_kasp_detach(&kasp);
9371 	}
9372 
9373 	dns_kasp_detach(&default_kasp);
9374 	tmpkasplist = server->kasplist;
9375 	server->kasplist = kasplist;
9376 	kasplist = tmpkasplist;
9377 
9378 	/*
9379 	 * Configure the views.
9380 	 */
9381 	views = NULL;
9382 	(void)cfg_map_get(config, "view", &views);
9383 
9384 	/*
9385 	 * Create the views and count all the configured zones in
9386 	 * order to correctly size the zone manager's task table.
9387 	 * (We only count zones for configured views; the built-in
9388 	 * "bind" view can be ignored as it only adds a negligible
9389 	 * number of zones.)
9390 	 *
9391 	 * If we're allowing new zones, we need to be able to find the
9392 	 * new zone file and count those as well.  So we setup the new
9393 	 * zone configuration context, but otherwise view configuration
9394 	 * waits until after the zone manager's task list has been sized.
9395 	 */
9396 	for (element = cfg_list_first(views); element != NULL;
9397 	     element = cfg_list_next(element))
9398 	{
9399 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9400 		const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
9401 		int nzf_num_zones;
9402 
9403 		view = NULL;
9404 
9405 		CHECK(create_view(vconfig, &viewlist, &view));
9406 		INSIST(view != NULL);
9407 
9408 		num_zones += count_zones(voptions);
9409 
9410 		CHECK(setup_newzones(view, config, vconfig, conf_parser,
9411 				     named_g_aclconfctx, &nzf_num_zones));
9412 		num_zones += nzf_num_zones;
9413 
9414 		dns_view_detach(&view);
9415 	}
9416 
9417 	/*
9418 	 * If there were no explicit views then we do the default
9419 	 * view here.
9420 	 */
9421 	if (views == NULL) {
9422 		int nzf_num_zones;
9423 
9424 		CHECK(create_view(NULL, &viewlist, &view));
9425 		INSIST(view != NULL);
9426 
9427 		num_zones = count_zones(config);
9428 
9429 		CHECK(setup_newzones(view, config, NULL, conf_parser,
9430 				     named_g_aclconfctx, &nzf_num_zones));
9431 		num_zones += nzf_num_zones;
9432 
9433 		dns_view_detach(&view);
9434 	}
9435 
9436 	/*
9437 	 * Zones have been counted; set the zone manager task pool size.
9438 	 */
9439 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9440 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9441 		      "sizing zone task pool based on %d zones", num_zones);
9442 	CHECK(dns_zonemgr_setsize(named_g_server->zonemgr, num_zones));
9443 
9444 	/*
9445 	 * Configure and freeze all explicit views.  Explicit
9446 	 * views that have zones were already created at parsing
9447 	 * time, but views with no zones must be created here.
9448 	 */
9449 	for (element = cfg_list_first(views); element != NULL;
9450 	     element = cfg_list_next(element))
9451 	{
9452 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9453 
9454 		view = NULL;
9455 		CHECK(find_view(vconfig, &viewlist, &view));
9456 		CHECK(configure_view(view, &viewlist, config, vconfig,
9457 				     &cachelist, &server->kasplist, bindkeys,
9458 				     named_g_mctx, named_g_aclconfctx, true));
9459 		dns_view_freeze(view);
9460 		dns_view_detach(&view);
9461 	}
9462 
9463 	/*
9464 	 * Make sure we have a default view if and only if there
9465 	 * were no explicit views.
9466 	 */
9467 	if (views == NULL) {
9468 		view = NULL;
9469 		CHECK(find_view(NULL, &viewlist, &view));
9470 		CHECK(configure_view(view, &viewlist, config, NULL, &cachelist,
9471 				     &server->kasplist, bindkeys, named_g_mctx,
9472 				     named_g_aclconfctx, true));
9473 		dns_view_freeze(view);
9474 		dns_view_detach(&view);
9475 	}
9476 
9477 	/*
9478 	 * Create (or recreate) the built-in views.
9479 	 */
9480 	builtin_views = NULL;
9481 	RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) ==
9482 		      ISC_R_SUCCESS);
9483 	for (element = cfg_list_first(builtin_views); element != NULL;
9484 	     element = cfg_list_next(element))
9485 	{
9486 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9487 
9488 		CHECK(create_view(vconfig, &builtin_viewlist, &view));
9489 		CHECK(configure_view(view, &viewlist, config, vconfig,
9490 				     &cachelist, &server->kasplist, bindkeys,
9491 				     named_g_mctx, named_g_aclconfctx, false));
9492 		dns_view_freeze(view);
9493 		dns_view_detach(&view);
9494 		view = NULL;
9495 	}
9496 
9497 	/* Now combine the two viewlists into one */
9498 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9499 
9500 	/*
9501 	 * Commit any dns_zone_setview() calls on all zones in the new
9502 	 * view.
9503 	 */
9504 	for (view = ISC_LIST_HEAD(viewlist); view != NULL;
9505 	     view = ISC_LIST_NEXT(view, link))
9506 	{
9507 		dns_view_setviewcommit(view);
9508 	}
9509 
9510 	/* Swap our new view list with the production one. */
9511 	tmpviewlist = server->viewlist;
9512 	server->viewlist = viewlist;
9513 	viewlist = tmpviewlist;
9514 
9515 	/* Make the view list available to each of the views */
9516 	view = ISC_LIST_HEAD(server->viewlist);
9517 	while (view != NULL) {
9518 		view->viewlist = &server->viewlist;
9519 		view = ISC_LIST_NEXT(view, link);
9520 	}
9521 
9522 	/* Swap our new cache list with the production one. */
9523 	tmpcachelist = server->cachelist;
9524 	server->cachelist = cachelist;
9525 	cachelist = tmpcachelist;
9526 
9527 	/* Load the TKEY information from the configuration. */
9528 	if (options != NULL) {
9529 		dns_tkeyctx_t *t = NULL;
9530 		CHECKM(named_tkeyctx_fromconfig(options, named_g_mctx, &t),
9531 		       "configuring TKEY");
9532 		if (server->sctx->tkeyctx != NULL) {
9533 			dns_tkeyctx_destroy(&server->sctx->tkeyctx);
9534 		}
9535 		server->sctx->tkeyctx = t;
9536 	}
9537 
9538 	/*
9539 	 * Bind the control port(s).
9540 	 */
9541 	CHECKM(named_controls_configure(named_g_server->controls, config,
9542 					named_g_aclconfctx),
9543 	       "binding control channel(s)");
9544 
9545 #ifdef HAVE_LMDB
9546 	/*
9547 	 * If we're using LMDB, we may have created newzones databases
9548 	 * as root, making it impossible to reopen them later after
9549 	 * switching to a new userid. We close them now, and reopen
9550 	 * after relinquishing privileges them.
9551 	 */
9552 	if (first_time) {
9553 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9554 		     view = ISC_LIST_NEXT(view, link))
9555 		{
9556 			nzd_env_close(view);
9557 		}
9558 	}
9559 #endif /* HAVE_LMDB */
9560 
9561 	/*
9562 	 * Relinquish root privileges.
9563 	 */
9564 	if (first_time) {
9565 		named_os_changeuser();
9566 	}
9567 
9568 #if 0
9569 	/*
9570 	 * Check that the working directory is writable.
9571 	 */
9572 	if (!isc_file_isdirwritable(".")) {
9573 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9574 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9575 			      "the working directory is not writable");
9576 		result = ISC_R_NOPERM;
9577 		goto cleanup;
9578 	}
9579 #endif
9580 
9581 #ifdef HAVE_LMDB
9582 	/*
9583 	 * Reopen NZD databases.
9584 	 */
9585 	if (first_time) {
9586 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9587 		     view = ISC_LIST_NEXT(view, link))
9588 		{
9589 			nzd_env_reopen(view);
9590 		}
9591 	}
9592 #endif /* HAVE_LMDB */
9593 
9594 	/*
9595 	 * Configure the logging system.
9596 	 *
9597 	 * Do this after changing UID to make sure that any log
9598 	 * files specified in named.conf get created by the
9599 	 * unprivileged user, not root.
9600 	 */
9601 	if (named_g_logstderr) {
9602 		const cfg_obj_t *logobj = NULL;
9603 
9604 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9605 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9606 			      "not using config file logging "
9607 			      "statement for logging due to "
9608 			      "-g option");
9609 
9610 		(void)cfg_map_get(config, "logging", &logobj);
9611 		if (logobj != NULL) {
9612 			result = named_logconfig(NULL, logobj);
9613 			if (result != ISC_R_SUCCESS) {
9614 				isc_log_write(
9615 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9616 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9617 					"checking logging configuration "
9618 					"failed: %s",
9619 					isc_result_totext(result));
9620 				goto cleanup;
9621 			}
9622 		}
9623 	} else {
9624 		const cfg_obj_t *logobj = NULL;
9625 
9626 		isc_logconfig_create(named_g_lctx, &logc);
9627 
9628 		logobj = NULL;
9629 		(void)cfg_map_get(config, "logging", &logobj);
9630 		if (logobj != NULL) {
9631 			CHECKM(named_logconfig(logc, logobj),
9632 			       "configuring logging");
9633 		} else {
9634 			named_log_setdefaultchannels(logc);
9635 			named_log_setdefaultsslkeylogfile(logc);
9636 			CHECKM(named_log_setunmatchedcategory(logc),
9637 			       "setting up default 'category unmatched'");
9638 			CHECKM(named_log_setdefaultcategory(logc),
9639 			       "setting up default 'category default'");
9640 		}
9641 
9642 		isc_logconfig_use(named_g_lctx, logc);
9643 		logc = NULL;
9644 
9645 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9646 			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9647 			      "now using logging configuration from "
9648 			      "config file");
9649 	}
9650 
9651 	/*
9652 	 * Set the default value of the query logging flag depending
9653 	 * whether a "queries" category has been defined.  This is
9654 	 * a disgusting hack, but we need to do this for BIND 8
9655 	 * compatibility.
9656 	 */
9657 	if (first_time) {
9658 		const cfg_obj_t *logobj = NULL;
9659 		const cfg_obj_t *categories = NULL;
9660 
9661 		obj = NULL;
9662 		if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
9663 			ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES,
9664 					    cfg_obj_asboolean(obj));
9665 		} else {
9666 			(void)cfg_map_get(config, "logging", &logobj);
9667 			if (logobj != NULL) {
9668 				(void)cfg_map_get(logobj, "category",
9669 						  &categories);
9670 			}
9671 			if (categories != NULL) {
9672 				for (element = cfg_list_first(categories);
9673 				     element != NULL;
9674 				     element = cfg_list_next(element))
9675 				{
9676 					const cfg_obj_t *catobj;
9677 					const char *str;
9678 
9679 					obj = cfg_listelt_value(element);
9680 					catobj = cfg_tuple_get(obj, "name");
9681 					str = cfg_obj_asstring(catobj);
9682 					if (strcasecmp(str, "queries") == 0) {
9683 						ns_server_setoption(
9684 							server->sctx,
9685 							NS_SERVER_LOGQUERIES,
9686 							true);
9687 					}
9688 				}
9689 			}
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 	CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
9717 	       "strdup");
9718 
9719 	obj = NULL;
9720 	result = named_config_get(maps, "dump-file", &obj);
9721 	INSIST(result == ISC_R_SUCCESS);
9722 	CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
9723 	       "strdup");
9724 
9725 	obj = NULL;
9726 	result = named_config_get(maps, "secroots-file", &obj);
9727 	INSIST(result == ISC_R_SUCCESS);
9728 	CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
9729 	       "strdup");
9730 
9731 	obj = NULL;
9732 	result = named_config_get(maps, "recursing-file", &obj);
9733 	INSIST(result == ISC_R_SUCCESS);
9734 	CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
9735 	       "strdup");
9736 
9737 	obj = NULL;
9738 	result = named_config_get(maps, "version", &obj);
9739 	if (result == ISC_R_SUCCESS) {
9740 		CHECKM(setoptstring(server, &server->version, obj), "strdup");
9741 		server->version_set = true;
9742 	} else {
9743 		server->version_set = false;
9744 	}
9745 
9746 	obj = NULL;
9747 	result = named_config_get(maps, "hostname", &obj);
9748 	if (result == ISC_R_SUCCESS) {
9749 		CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
9750 		server->hostname_set = true;
9751 	} else {
9752 		server->hostname_set = false;
9753 	}
9754 
9755 	obj = NULL;
9756 	result = named_config_get(maps, "server-id", &obj);
9757 	server->sctx->usehostname = false;
9758 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
9759 		/* The parser translates "hostname" to true */
9760 		server->sctx->usehostname = true;
9761 		result = ns_server_setserverid(server->sctx, NULL);
9762 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
9763 		/* Found a quoted string */
9764 		result = ns_server_setserverid(server->sctx,
9765 					       cfg_obj_asstring(obj));
9766 	} else {
9767 		result = ns_server_setserverid(server->sctx, NULL);
9768 	}
9769 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9770 
9771 	obj = NULL;
9772 	result = named_config_get(maps, "flush-zones-on-shutdown", &obj);
9773 	if (result == ISC_R_SUCCESS) {
9774 		server->flushonshutdown = cfg_obj_asboolean(obj);
9775 	} else {
9776 		server->flushonshutdown = false;
9777 	}
9778 
9779 	obj = NULL;
9780 	result = named_config_get(maps, "answer-cookie", &obj);
9781 	INSIST(result == ISC_R_SUCCESS);
9782 	server->sctx->answercookie = cfg_obj_asboolean(obj);
9783 
9784 	obj = NULL;
9785 	result = named_config_get(maps, "cookie-algorithm", &obj);
9786 	INSIST(result == ISC_R_SUCCESS);
9787 	if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
9788 		server->sctx->cookiealg = ns_cookiealg_siphash24;
9789 	} else if (strcasecmp(cfg_obj_asstring(obj), "aes") == 0) {
9790 		server->sctx->cookiealg = ns_cookiealg_aes;
9791 	} else {
9792 		UNREACHABLE();
9793 	}
9794 
9795 	obj = NULL;
9796 	result = named_config_get(maps, "cookie-secret", &obj);
9797 	if (result == ISC_R_SUCCESS) {
9798 		const char *str;
9799 		bool first = true;
9800 		isc_buffer_t b;
9801 		unsigned int usedlength;
9802 		unsigned int expectedlength;
9803 
9804 		for (element = cfg_list_first(obj); element != NULL;
9805 		     element = cfg_list_next(element))
9806 		{
9807 			obj = cfg_listelt_value(element);
9808 			str = cfg_obj_asstring(obj);
9809 
9810 			if (first) {
9811 				memset(server->sctx->secret, 0,
9812 				       sizeof(server->sctx->secret));
9813 				isc_buffer_init(&b, server->sctx->secret,
9814 						sizeof(server->sctx->secret));
9815 				result = isc_hex_decodestring(str, &b);
9816 				if (result != ISC_R_SUCCESS &&
9817 				    result != ISC_R_NOSPACE)
9818 				{
9819 					goto cleanup;
9820 				}
9821 				first = false;
9822 			} else {
9823 				altsecret = isc_mem_get(server->sctx->mctx,
9824 							sizeof(*altsecret));
9825 				isc_buffer_init(&b, altsecret->secret,
9826 						sizeof(altsecret->secret));
9827 				result = isc_hex_decodestring(str, &b);
9828 				if (result != ISC_R_SUCCESS &&
9829 				    result != ISC_R_NOSPACE)
9830 				{
9831 					isc_mem_put(server->sctx->mctx,
9832 						    altsecret,
9833 						    sizeof(*altsecret));
9834 					goto cleanup;
9835 				}
9836 				ISC_LIST_INITANDAPPEND(altsecrets, altsecret,
9837 						       link);
9838 			}
9839 
9840 			usedlength = isc_buffer_usedlength(&b);
9841 			switch (server->sctx->cookiealg) {
9842 			case ns_cookiealg_siphash24:
9843 				expectedlength = ISC_SIPHASH24_KEY_LENGTH;
9844 				if (usedlength != expectedlength) {
9845 					CHECKM(ISC_R_RANGE, "SipHash-2-4 "
9846 							    "cookie-secret "
9847 							    "must be 128 bits");
9848 				}
9849 				break;
9850 			case ns_cookiealg_aes:
9851 				expectedlength = ISC_AES128_KEYLENGTH;
9852 				if (usedlength != expectedlength) {
9853 					CHECKM(ISC_R_RANGE, "AES cookie-secret "
9854 							    "must be 128 bits");
9855 				}
9856 				break;
9857 			}
9858 		}
9859 	} else {
9860 		isc_nonce_buf(server->sctx->secret,
9861 			      sizeof(server->sctx->secret));
9862 	}
9863 
9864 	/*
9865 	 * Swap altsecrets lists.
9866 	 */
9867 	tmpaltsecrets = server->sctx->altsecrets;
9868 	server->sctx->altsecrets = altsecrets;
9869 	altsecrets = tmpaltsecrets;
9870 
9871 	(void)named_server_loadnta(server);
9872 
9873 #ifdef USE_DNSRPS
9874 	/*
9875 	 * Start and connect to the DNS Response Policy Service
9876 	 * daemon, dnsrpzd, for each view that uses DNSRPS.
9877 	 */
9878 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9879 	     view = ISC_LIST_NEXT(view, link))
9880 	{
9881 		result = dns_dnsrps_connect(view->rpzs);
9882 		if (result != ISC_R_SUCCESS) {
9883 			view = NULL;
9884 			goto cleanup;
9885 		}
9886 	}
9887 #endif /* ifdef USE_DNSRPS */
9888 
9889 	result = ISC_R_SUCCESS;
9890 
9891 cleanup:
9892 	if (logc != NULL) {
9893 		isc_logconfig_destroy(&logc);
9894 	}
9895 
9896 	if (v4portset != NULL) {
9897 		isc_portset_destroy(named_g_mctx, &v4portset);
9898 	}
9899 
9900 	if (v6portset != NULL) {
9901 		isc_portset_destroy(named_g_mctx, &v6portset);
9902 	}
9903 
9904 	if (conf_parser != NULL) {
9905 		if (config != NULL) {
9906 			cfg_obj_destroy(conf_parser, &config);
9907 		}
9908 		cfg_parser_destroy(&conf_parser);
9909 	}
9910 
9911 	if (bindkeys_parser != NULL) {
9912 		if (bindkeys != NULL) {
9913 			cfg_obj_destroy(bindkeys_parser, &bindkeys);
9914 		}
9915 		cfg_parser_destroy(&bindkeys_parser);
9916 	}
9917 
9918 	if (view != NULL) {
9919 		dns_view_detach(&view);
9920 	}
9921 
9922 	if (kasp != NULL) {
9923 		dns_kasp_detach(&kasp);
9924 	}
9925 
9926 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9927 
9928 	/*
9929 	 * This cleans up either the old production view list
9930 	 * or our temporary list depending on whether they
9931 	 * were swapped above or not.
9932 	 */
9933 	for (view = ISC_LIST_HEAD(viewlist); view != NULL; view = view_next) {
9934 		view_next = ISC_LIST_NEXT(view, link);
9935 		ISC_LIST_UNLINK(viewlist, view, link);
9936 		if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
9937 		{
9938 			dns_view_setviewrevert(view);
9939 			(void)dns_zt_apply(view->zonetable, isc_rwlocktype_read,
9940 					   false, NULL, removed, view);
9941 		}
9942 		dns_view_detach(&view);
9943 	}
9944 
9945 	/*
9946 	 * Same cleanup for kasp list.
9947 	 */
9948 	for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
9949 		kasp_next = ISC_LIST_NEXT(kasp, link);
9950 		ISC_LIST_UNLINK(kasplist, kasp, link);
9951 		dns_kasp_detach(&kasp);
9952 	}
9953 
9954 	/* Same cleanup for cache list. */
9955 	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
9956 		ISC_LIST_UNLINK(cachelist, nsc, link);
9957 		dns_cache_detach(&nsc->cache);
9958 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9959 	}
9960 
9961 	/* Cleanup for altsecrets list. */
9962 	while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) {
9963 		ISC_LIST_UNLINK(altsecrets, altsecret, link);
9964 		isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret));
9965 	}
9966 
9967 	/*
9968 	 * Record the time of most recent configuration
9969 	 */
9970 	tresult = isc_time_now(&named_g_configtime);
9971 	if (tresult != ISC_R_SUCCESS) {
9972 		named_main_earlyfatal("isc_time_now() failed: %s",
9973 				      isc_result_totext(result));
9974 	}
9975 
9976 	/* Relinquish exclusive access to configuration data. */
9977 	if (exclusive) {
9978 		isc_task_endexclusive(server->task);
9979 	}
9980 
9981 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9982 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9983 		      "load_configuration: %s", isc_result_totext(result));
9984 
9985 	return (result);
9986 }
9987 
9988 static isc_result_t
9989 view_loaded(void *arg) {
9990 	isc_result_t result;
9991 	ns_zoneload_t *zl = (ns_zoneload_t *)arg;
9992 
9993 	/*
9994 	 * Force zone maintenance.  Do this after loading
9995 	 * so that we know when we need to force AXFR of
9996 	 * secondary zones whose master files are missing.
9997 	 *
9998 	 * We use the zoneload reference counter to let us
9999 	 * know when all views are finished.
10000 	 */
10001 	if (isc_refcount_decrement(&zl->refs) == 1) {
10002 		named_server_t *server = zl->server;
10003 		bool reconfig = zl->reconfig;
10004 		dns_view_t *view = NULL;
10005 
10006 		isc_refcount_destroy(&zl->refs);
10007 		isc_mem_put(server->mctx, zl, sizeof(*zl));
10008 
10009 		/*
10010 		 * To maintain compatibility with log parsing tools that might
10011 		 * be looking for this string after "rndc reconfig", we keep it
10012 		 * as it is
10013 		 */
10014 		if (reconfig) {
10015 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10016 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10017 				      "any newly configured zones are now "
10018 				      "loaded");
10019 		} else {
10020 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10021 				      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
10022 				      "all zones loaded");
10023 		}
10024 
10025 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
10026 		     view = ISC_LIST_NEXT(view, link))
10027 		{
10028 			if (view->managed_keys != NULL) {
10029 				result = dns_zone_synckeyzone(
10030 					view->managed_keys);
10031 				if (result != ISC_R_SUCCESS) {
10032 					isc_log_write(
10033 						named_g_lctx,
10034 						DNS_LOGCATEGORY_DNSSEC,
10035 						DNS_LOGMODULE_DNSSEC,
10036 						ISC_LOG_ERROR,
10037 						"failed to initialize "
10038 						"managed-keys for view %s "
10039 						"(%s): DNSSEC validation is "
10040 						"at risk",
10041 						view->name,
10042 						isc_result_totext(result));
10043 				}
10044 			}
10045 		}
10046 
10047 		CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
10048 			   "forcing zone maintenance");
10049 
10050 		named_os_started();
10051 
10052 #ifdef HAVE_FIPS_MODE
10053 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10054 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
10055 			      "FIPS mode is %s",
10056 			      FIPS_mode() ? "enabled" : "disabled");
10057 #endif /* ifdef HAVE_FIPS_MODE */
10058 		atomic_store(&server->reload_status, NAMED_RELOAD_DONE);
10059 
10060 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10061 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
10062 			      "running");
10063 	}
10064 
10065 	return (ISC_R_SUCCESS);
10066 }
10067 
10068 static isc_result_t
10069 load_zones(named_server_t *server, bool init, bool reconfig) {
10070 	isc_result_t result;
10071 	isc_taskmgr_t *taskmgr = dns_zonemgr_gettaskmgr(server->zonemgr);
10072 	ns_zoneload_t *zl = NULL;
10073 	dns_view_t *view = NULL;
10074 
10075 	zl = isc_mem_get(server->mctx, sizeof(*zl));
10076 	zl->server = server;
10077 	zl->reconfig = reconfig;
10078 
10079 	result = isc_task_beginexclusive(server->task);
10080 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
10081 
10082 	isc_refcount_init(&zl->refs, 1);
10083 
10084 	/*
10085 	 * Schedule zones to be loaded from disk.
10086 	 */
10087 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
10088 	     view = ISC_LIST_NEXT(view, link))
10089 	{
10090 		if (view->managed_keys != NULL) {
10091 			result = dns_zone_load(view->managed_keys, false);
10092 			if (result != ISC_R_SUCCESS &&
10093 			    result != DNS_R_UPTODATE &&
10094 			    result != DNS_R_CONTINUE)
10095 			{
10096 				goto cleanup;
10097 			}
10098 		}
10099 		if (view->redirect != NULL) {
10100 			result = dns_zone_load(view->redirect, false);
10101 			if (result != ISC_R_SUCCESS &&
10102 			    result != DNS_R_UPTODATE &&
10103 			    result != DNS_R_CONTINUE)
10104 			{
10105 				goto cleanup;
10106 			}
10107 		}
10108 
10109 		/*
10110 		 * 'dns_view_asyncload' calls view_loaded if there are no
10111 		 * zones.
10112 		 */
10113 		isc_refcount_increment(&zl->refs);
10114 		result = dns_view_asyncload(view, reconfig, view_loaded, zl);
10115 		if (result != ISC_R_SUCCESS) {
10116 			isc_refcount_decrement1(&zl->refs);
10117 			goto cleanup;
10118 		}
10119 	}
10120 
10121 cleanup:
10122 	if (isc_refcount_decrement(&zl->refs) == 1) {
10123 		isc_refcount_destroy(&zl->refs);
10124 		isc_mem_put(server->mctx, zl, sizeof(*zl));
10125 	}
10126 
10127 	if (init) {
10128 		/*
10129 		 * If we're setting up the server for the first time, set
10130 		 * the task manager into privileged mode; this ensures
10131 		 * that no other tasks will begin to run until after zone
10132 		 * loading is complete. We won't return from exclusive mode
10133 		 * until the loading is finished; we can then drop out of
10134 		 * privileged mode.
10135 		 *
10136 		 * We do *not* want to do this in the case of reload or
10137 		 * reconfig, as loading a large zone could cause the server
10138 		 * to be inactive for too long a time.
10139 		 */
10140 		isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
10141 		isc_task_endexclusive(server->task);
10142 		isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal);
10143 	} else {
10144 		isc_task_endexclusive(server->task);
10145 	}
10146 
10147 	return (result);
10148 }
10149 
10150 static void
10151 run_server(isc_task_t *task, isc_event_t *event) {
10152 	isc_result_t result;
10153 	named_server_t *server = (named_server_t *)event->ev_arg;
10154 	dns_geoip_databases_t *geoip;
10155 
10156 	INSIST(task == server->task);
10157 
10158 	isc_event_free(&event);
10159 
10160 	CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_netmgr,
10161 					  &named_g_dispatchmgr),
10162 		   "creating dispatch manager");
10163 
10164 	dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
10165 
10166 #if defined(HAVE_GEOIP2)
10167 	geoip = named_g_geoip;
10168 #else  /* if defined(HAVE_GEOIP2) */
10169 	geoip = NULL;
10170 #endif /* if defined(HAVE_GEOIP2) */
10171 
10172 	CHECKFATAL(ns_interfacemgr_create(named_g_mctx, server->sctx,
10173 					  named_g_taskmgr, named_g_timermgr,
10174 					  named_g_netmgr, named_g_dispatchmgr,
10175 					  server->task, geoip, named_g_cpus,
10176 					  true, &server->interfacemgr),
10177 		   "creating interface manager");
10178 
10179 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
10180 				    NULL, NULL, server->task,
10181 				    interface_timer_tick, server,
10182 				    &server->interface_timer),
10183 		   "creating interface timer");
10184 
10185 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
10186 				    NULL, NULL, server->task,
10187 				    heartbeat_timer_tick, server,
10188 				    &server->heartbeat_timer),
10189 		   "creating heartbeat timer");
10190 
10191 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
10192 				    NULL, NULL, server->task, tat_timer_tick,
10193 				    server, &server->tat_timer),
10194 		   "creating trust anchor telemetry timer");
10195 
10196 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
10197 				    NULL, NULL, server->task, pps_timer_tick,
10198 				    server, &server->pps_timer),
10199 		   "creating 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, true, 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(isc_task_t *task, isc_event_t *event) {
10227 	isc_result_t result;
10228 	dns_view_t *view, *view_next = NULL;
10229 	dns_kasp_t *kasp, *kasp_next = NULL;
10230 	named_server_t *server = (named_server_t *)event->ev_arg;
10231 	bool flush = server->flushonshutdown;
10232 	named_cache_t *nsc;
10233 
10234 	UNUSED(task);
10235 	INSIST(task == server->task);
10236 
10237 	/*
10238 	 * We need to shutdown the interface before going
10239 	 * exclusive (which would pause the netmgr).
10240 	 */
10241 	ns_interfacemgr_shutdown(server->interfacemgr);
10242 
10243 	result = isc_task_beginexclusive(server->task);
10244 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
10245 
10246 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10247 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "shutting down%s",
10248 		      flush ? ": flushing changes" : "");
10249 
10250 	named_statschannels_shutdown(server);
10251 	named_controls_shutdown(server->controls);
10252 	end_reserved_dispatches(server, true);
10253 	cleanup_session_key(server, server->mctx);
10254 
10255 	if (named_g_aclconfctx != NULL) {
10256 		cfg_aclconfctx_detach(&named_g_aclconfctx);
10257 	}
10258 
10259 	cfg_obj_destroy(named_g_parser, &named_g_config);
10260 	cfg_parser_destroy(&named_g_parser);
10261 	cfg_parser_destroy(&named_g_addparser);
10262 
10263 	(void)named_server_saventa(server);
10264 
10265 	for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL;
10266 	     kasp = kasp_next)
10267 	{
10268 		kasp_next = ISC_LIST_NEXT(kasp, link);
10269 		ISC_LIST_UNLINK(server->kasplist, kasp, link);
10270 		dns_kasp_detach(&kasp);
10271 	}
10272 
10273 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
10274 	     view = view_next)
10275 	{
10276 		view_next = ISC_LIST_NEXT(view, link);
10277 		ISC_LIST_UNLINK(server->viewlist, view, link);
10278 		if (flush) {
10279 			dns_view_flushanddetach(&view);
10280 		} else {
10281 			dns_view_detach(&view);
10282 		}
10283 	}
10284 
10285 	/*
10286 	 * Shut down all dyndb instances.
10287 	 */
10288 	dns_dyndb_cleanup(true);
10289 
10290 	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
10291 		ISC_LIST_UNLINK(server->cachelist, nsc, link);
10292 		dns_cache_detach(&nsc->cache);
10293 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
10294 	}
10295 
10296 	isc_timer_destroy(&server->interface_timer);
10297 	isc_timer_destroy(&server->heartbeat_timer);
10298 	isc_timer_destroy(&server->pps_timer);
10299 	isc_timer_destroy(&server->tat_timer);
10300 
10301 	ns_interfacemgr_detach(&server->interfacemgr);
10302 
10303 	dns_dispatchmgr_detach(&named_g_dispatchmgr);
10304 
10305 	dns_zonemgr_shutdown(server->zonemgr);
10306 
10307 	if (named_g_sessionkey != NULL) {
10308 		dns_tsigkey_detach(&named_g_sessionkey);
10309 		dns_name_free(&named_g_sessionkeyname, server->mctx);
10310 	}
10311 #if defined(HAVE_GEOIP2)
10312 	named_geoip_shutdown();
10313 #endif /* HAVE_GEOIP2 */
10314 
10315 	dns_db_detach(&server->in_roothints);
10316 
10317 	isc_task_endexclusive(server->task);
10318 
10319 	isc_task_detach(&server->task);
10320 
10321 	isc_event_free(&event);
10322 }
10323 
10324 /*%
10325  * Find a view that matches the source and destination addresses of a query.
10326  */
10327 static isc_result_t
10328 get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
10329 		  dns_message_t *message, dns_aclenv_t *env,
10330 		  isc_result_t *sigresult, dns_view_t **viewp) {
10331 	dns_view_t *view;
10332 
10333 	REQUIRE(message != NULL);
10334 	REQUIRE(sigresult != NULL);
10335 	REQUIRE(viewp != NULL && *viewp == NULL);
10336 
10337 	for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
10338 	     view = ISC_LIST_NEXT(view, link))
10339 	{
10340 		if (message->rdclass == view->rdclass ||
10341 		    message->rdclass == dns_rdataclass_any)
10342 		{
10343 			const dns_name_t *tsig = NULL;
10344 
10345 			*sigresult = dns_message_rechecksig(message, view);
10346 			if (*sigresult == ISC_R_SUCCESS) {
10347 				dns_tsigkey_t *tsigkey;
10348 
10349 				tsigkey = message->tsigkey;
10350 				tsig = dns_tsigkey_identity(tsigkey);
10351 			}
10352 
10353 			if (dns_acl_allowed(srcaddr, tsig, view->matchclients,
10354 					    env) &&
10355 			    dns_acl_allowed(destaddr, tsig,
10356 					    view->matchdestinations, env) &&
10357 			    !(view->matchrecursiveonly &&
10358 			      (message->flags & DNS_MESSAGEFLAG_RD) == 0))
10359 			{
10360 				dns_view_attach(view, viewp);
10361 				return (ISC_R_SUCCESS);
10362 			}
10363 		}
10364 	}
10365 
10366 	return (ISC_R_NOTFOUND);
10367 }
10368 
10369 void
10370 named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
10371 	isc_result_t result;
10372 	named_server_t *server = isc_mem_get(mctx, sizeof(*server));
10373 
10374 	*server = (named_server_t){
10375 		.mctx = mctx,
10376 		.statsfile = isc_mem_strdup(mctx, "named.stats"),
10377 		.bindkeysfile = isc_mem_strdup(mctx, named_g_defaultbindkeys),
10378 		.dumpfile = isc_mem_strdup(mctx, "named_dump.db"),
10379 		.secrootsfile = isc_mem_strdup(mctx, "named.secroots"),
10380 		.recfile = isc_mem_strdup(mctx, "named.recursing"),
10381 	};
10382 
10383 #ifdef USE_DNSRPS
10384 	CHECKFATAL(dns_dnsrps_server_create(), "initializing RPZ service "
10385 					       "interface");
10386 #endif /* ifdef USE_DNSRPS */
10387 
10388 	/* Initialize server data structures. */
10389 	ISC_LIST_INIT(server->kasplist);
10390 	ISC_LIST_INIT(server->viewlist);
10391 
10392 	/* Must be first. */
10393 	CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine), "initializing "
10394 							       "DST");
10395 
10396 	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
10397 				     &server->in_roothints),
10398 		   "setting up root hints");
10399 
10400 	atomic_init(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10401 
10402 	/*
10403 	 * Setup the server task, which is responsible for coordinating
10404 	 * startup and shutdown of the server, as well as all exclusive
10405 	 * tasks.
10406 	 */
10407 	CHECKFATAL(isc_task_create_bound(named_g_taskmgr, 0, &server->task, 0),
10408 		   "creating server task");
10409 	isc_task_setname(server->task, "server", server);
10410 	isc_taskmgr_setexcltask(named_g_taskmgr, server->task);
10411 
10412 	CHECKFATAL(ns_server_create(mctx, get_matching_view, &server->sctx),
10413 		   "creating server context");
10414 
10415 #if defined(HAVE_GEOIP2)
10416 	/*
10417 	 * GeoIP must be initialized before the interface
10418 	 * manager (which includes the ACL environment)
10419 	 * is created.
10420 	 */
10421 	named_geoip_init();
10422 #endif /* HAVE_GEOIP2 */
10423 
10424 #ifdef ENABLE_AFL
10425 	server->sctx->fuzztype = named_g_fuzz_type;
10426 	server->sctx->fuzznotify = named_fuzz_notify;
10427 #endif /* ifdef ENABLE_AFL */
10428 
10429 	CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
10430 		   "isc_task_onshutdown");
10431 	CHECKFATAL(
10432 		isc_app_onrun(named_g_mctx, server->task, run_server, server),
10433 		"isc_app_onrun");
10434 
10435 	CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr,
10436 				      named_g_timermgr, named_g_netmgr,
10437 				      &server->zonemgr),
10438 		   "dns_zonemgr_create");
10439 	CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_"
10440 							       "setsize");
10441 
10442 	CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
10443 				    isc_sockstatscounter_max),
10444 		   "isc_stats_create");
10445 	isc_nm_setstats(named_g_netmgr, server->sockstats);
10446 
10447 	CHECKFATAL(isc_stats_create(named_g_mctx, &server->zonestats,
10448 				    dns_zonestatscounter_max),
10449 		   "dns_stats_create (zone)");
10450 
10451 	CHECKFATAL(isc_stats_create(named_g_mctx, &server->resolverstats,
10452 				    dns_resstatscounter_max),
10453 		   "dns_stats_create (resolver)");
10454 
10455 	CHECKFATAL(named_controls_create(server, &server->controls),
10456 		   "named_controls_create");
10457 
10458 	ISC_LIST_INIT(server->dispatches);
10459 
10460 	ISC_LIST_INIT(server->statschannels);
10461 
10462 	ISC_LIST_INIT(server->cachelist);
10463 
10464 	server->magic = NAMED_SERVER_MAGIC;
10465 
10466 	*serverp = server;
10467 }
10468 
10469 void
10470 named_server_destroy(named_server_t **serverp) {
10471 	named_server_t *server = *serverp;
10472 	REQUIRE(NAMED_SERVER_VALID(server));
10473 
10474 #ifdef HAVE_DNSTAP
10475 	if (server->dtenv != NULL) {
10476 		dns_dt_detach(&server->dtenv);
10477 	}
10478 #endif /* HAVE_DNSTAP */
10479 
10480 #ifdef USE_DNSRPS
10481 	dns_dnsrps_server_destroy();
10482 #endif /* ifdef USE_DNSRPS */
10483 
10484 	named_controls_destroy(&server->controls);
10485 
10486 	isc_stats_detach(&server->zonestats);
10487 	isc_stats_detach(&server->sockstats);
10488 	isc_stats_detach(&server->resolverstats);
10489 
10490 	if (server->sctx != NULL) {
10491 		ns_server_detach(&server->sctx);
10492 	}
10493 
10494 	isc_mem_free(server->mctx, server->statsfile);
10495 	isc_mem_free(server->mctx, server->bindkeysfile);
10496 	isc_mem_free(server->mctx, server->dumpfile);
10497 	isc_mem_free(server->mctx, server->secrootsfile);
10498 	isc_mem_free(server->mctx, server->recfile);
10499 
10500 	if (server->version != NULL) {
10501 		isc_mem_free(server->mctx, server->version);
10502 	}
10503 	if (server->hostname != NULL) {
10504 		isc_mem_free(server->mctx, server->hostname);
10505 	}
10506 	if (server->lockfile != NULL) {
10507 		isc_mem_free(server->mctx, server->lockfile);
10508 	}
10509 
10510 	if (server->zonemgr != NULL) {
10511 		dns_zonemgr_detach(&server->zonemgr);
10512 	}
10513 
10514 	dst_lib_destroy();
10515 
10516 	INSIST(ISC_LIST_EMPTY(server->kasplist));
10517 	INSIST(ISC_LIST_EMPTY(server->viewlist));
10518 	INSIST(ISC_LIST_EMPTY(server->cachelist));
10519 
10520 	if (server->tlsctx_server_cache != NULL) {
10521 		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
10522 	}
10523 
10524 	if (server->tlsctx_client_cache != NULL) {
10525 		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
10526 	}
10527 
10528 	server->magic = 0;
10529 	isc_mem_put(server->mctx, server, sizeof(*server));
10530 	*serverp = NULL;
10531 }
10532 
10533 static void
10534 fatal(named_server_t *server, const char *msg, isc_result_t result) {
10535 	if (server != NULL && server->task != NULL) {
10536 		/*
10537 		 * Prevent races between the OpenSSL on_exit registered
10538 		 * function and any other OpenSSL calls from other tasks
10539 		 * by requesting exclusive access to the task manager.
10540 		 */
10541 		(void)isc_task_beginexclusive(server->task);
10542 	}
10543 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10544 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, "%s: %s", msg,
10545 		      isc_result_totext(result));
10546 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10547 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
10548 		      "exiting (due to fatal error)");
10549 	named_os_shutdown();
10550 	_exit(EXIT_FAILURE);
10551 }
10552 
10553 static void
10554 start_reserved_dispatches(named_server_t *server) {
10555 	REQUIRE(NAMED_SERVER_VALID(server));
10556 
10557 	server->dispatchgen++;
10558 }
10559 
10560 static void
10561 end_reserved_dispatches(named_server_t *server, bool all) {
10562 	named_dispatch_t *dispatch, *nextdispatch;
10563 
10564 	REQUIRE(NAMED_SERVER_VALID(server));
10565 
10566 	for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10567 	     dispatch = nextdispatch)
10568 	{
10569 		nextdispatch = ISC_LIST_NEXT(dispatch, link);
10570 		if (!all && server->dispatchgen == dispatch->dispatchgen) {
10571 			continue;
10572 		}
10573 		ISC_LIST_UNLINK(server->dispatches, dispatch, link);
10574 		dns_dispatch_detach(&dispatch->dispatch);
10575 		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10576 	}
10577 }
10578 
10579 void
10580 named_add_reserved_dispatch(named_server_t *server,
10581 			    const isc_sockaddr_t *addr) {
10582 	named_dispatch_t *dispatch;
10583 	in_port_t port;
10584 	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
10585 	isc_result_t result;
10586 
10587 	REQUIRE(NAMED_SERVER_VALID(server));
10588 
10589 	port = isc_sockaddr_getport(addr);
10590 	if (port == 0 || port >= 1024) {
10591 		return;
10592 	}
10593 
10594 	for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10595 	     dispatch = ISC_LIST_NEXT(dispatch, link))
10596 	{
10597 		if (isc_sockaddr_equal(&dispatch->addr, addr)) {
10598 			break;
10599 		}
10600 	}
10601 	if (dispatch != NULL) {
10602 		dispatch->dispatchgen = server->dispatchgen;
10603 		return;
10604 	}
10605 
10606 	dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
10607 
10608 	dispatch->addr = *addr;
10609 	dispatch->dispatchgen = server->dispatchgen;
10610 	dispatch->dispatch = NULL;
10611 
10612 	result = dns_dispatch_createudp(named_g_dispatchmgr, &dispatch->addr,
10613 					&dispatch->dispatch);
10614 	if (result != ISC_R_SUCCESS) {
10615 		goto cleanup;
10616 	}
10617 
10618 	ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
10619 
10620 	return;
10621 
10622 cleanup:
10623 	isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10624 	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
10625 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10626 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
10627 		      "unable to create dispatch for reserved port %s: %s",
10628 		      addrbuf, isc_result_totext(result));
10629 }
10630 
10631 static isc_result_t
10632 loadconfig(named_server_t *server) {
10633 	isc_result_t result;
10634 	start_reserved_dispatches(server);
10635 	result = load_configuration(named_g_conffile, server, false);
10636 	if (result == ISC_R_SUCCESS) {
10637 		end_reserved_dispatches(server, false);
10638 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10639 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10640 			      "reloading configuration succeeded");
10641 	} else {
10642 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10643 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10644 			      "reloading configuration failed: %s",
10645 			      isc_result_totext(result));
10646 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10647 	}
10648 
10649 	return (result);
10650 }
10651 
10652 static isc_result_t
10653 reload(named_server_t *server) {
10654 	isc_result_t result;
10655 
10656 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10657 
10658 	CHECK(loadconfig(server));
10659 
10660 	result = load_zones(server, false, false);
10661 	if (result == ISC_R_SUCCESS) {
10662 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10663 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10664 			      "reloading zones succeeded");
10665 	} else {
10666 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10667 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10668 			      "reloading zones failed: %s",
10669 			      isc_result_totext(result));
10670 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10671 	}
10672 cleanup:
10673 	return (result);
10674 }
10675 
10676 /*
10677  * Handle a reload event (from SIGHUP).
10678  */
10679 static void
10680 named_server_reload(isc_task_t *task, isc_event_t *event) {
10681 	named_server_t *server = (named_server_t *)event->ev_sender;
10682 
10683 	INSIST(task == server->task);
10684 	UNUSED(task);
10685 
10686 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10687 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10688 		      "received SIGHUP signal to reload zones");
10689 	(void)reload(server);
10690 
10691 	isc_event_free(&event);
10692 }
10693 
10694 void
10695 named_server_reloadwanted(named_server_t *server) {
10696 	isc_event_t *event = isc_event_allocate(
10697 		named_g_mctx, server, NAMED_EVENT_RELOAD, named_server_reload,
10698 		NULL, sizeof(isc_event_t));
10699 	isc_task_send(server->task, &event);
10700 }
10701 
10702 void
10703 named_server_scan_interfaces(named_server_t *server) {
10704 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10705 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
10706 		      "automatic interface rescan");
10707 
10708 	ns_interfacemgr_scan(server->interfacemgr, true, false);
10709 }
10710 
10711 /*
10712  * Get the next token from lexer 'lex'.
10713  *
10714  * NOTE: the token value for string tokens always uses the same pointer
10715  * value.  Multiple calls to this function on the same lexer will always
10716  * return either that value (lex->data) or NULL. It is necessary to copy
10717  * the token into local storage if it needs to be referenced after the next
10718  * call to next_token().
10719  */
10720 static char *
10721 next_token(isc_lex_t *lex, isc_buffer_t **text) {
10722 	isc_result_t result;
10723 	isc_token_t token;
10724 
10725 	token.type = isc_tokentype_unknown;
10726 	result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING,
10727 				  &token);
10728 
10729 	switch (result) {
10730 	case ISC_R_NOMORE:
10731 		(void)isc_lex_close(lex);
10732 		break;
10733 	case ISC_R_SUCCESS:
10734 		if (token.type == isc_tokentype_eof) {
10735 			(void)isc_lex_close(lex);
10736 		}
10737 		break;
10738 	case ISC_R_NOSPACE:
10739 		if (text != NULL) {
10740 			(void)putstr(text, "token too large");
10741 			(void)putnull(text);
10742 		}
10743 		return (NULL);
10744 	default:
10745 		if (text != NULL) {
10746 			(void)putstr(text, isc_result_totext(result));
10747 			(void)putnull(text);
10748 		}
10749 		return (NULL);
10750 	}
10751 
10752 	if (token.type == isc_tokentype_string ||
10753 	    token.type == isc_tokentype_qstring)
10754 	{
10755 		return (token.value.as_textregion.base);
10756 	}
10757 
10758 	return (NULL);
10759 }
10760 
10761 /*
10762  * Find the zone specified in the control channel command, if any.
10763  * If a zone is specified, point '*zonep' at it, otherwise
10764  * set '*zonep' to NULL, and f 'zonename' is not NULL, copy
10765  * the zone name into it (N.B. 'zonename' must have space to hold
10766  * a full DNS name).
10767  *
10768  * If 'zonetxt' is set, the caller has already pulled a token
10769  * off the command line that is to be used as the zone name. (This
10770  * is sometimes done when it's necessary to check for an optional
10771  * argument before the zone name, as in "rndc sync [-clean] zone".)
10772  */
10773 static isc_result_t
10774 zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
10775 	       dns_zone_t **zonep, char *zonename, isc_buffer_t **text,
10776 	       bool skip) {
10777 	char *ptr;
10778 	char *classtxt;
10779 	const char *viewtxt = NULL;
10780 	dns_fixedname_t fname;
10781 	dns_name_t *name;
10782 	isc_result_t result;
10783 	dns_view_t *view = NULL;
10784 	dns_rdataclass_t rdclass;
10785 	char problem[DNS_NAME_FORMATSIZE + 500] = "";
10786 	char zonebuf[DNS_NAME_FORMATSIZE];
10787 	bool redirect = false;
10788 
10789 	REQUIRE(zonep != NULL && *zonep == NULL);
10790 
10791 	if (skip) {
10792 		/* Skip the command name. */
10793 		ptr = next_token(lex, text);
10794 		if (ptr == NULL) {
10795 			return (ISC_R_UNEXPECTEDEND);
10796 		}
10797 	}
10798 
10799 	/* Look for the zone name. */
10800 	if (zonetxt == NULL) {
10801 		zonetxt = next_token(lex, text);
10802 	}
10803 	if (zonetxt == NULL) {
10804 		return (ISC_R_SUCCESS);
10805 	}
10806 
10807 	/* Copy zonetxt because it'll be overwritten by next_token() */
10808 	/* To locate a zone named "-redirect" use "-redirect." */
10809 	if (strcmp(zonetxt, "-redirect") == 0) {
10810 		redirect = true;
10811 		strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE);
10812 	} else {
10813 		strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE);
10814 	}
10815 	if (zonename != NULL) {
10816 		strlcpy(zonename, redirect ? "." : zonetxt,
10817 			DNS_NAME_FORMATSIZE);
10818 	}
10819 
10820 	name = dns_fixedname_initname(&fname);
10821 	CHECK(dns_name_fromstring(name, zonebuf, 0, NULL));
10822 
10823 	/* Look for the optional class name. */
10824 	classtxt = next_token(lex, text);
10825 	if (classtxt != NULL) {
10826 		isc_textregion_t r;
10827 		r.base = classtxt;
10828 		r.length = strlen(classtxt);
10829 		CHECK(dns_rdataclass_fromtext(&rdclass, &r));
10830 
10831 		/* Look for the optional view name. */
10832 		viewtxt = next_token(lex, text);
10833 	} else {
10834 		rdclass = dns_rdataclass_in;
10835 	}
10836 
10837 	if (viewtxt == NULL) {
10838 		if (redirect) {
10839 			result = dns_viewlist_find(&server->viewlist,
10840 						   "_default",
10841 						   dns_rdataclass_in, &view);
10842 			if (result != ISC_R_SUCCESS || view->redirect == NULL) {
10843 				result = ISC_R_NOTFOUND;
10844 				snprintf(problem, sizeof(problem),
10845 					 "redirect zone not found in "
10846 					 "_default view");
10847 			} else {
10848 				dns_zone_attach(view->redirect, zonep);
10849 				result = ISC_R_SUCCESS;
10850 			}
10851 		} else {
10852 			result = dns_viewlist_findzone(&server->viewlist, name,
10853 						       (classtxt == NULL),
10854 						       rdclass, zonep);
10855 			if (result == ISC_R_NOTFOUND) {
10856 				snprintf(problem, sizeof(problem),
10857 					 "no matching zone '%s' in any view",
10858 					 zonebuf);
10859 			} else if (result == ISC_R_MULTIPLE) {
10860 				snprintf(problem, sizeof(problem),
10861 					 "zone '%s' was found in multiple "
10862 					 "views",
10863 					 zonebuf);
10864 			}
10865 		}
10866 	} else {
10867 		result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass,
10868 					   &view);
10869 		if (result != ISC_R_SUCCESS) {
10870 			snprintf(problem, sizeof(problem),
10871 				 "no matching view '%s'", viewtxt);
10872 			goto report;
10873 		}
10874 
10875 		if (redirect) {
10876 			if (view->redirect != NULL) {
10877 				dns_zone_attach(view->redirect, zonep);
10878 				result = ISC_R_SUCCESS;
10879 			} else {
10880 				result = ISC_R_NOTFOUND;
10881 			}
10882 		} else {
10883 			result = dns_zt_find(view->zonetable, name, 0, NULL,
10884 					     zonep);
10885 		}
10886 		if (result != ISC_R_SUCCESS) {
10887 			snprintf(problem, sizeof(problem),
10888 				 "no matching zone '%s' in view '%s'", zonebuf,
10889 				 viewtxt);
10890 		}
10891 	}
10892 
10893 	/* Partial match? */
10894 	if (result != ISC_R_SUCCESS && *zonep != NULL) {
10895 		dns_zone_detach(zonep);
10896 	}
10897 	if (result == DNS_R_PARTIALMATCH) {
10898 		result = ISC_R_NOTFOUND;
10899 	}
10900 report:
10901 	if (result != ISC_R_SUCCESS) {
10902 		isc_result_t tresult;
10903 
10904 		tresult = putstr(text, problem);
10905 		if (tresult == ISC_R_SUCCESS) {
10906 			(void)putnull(text);
10907 		}
10908 	}
10909 
10910 cleanup:
10911 	if (view != NULL) {
10912 		dns_view_detach(&view);
10913 	}
10914 
10915 	return (result);
10916 }
10917 
10918 /*
10919  * Act on a "retransfer" command from the command channel.
10920  */
10921 isc_result_t
10922 named_server_retransfercommand(named_server_t *server, isc_lex_t *lex,
10923 			       isc_buffer_t **text) {
10924 	isc_result_t result;
10925 	dns_zone_t *zone = NULL;
10926 	dns_zone_t *raw = NULL;
10927 	dns_zonetype_t type;
10928 
10929 	REQUIRE(text != NULL);
10930 
10931 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10932 	if (result != ISC_R_SUCCESS) {
10933 		return (result);
10934 	}
10935 	if (zone == NULL) {
10936 		return (ISC_R_UNEXPECTEDEND);
10937 	}
10938 	dns_zone_getraw(zone, &raw);
10939 	if (raw != NULL) {
10940 		dns_zone_detach(&zone);
10941 		dns_zone_attach(raw, &zone);
10942 		dns_zone_detach(&raw);
10943 	}
10944 	type = dns_zone_gettype(zone);
10945 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
10946 	    type == dns_zone_stub ||
10947 	    (type == dns_zone_redirect &&
10948 	     dns_zone_getredirecttype(zone) == dns_zone_secondary))
10949 	{
10950 		dns_zone_forcereload(zone);
10951 	} else {
10952 		(void)putstr(text, "retransfer: inappropriate zone type: ");
10953 		(void)putstr(text, dns_zonetype_name(type));
10954 		if (type == dns_zone_redirect) {
10955 			type = dns_zone_getredirecttype(zone);
10956 			(void)putstr(text, "(");
10957 			(void)putstr(text, dns_zonetype_name(type));
10958 			(void)putstr(text, ")");
10959 		}
10960 		(void)putnull(text);
10961 		result = ISC_R_FAILURE;
10962 	}
10963 	dns_zone_detach(&zone);
10964 	return (result);
10965 }
10966 
10967 /*
10968  * Act on a "reload" command from the command channel.
10969  */
10970 isc_result_t
10971 named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
10972 			   isc_buffer_t **text) {
10973 	isc_result_t result;
10974 	dns_zone_t *zone = NULL;
10975 	dns_zonetype_t type;
10976 	const char *msg = NULL;
10977 
10978 	REQUIRE(text != NULL);
10979 
10980 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10981 	if (result != ISC_R_SUCCESS) {
10982 		return (result);
10983 	}
10984 	if (zone == NULL) {
10985 		result = reload(server);
10986 		if (result == ISC_R_SUCCESS) {
10987 			msg = "server reload successful";
10988 		}
10989 	} else {
10990 		type = dns_zone_gettype(zone);
10991 		if (type == dns_zone_secondary || type == dns_zone_mirror ||
10992 		    type == dns_zone_stub)
10993 		{
10994 			dns_zone_refresh(zone);
10995 			dns_zone_detach(&zone);
10996 			msg = "zone refresh queued";
10997 		} else {
10998 			result = dns_zone_load(zone, false);
10999 			dns_zone_detach(&zone);
11000 			switch (result) {
11001 			case ISC_R_SUCCESS:
11002 				msg = "zone reload successful";
11003 				break;
11004 			case DNS_R_CONTINUE:
11005 				msg = "zone reload queued";
11006 				result = ISC_R_SUCCESS;
11007 				break;
11008 			case DNS_R_UPTODATE:
11009 				msg = "zone reload up-to-date";
11010 				result = ISC_R_SUCCESS;
11011 				break;
11012 			default:
11013 				/* failure message will be generated by rndc */
11014 				break;
11015 			}
11016 		}
11017 	}
11018 	if (msg != NULL) {
11019 		(void)putstr(text, msg);
11020 		(void)putnull(text);
11021 	}
11022 	return (result);
11023 }
11024 
11025 /*
11026  * Act on a "reconfig" command from the command channel.
11027  */
11028 isc_result_t
11029 named_server_reconfigcommand(named_server_t *server) {
11030 	isc_result_t result;
11031 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
11032 
11033 	CHECK(loadconfig(server));
11034 
11035 	result = load_zones(server, false, true);
11036 	if (result == ISC_R_SUCCESS) {
11037 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11038 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11039 			      "scheduled loading new zones");
11040 	} else {
11041 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11042 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11043 			      "loading new zones failed: %s",
11044 			      isc_result_totext(result));
11045 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
11046 	}
11047 cleanup:
11048 	return (result);
11049 }
11050 
11051 /*
11052  * Act on a "notify" command from the command channel.
11053  */
11054 isc_result_t
11055 named_server_notifycommand(named_server_t *server, isc_lex_t *lex,
11056 			   isc_buffer_t **text) {
11057 	isc_result_t result;
11058 	dns_zone_t *zone = NULL;
11059 	const char msg[] = "zone notify queued";
11060 
11061 	REQUIRE(text != NULL);
11062 
11063 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
11064 	if (result != ISC_R_SUCCESS) {
11065 		return (result);
11066 	}
11067 	if (zone == NULL) {
11068 		return (ISC_R_UNEXPECTEDEND);
11069 	}
11070 
11071 	dns_zone_notify(zone);
11072 	dns_zone_detach(&zone);
11073 	(void)putstr(text, msg);
11074 	(void)putnull(text);
11075 
11076 	return (ISC_R_SUCCESS);
11077 }
11078 
11079 /*
11080  * Act on a "refresh" command from the command channel.
11081  */
11082 isc_result_t
11083 named_server_refreshcommand(named_server_t *server, isc_lex_t *lex,
11084 			    isc_buffer_t **text) {
11085 	isc_result_t result;
11086 	dns_zone_t *zone = NULL, *raw = NULL;
11087 	const char msg1[] = "zone refresh queued";
11088 	const char msg2[] = "not a secondary, mirror, or stub zone";
11089 	dns_zonetype_t type;
11090 
11091 	REQUIRE(text != NULL);
11092 
11093 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
11094 	if (result != ISC_R_SUCCESS) {
11095 		return (result);
11096 	}
11097 	if (zone == NULL) {
11098 		return (ISC_R_UNEXPECTEDEND);
11099 	}
11100 
11101 	dns_zone_getraw(zone, &raw);
11102 	if (raw != NULL) {
11103 		dns_zone_detach(&zone);
11104 		dns_zone_attach(raw, &zone);
11105 		dns_zone_detach(&raw);
11106 	}
11107 
11108 	type = dns_zone_gettype(zone);
11109 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
11110 	    type == dns_zone_stub)
11111 	{
11112 		dns_zone_refresh(zone);
11113 		dns_zone_detach(&zone);
11114 		(void)putstr(text, msg1);
11115 		(void)putnull(text);
11116 		return (ISC_R_SUCCESS);
11117 	}
11118 
11119 	dns_zone_detach(&zone);
11120 	(void)putstr(text, msg2);
11121 	(void)putnull(text);
11122 	return (ISC_R_FAILURE);
11123 }
11124 
11125 isc_result_t
11126 named_server_togglequerylog(named_server_t *server, isc_lex_t *lex) {
11127 	bool prev, value;
11128 	char *ptr;
11129 
11130 	/* Skip the command name. */
11131 	ptr = next_token(lex, NULL);
11132 	if (ptr == NULL) {
11133 		return (ISC_R_UNEXPECTEDEND);
11134 	}
11135 
11136 	prev = ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES);
11137 
11138 	ptr = next_token(lex, NULL);
11139 	if (ptr == NULL) {
11140 		value = !prev;
11141 	} else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
11142 		   !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
11143 	{
11144 		value = true;
11145 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
11146 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
11147 	{
11148 		value = false;
11149 	} else {
11150 		return (DNS_R_SYNTAX);
11151 	}
11152 
11153 	if (value == prev) {
11154 		return (ISC_R_SUCCESS);
11155 	}
11156 
11157 	ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES, value);
11158 
11159 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11160 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11161 		      "query logging is now %s", value ? "on" : "off");
11162 	return (ISC_R_SUCCESS);
11163 }
11164 
11165 static isc_result_t
11166 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
11167 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
11168 		      isc_tlsctx_cache_t *tlsctx_cache,
11169 		      ns_listenlist_t **target) {
11170 	isc_result_t result;
11171 	const cfg_listelt_t *element;
11172 	ns_listenlist_t *dlist = NULL;
11173 
11174 	REQUIRE(target != NULL && *target == NULL);
11175 
11176 	result = ns_listenlist_create(mctx, &dlist);
11177 	if (result != ISC_R_SUCCESS) {
11178 		return (result);
11179 	}
11180 
11181 	for (element = cfg_list_first(listenlist); element != NULL;
11182 	     element = cfg_list_next(element))
11183 	{
11184 		ns_listenelt_t *delt = NULL;
11185 		const cfg_obj_t *listener = cfg_listelt_value(element);
11186 		result = listenelt_fromconfig(listener, config, actx, mctx,
11187 					      family, tlsctx_cache, &delt);
11188 		if (result != ISC_R_SUCCESS) {
11189 			goto cleanup;
11190 		}
11191 		ISC_LIST_APPEND(dlist->elts, delt, link);
11192 	}
11193 	*target = dlist;
11194 	return (ISC_R_SUCCESS);
11195 
11196 cleanup:
11197 	ns_listenlist_detach(&dlist);
11198 	return (result);
11199 }
11200 
11201 static const cfg_obj_t *
11202 find_maplist(const cfg_obj_t *config, const char *listname, const char *name) {
11203 	isc_result_t result;
11204 	const cfg_obj_t *maplist = NULL;
11205 	const cfg_listelt_t *elt = NULL;
11206 
11207 	REQUIRE(config != NULL);
11208 	REQUIRE(name != NULL);
11209 
11210 	result = cfg_map_get(config, listname, &maplist);
11211 	if (result != ISC_R_SUCCESS) {
11212 		return (NULL);
11213 	}
11214 
11215 	for (elt = cfg_list_first(maplist); elt != NULL;
11216 	     elt = cfg_list_next(elt))
11217 	{
11218 		const cfg_obj_t *map = cfg_listelt_value(elt);
11219 		if (strcasecmp(cfg_obj_asstring(cfg_map_getname(map)), name) ==
11220 		    0)
11221 		{
11222 			return (map);
11223 		}
11224 	}
11225 
11226 	return (NULL);
11227 }
11228 
11229 /*
11230  * Create a listen list from the corresponding configuration
11231  * data structure.
11232  */
11233 static isc_result_t
11234 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
11235 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
11236 		     isc_tlsctx_cache_t *tlsctx_cache,
11237 		     ns_listenelt_t **target) {
11238 	isc_result_t result;
11239 	const cfg_obj_t *ltup = NULL;
11240 	const cfg_obj_t *tlsobj = NULL, *httpobj = NULL;
11241 	const cfg_obj_t *portobj = NULL;
11242 	const cfg_obj_t *http_server = NULL;
11243 	in_port_t port = 0;
11244 	const char *key = NULL, *cert = NULL, *ca_file = NULL,
11245 		   *dhparam_file = NULL, *ciphers = NULL;
11246 	bool tls_prefer_server_ciphers = false,
11247 	     tls_prefer_server_ciphers_set = false;
11248 	bool tls_session_tickets = false, tls_session_tickets_set = false;
11249 	bool do_tls = false, no_tls = false, http = false;
11250 	ns_listenelt_t *delt = NULL;
11251 	uint32_t tls_protos = 0;
11252 	ns_listen_tls_params_t tls_params = { 0 };
11253 	const char *tlsname = NULL;
11254 
11255 	REQUIRE(target != NULL && *target == NULL);
11256 
11257 	ltup = cfg_tuple_get(listener, "tuple");
11258 	RUNTIME_CHECK(ltup != NULL);
11259 
11260 	tlsobj = cfg_tuple_get(ltup, "tls");
11261 	if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) {
11262 		tlsname = cfg_obj_asstring(tlsobj);
11263 
11264 		if (strcasecmp(tlsname, "none") == 0) {
11265 			no_tls = true;
11266 		} else if (strcasecmp(tlsname, "ephemeral") == 0) {
11267 			do_tls = true;
11268 		} else {
11269 			const cfg_obj_t *keyobj = NULL, *certobj = NULL,
11270 					*ca_obj = NULL, *dhparam_obj = NULL;
11271 			const cfg_obj_t *tlsmap = NULL;
11272 			const cfg_obj_t *tls_proto_list = NULL;
11273 			const cfg_obj_t *ciphers_obj = NULL;
11274 			const cfg_obj_t *prefer_server_ciphers_obj = NULL;
11275 			const cfg_obj_t *session_tickets_obj = NULL;
11276 
11277 			do_tls = true;
11278 
11279 			tlsmap = find_maplist(config, "tls", tlsname);
11280 			if (tlsmap == NULL) {
11281 				cfg_obj_log(tlsobj, named_g_lctx, ISC_LOG_ERROR,
11282 					    "tls '%s' is not defined",
11283 					    cfg_obj_asstring(tlsobj));
11284 				return (ISC_R_FAILURE);
11285 			}
11286 
11287 			CHECK(cfg_map_get(tlsmap, "key-file", &keyobj));
11288 			key = cfg_obj_asstring(keyobj);
11289 
11290 			CHECK(cfg_map_get(tlsmap, "cert-file", &certobj));
11291 			cert = cfg_obj_asstring(certobj);
11292 
11293 			if (cfg_map_get(tlsmap, "ca-file", &ca_obj) ==
11294 			    ISC_R_SUCCESS)
11295 			{
11296 				ca_file = cfg_obj_asstring(ca_obj);
11297 			}
11298 
11299 			if (cfg_map_get(tlsmap, "protocols", &tls_proto_list) ==
11300 			    ISC_R_SUCCESS)
11301 			{
11302 				const cfg_listelt_t *proto = NULL;
11303 				INSIST(tls_proto_list != NULL);
11304 				for (proto = cfg_list_first(tls_proto_list);
11305 				     proto != 0; proto = cfg_list_next(proto))
11306 				{
11307 					const cfg_obj_t *tls_proto_obj =
11308 						cfg_listelt_value(proto);
11309 					const char *tls_sver =
11310 						cfg_obj_asstring(tls_proto_obj);
11311 					const isc_tls_protocol_version_t ver =
11312 						isc_tls_protocol_name_to_version(
11313 							tls_sver);
11314 
11315 					INSIST(ver !=
11316 					       ISC_TLS_PROTO_VER_UNDEFINED);
11317 					INSIST(isc_tls_protocol_supported(ver));
11318 					tls_protos |= ver;
11319 				}
11320 			}
11321 
11322 			if (cfg_map_get(tlsmap, "dhparam-file", &dhparam_obj) ==
11323 			    ISC_R_SUCCESS)
11324 			{
11325 				dhparam_file = cfg_obj_asstring(dhparam_obj);
11326 			}
11327 
11328 			if (cfg_map_get(tlsmap, "ciphers", &ciphers_obj) ==
11329 			    ISC_R_SUCCESS)
11330 			{
11331 				ciphers = cfg_obj_asstring(ciphers_obj);
11332 			}
11333 
11334 			if (cfg_map_get(tlsmap, "prefer-server-ciphers",
11335 					&prefer_server_ciphers_obj) ==
11336 			    ISC_R_SUCCESS)
11337 			{
11338 				tls_prefer_server_ciphers = cfg_obj_asboolean(
11339 					prefer_server_ciphers_obj);
11340 				tls_prefer_server_ciphers_set = true;
11341 			}
11342 
11343 			if (cfg_map_get(tlsmap, "session-tickets",
11344 					&session_tickets_obj) == ISC_R_SUCCESS)
11345 			{
11346 				tls_session_tickets =
11347 					cfg_obj_asboolean(session_tickets_obj);
11348 				tls_session_tickets_set = true;
11349 			}
11350 		}
11351 	}
11352 
11353 	tls_params = (ns_listen_tls_params_t){
11354 		.name = tlsname,
11355 		.key = key,
11356 		.cert = cert,
11357 		.ca_file = ca_file,
11358 		.protocols = tls_protos,
11359 		.dhparam_file = dhparam_file,
11360 		.ciphers = ciphers,
11361 		.prefer_server_ciphers = tls_prefer_server_ciphers,
11362 		.prefer_server_ciphers_set = tls_prefer_server_ciphers_set,
11363 		.session_tickets = tls_session_tickets,
11364 		.session_tickets_set = tls_session_tickets_set
11365 	};
11366 
11367 	httpobj = cfg_tuple_get(ltup, "http");
11368 	if (httpobj != NULL && cfg_obj_isstring(httpobj)) {
11369 		const char *httpname = cfg_obj_asstring(httpobj);
11370 
11371 		if (!do_tls && !no_tls) {
11372 			return (ISC_R_FAILURE);
11373 		}
11374 
11375 		http_server = find_maplist(config, "http", httpname);
11376 		if (http_server == NULL && strcasecmp(httpname, "default") != 0)
11377 		{
11378 			cfg_obj_log(httpobj, named_g_lctx, ISC_LOG_ERROR,
11379 				    "http '%s' is not defined",
11380 				    cfg_obj_asstring(httpobj));
11381 			return (ISC_R_FAILURE);
11382 		}
11383 
11384 		http = true;
11385 	}
11386 
11387 	portobj = cfg_tuple_get(ltup, "port");
11388 	if (!cfg_obj_isuint32(portobj)) {
11389 		if (http && do_tls) {
11390 			if (named_g_httpsport != 0) {
11391 				port = named_g_httpsport;
11392 			} else {
11393 				result = named_config_getport(
11394 					config, "https-port", &port);
11395 				if (result != ISC_R_SUCCESS) {
11396 					return (result);
11397 				}
11398 			}
11399 		} else if (http && !do_tls) {
11400 			if (named_g_httpport != 0) {
11401 				port = named_g_httpport;
11402 			} else {
11403 				result = named_config_getport(
11404 					config, "http-port", &port);
11405 				if (result != ISC_R_SUCCESS) {
11406 					return (result);
11407 				}
11408 			}
11409 		} else if (do_tls) {
11410 			if (named_g_tlsport != 0) {
11411 				port = named_g_tlsport;
11412 			} else {
11413 				result = named_config_getport(
11414 					config, "tls-port", &port);
11415 				if (result != ISC_R_SUCCESS) {
11416 					return (result);
11417 				}
11418 			}
11419 		} else {
11420 			if (named_g_port != 0) {
11421 				port = named_g_port;
11422 			} else {
11423 				result = named_config_getport(config, "port",
11424 							      &port);
11425 				if (result != ISC_R_SUCCESS) {
11426 					return (result);
11427 				}
11428 			}
11429 		}
11430 	} else {
11431 		if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
11432 			return (ISC_R_RANGE);
11433 		}
11434 		port = (in_port_t)cfg_obj_asuint32(portobj);
11435 	}
11436 
11437 #ifdef HAVE_LIBNGHTTP2
11438 	if (http) {
11439 		CHECK(listenelt_http(http_server, family, do_tls, &tls_params,
11440 				     tlsctx_cache, port, mctx, &delt));
11441 	}
11442 #endif /* HAVE_LIBNGHTTP2 */
11443 
11444 	if (!http) {
11445 		CHECK(ns_listenelt_create(mctx, port, NULL, family, do_tls,
11446 					  &tls_params, tlsctx_cache, &delt));
11447 	}
11448 
11449 	result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"), config,
11450 				     named_g_lctx, actx, mctx, 0, family,
11451 				     &delt->acl);
11452 	if (result != ISC_R_SUCCESS) {
11453 		ns_listenelt_destroy(delt);
11454 		return (result);
11455 	}
11456 	*target = delt;
11457 
11458 cleanup:
11459 	return (result);
11460 }
11461 
11462 #ifdef HAVE_LIBNGHTTP2
11463 static isc_result_t
11464 listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
11465 	       const ns_listen_tls_params_t *tls_params,
11466 	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
11467 	       isc_mem_t *mctx, ns_listenelt_t **target) {
11468 	isc_result_t result = ISC_R_SUCCESS;
11469 	ns_listenelt_t *delt = NULL;
11470 	char **endpoints = NULL;
11471 	const cfg_obj_t *eplist = NULL;
11472 	const cfg_listelt_t *elt = NULL;
11473 	size_t len = 1, i = 0;
11474 	uint32_t max_clients = named_g_http_listener_clients;
11475 	uint32_t max_streams = named_g_http_streams_per_conn;
11476 
11477 	REQUIRE(target != NULL && *target == NULL);
11478 
11479 	if (tls) {
11480 		INSIST(tls_params != NULL);
11481 		INSIST((tls_params->key == NULL) == (tls_params->cert == NULL));
11482 	}
11483 
11484 	if (port == 0) {
11485 		port = tls ? named_g_httpsport : named_g_httpport;
11486 	}
11487 
11488 	/*
11489 	 * If "default" was used, we set up the default endpoint
11490 	 * of "/dns-query".
11491 	 */
11492 	if (http != NULL) {
11493 		const cfg_obj_t *cfg_max_clients = NULL;
11494 		const cfg_obj_t *cfg_max_streams = NULL;
11495 
11496 		if (cfg_map_get(http, "endpoints", &eplist) == ISC_R_SUCCESS) {
11497 			INSIST(eplist != NULL);
11498 			len = cfg_list_length(eplist, false);
11499 		}
11500 
11501 		if (cfg_map_get(http, "listener-clients", &cfg_max_clients) ==
11502 		    ISC_R_SUCCESS)
11503 		{
11504 			INSIST(cfg_max_clients != NULL);
11505 			max_clients = cfg_obj_asuint32(cfg_max_clients);
11506 		}
11507 
11508 		if (cfg_map_get(http, "streams-per-connection",
11509 				&cfg_max_streams) == ISC_R_SUCCESS)
11510 		{
11511 			INSIST(cfg_max_streams != NULL);
11512 			max_streams = cfg_obj_asuint32(cfg_max_streams);
11513 		}
11514 	}
11515 
11516 	endpoints = isc_mem_allocate(mctx, sizeof(endpoints[0]) * len);
11517 
11518 	if (http != NULL && eplist != NULL) {
11519 		for (elt = cfg_list_first(eplist); elt != NULL;
11520 		     elt = cfg_list_next(elt))
11521 		{
11522 			const cfg_obj_t *ep = cfg_listelt_value(elt);
11523 			const char *path = cfg_obj_asstring(ep);
11524 			endpoints[i++] = isc_mem_strdup(mctx, path);
11525 		}
11526 	} else {
11527 		endpoints[i++] = isc_mem_strdup(mctx, ISC_NM_HTTP_DEFAULT_PATH);
11528 	}
11529 
11530 	INSIST(i == len);
11531 
11532 	result = ns_listenelt_create_http(mctx, port, NULL, family, tls,
11533 					  tls_params, tlsctx_cache, endpoints,
11534 					  len, max_clients, max_streams, &delt);
11535 	if (result != ISC_R_SUCCESS) {
11536 		goto error;
11537 	}
11538 
11539 	*target = delt;
11540 
11541 	return (result);
11542 error:
11543 	if (delt != NULL) {
11544 		ns_listenelt_destroy(delt);
11545 	}
11546 	return (result);
11547 }
11548 #endif /* HAVE_LIBNGHTTP2 */
11549 
11550 isc_result_t
11551 named_server_dumpstats(named_server_t *server) {
11552 	isc_result_t result;
11553 	FILE *fp = NULL;
11554 
11555 	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
11556 		"could not open statistics dump file", server->statsfile);
11557 
11558 	result = named_stats_dump(server, fp);
11559 
11560 cleanup:
11561 	if (fp != NULL) {
11562 		(void)isc_stdio_close(fp);
11563 	}
11564 	if (result == ISC_R_SUCCESS) {
11565 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11566 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11567 			      "dumpstats complete");
11568 	} else {
11569 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11570 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11571 			      "dumpstats failed: %s",
11572 			      isc_result_totext(result));
11573 	}
11574 	return (result);
11575 }
11576 
11577 static isc_result_t
11578 add_zone_tolist(dns_zone_t *zone, void *uap) {
11579 	struct dumpcontext *dctx = uap;
11580 	struct zonelistentry *zle;
11581 
11582 	zle = isc_mem_get(dctx->mctx, sizeof *zle);
11583 	zle->zone = NULL;
11584 	dns_zone_attach(zone, &zle->zone);
11585 	ISC_LINK_INIT(zle, link);
11586 	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
11587 	return (ISC_R_SUCCESS);
11588 }
11589 
11590 static isc_result_t
11591 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
11592 	struct viewlistentry *vle;
11593 	isc_result_t result = ISC_R_SUCCESS;
11594 
11595 	/*
11596 	 * Prevent duplicate views.
11597 	 */
11598 	for (vle = ISC_LIST_HEAD(dctx->viewlist); vle != NULL;
11599 	     vle = ISC_LIST_NEXT(vle, link))
11600 	{
11601 		if (vle->view == view) {
11602 			return (ISC_R_SUCCESS);
11603 		}
11604 	}
11605 
11606 	vle = isc_mem_get(dctx->mctx, sizeof *vle);
11607 	vle->view = NULL;
11608 	dns_view_attach(view, &vle->view);
11609 	ISC_LINK_INIT(vle, link);
11610 	ISC_LIST_INIT(vle->zonelist);
11611 	ISC_LIST_APPEND(dctx->viewlist, vle, link);
11612 	if (dctx->dumpzones) {
11613 		result = dns_zt_apply(view->zonetable, isc_rwlocktype_read,
11614 				      true, NULL, add_zone_tolist, dctx);
11615 	}
11616 	return (result);
11617 }
11618 
11619 static void
11620 dumpcontext_destroy(struct dumpcontext *dctx) {
11621 	struct viewlistentry *vle;
11622 	struct zonelistentry *zle;
11623 
11624 	vle = ISC_LIST_HEAD(dctx->viewlist);
11625 	while (vle != NULL) {
11626 		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
11627 		zle = ISC_LIST_HEAD(vle->zonelist);
11628 		while (zle != NULL) {
11629 			ISC_LIST_UNLINK(vle->zonelist, zle, link);
11630 			dns_zone_detach(&zle->zone);
11631 			isc_mem_put(dctx->mctx, zle, sizeof *zle);
11632 			zle = ISC_LIST_HEAD(vle->zonelist);
11633 		}
11634 		dns_view_detach(&vle->view);
11635 		isc_mem_put(dctx->mctx, vle, sizeof *vle);
11636 		vle = ISC_LIST_HEAD(dctx->viewlist);
11637 	}
11638 	if (dctx->version != NULL) {
11639 		dns_db_closeversion(dctx->db, &dctx->version, false);
11640 	}
11641 	if (dctx->db != NULL) {
11642 		dns_db_detach(&dctx->db);
11643 	}
11644 	if (dctx->cache != NULL) {
11645 		dns_db_detach(&dctx->cache);
11646 	}
11647 	if (dctx->task != NULL) {
11648 		isc_task_detach(&dctx->task);
11649 	}
11650 	if (dctx->fp != NULL) {
11651 		(void)isc_stdio_close(dctx->fp);
11652 	}
11653 	if (dctx->mdctx != NULL) {
11654 		dns_dumpctx_detach(&dctx->mdctx);
11655 	}
11656 	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
11657 }
11658 
11659 static void
11660 dumpdone(void *arg, isc_result_t result) {
11661 	struct dumpcontext *dctx = arg;
11662 	char buf[1024 + 32];
11663 	const dns_master_style_t *style;
11664 
11665 	if (result != ISC_R_SUCCESS) {
11666 		goto cleanup;
11667 	}
11668 	if (dctx->mdctx != NULL) {
11669 		dns_dumpctx_detach(&dctx->mdctx);
11670 	}
11671 	if (dctx->view == NULL) {
11672 		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
11673 		if (dctx->view == NULL) {
11674 			goto done;
11675 		}
11676 		INSIST(dctx->zone == NULL);
11677 	} else {
11678 		goto resume;
11679 	}
11680 nextview:
11681 	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
11682 resume:
11683 	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
11684 		fprintf(dctx->fp, ";\n; Cache of view '%s' is shared as '%s'\n",
11685 			dctx->view->view->name,
11686 			dns_cache_getname(dctx->view->view->cache));
11687 	} else if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache)
11688 	{
11689 		if (dctx->dumpexpired) {
11690 			style = &dns_master_style_cache_with_expired;
11691 		} else {
11692 			style = &dns_master_style_cache;
11693 		}
11694 		/* start cache dump */
11695 		if (dctx->view->view->cachedb != NULL) {
11696 			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11697 		}
11698 		if (dctx->cache != NULL) {
11699 			fprintf(dctx->fp,
11700 				";\n; Cache dump of view '%s' (cache %s)\n;\n",
11701 				dctx->view->view->name,
11702 				dns_cache_getname(dctx->view->view->cache));
11703 			result = dns_master_dumptostreamasync(
11704 				dctx->mctx, dctx->cache, NULL, style, dctx->fp,
11705 				dctx->task, dumpdone, dctx, &dctx->mdctx);
11706 			if (result == DNS_R_CONTINUE) {
11707 				return;
11708 			}
11709 			if (result == ISC_R_NOTIMPLEMENTED) {
11710 				fprintf(dctx->fp, "; %s\n",
11711 					isc_result_totext(result));
11712 			} else if (result != ISC_R_SUCCESS) {
11713 				goto cleanup;
11714 			}
11715 		}
11716 	}
11717 
11718 	if ((dctx->dumpadb || dctx->dumpbad || dctx->dumpfail) &&
11719 	    dctx->cache == NULL && dctx->view->view->cachedb != NULL)
11720 	{
11721 		dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11722 	}
11723 
11724 	if (dctx->cache != NULL) {
11725 		if (dctx->dumpadb) {
11726 			dns_adb_dump(dctx->view->view->adb, dctx->fp);
11727 		}
11728 		if (dctx->dumpbad) {
11729 			dns_resolver_printbadcache(dctx->view->view->resolver,
11730 						   dctx->fp);
11731 		}
11732 		if (dctx->dumpfail) {
11733 			dns_badcache_print(dctx->view->view->failcache,
11734 					   "SERVFAIL cache", dctx->fp);
11735 		}
11736 		dns_db_detach(&dctx->cache);
11737 	}
11738 	if (dctx->dumpzones) {
11739 		style = &dns_master_style_full;
11740 	nextzone:
11741 		if (dctx->version != NULL) {
11742 			dns_db_closeversion(dctx->db, &dctx->version, false);
11743 		}
11744 		if (dctx->db != NULL) {
11745 			dns_db_detach(&dctx->db);
11746 		}
11747 		if (dctx->zone == NULL) {
11748 			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
11749 		} else {
11750 			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
11751 		}
11752 		if (dctx->zone != NULL) {
11753 			/* start zone dump */
11754 			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
11755 			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
11756 			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
11757 			if (result != ISC_R_SUCCESS) {
11758 				fprintf(dctx->fp, "; %s\n",
11759 					isc_result_totext(result));
11760 				goto nextzone;
11761 			}
11762 			dns_db_currentversion(dctx->db, &dctx->version);
11763 			result = dns_master_dumptostreamasync(
11764 				dctx->mctx, dctx->db, dctx->version, style,
11765 				dctx->fp, dctx->task, dumpdone, dctx,
11766 				&dctx->mdctx);
11767 			if (result == DNS_R_CONTINUE) {
11768 				return;
11769 			}
11770 			if (result == ISC_R_NOTIMPLEMENTED) {
11771 				fprintf(dctx->fp, "; %s\n",
11772 					isc_result_totext(result));
11773 				result = ISC_R_SUCCESS;
11774 				POST(result);
11775 				goto nextzone;
11776 			}
11777 			if (result != ISC_R_SUCCESS) {
11778 				goto cleanup;
11779 			}
11780 		}
11781 	}
11782 	if (dctx->view != NULL) {
11783 		dctx->view = ISC_LIST_NEXT(dctx->view, link);
11784 		if (dctx->view != NULL) {
11785 			goto nextview;
11786 		}
11787 	}
11788 done:
11789 	fprintf(dctx->fp, "; Dump complete\n");
11790 	result = isc_stdio_flush(dctx->fp);
11791 	if (result == ISC_R_SUCCESS) {
11792 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11793 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11794 			      "dumpdb complete");
11795 	}
11796 cleanup:
11797 	if (result != ISC_R_SUCCESS) {
11798 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11799 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11800 			      "dumpdb failed: %s", isc_result_totext(result));
11801 	}
11802 	dumpcontext_destroy(dctx);
11803 }
11804 
11805 isc_result_t
11806 named_server_dumpdb(named_server_t *server, isc_lex_t *lex,
11807 		    isc_buffer_t **text) {
11808 	struct dumpcontext *dctx = NULL;
11809 	dns_view_t *view;
11810 	isc_result_t result;
11811 	char *ptr;
11812 	const char *sep;
11813 	bool found;
11814 
11815 	REQUIRE(text != NULL);
11816 
11817 	/* Skip the command name. */
11818 	ptr = next_token(lex, NULL);
11819 	if (ptr == NULL) {
11820 		return (ISC_R_UNEXPECTEDEND);
11821 	}
11822 
11823 	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
11824 
11825 	dctx->mctx = server->mctx;
11826 	dctx->dumpcache = true;
11827 	dctx->dumpadb = true;
11828 	dctx->dumpbad = true;
11829 	dctx->dumpexpired = false;
11830 	dctx->dumpfail = true;
11831 	dctx->dumpzones = false;
11832 	dctx->fp = NULL;
11833 	ISC_LIST_INIT(dctx->viewlist);
11834 	dctx->view = NULL;
11835 	dctx->zone = NULL;
11836 	dctx->cache = NULL;
11837 	dctx->mdctx = NULL;
11838 	dctx->db = NULL;
11839 	dctx->cache = NULL;
11840 	dctx->task = NULL;
11841 	dctx->version = NULL;
11842 	isc_task_attach(server->task, &dctx->task);
11843 
11844 	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
11845 		"could not open dump file", server->dumpfile);
11846 
11847 	ptr = next_token(lex, NULL);
11848 	sep = (ptr == NULL) ? "" : ": ";
11849 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11850 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11851 		      "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : "");
11852 
11853 	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
11854 		/* also dump zones */
11855 		dctx->dumpzones = true;
11856 		ptr = next_token(lex, NULL);
11857 	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
11858 		/* this is the default */
11859 		ptr = next_token(lex, NULL);
11860 	} else if (ptr != NULL && strcmp(ptr, "-expired") == 0) {
11861 		/* this is the same as -cache but includes expired data */
11862 		dctx->dumpexpired = true;
11863 		ptr = next_token(lex, NULL);
11864 	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
11865 		/* only dump zones, suppress caches */
11866 		dctx->dumpadb = false;
11867 		dctx->dumpbad = false;
11868 		dctx->dumpcache = false;
11869 		dctx->dumpfail = false;
11870 		dctx->dumpzones = true;
11871 		ptr = next_token(lex, NULL);
11872 	} else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
11873 		/* only dump adb, suppress other caches */
11874 		dctx->dumpbad = false;
11875 		dctx->dumpcache = false;
11876 		dctx->dumpfail = false;
11877 		ptr = next_token(lex, NULL);
11878 	} else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
11879 		/* only dump badcache, suppress other caches */
11880 		dctx->dumpadb = false;
11881 		dctx->dumpcache = false;
11882 		dctx->dumpfail = false;
11883 		ptr = next_token(lex, NULL);
11884 	} else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
11885 		/* only dump servfail cache, suppress other caches */
11886 		dctx->dumpadb = false;
11887 		dctx->dumpbad = false;
11888 		dctx->dumpcache = false;
11889 		ptr = next_token(lex, NULL);
11890 	}
11891 
11892 nextview:
11893 	found = false;
11894 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11895 	     view = ISC_LIST_NEXT(view, link))
11896 	{
11897 		if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11898 			continue;
11899 		}
11900 		found = true;
11901 		CHECK(add_view_tolist(dctx, view));
11902 	}
11903 	if (ptr != NULL) {
11904 		if (!found) {
11905 			CHECK(putstr(text, "view '"));
11906 			CHECK(putstr(text, ptr));
11907 			CHECK(putstr(text, "' not found"));
11908 			CHECK(putnull(text));
11909 			result = ISC_R_NOTFOUND;
11910 			dumpdone(dctx, result);
11911 			return (result);
11912 		}
11913 		ptr = next_token(lex, NULL);
11914 		if (ptr != NULL) {
11915 			goto nextview;
11916 		}
11917 	}
11918 	dumpdone(dctx, ISC_R_SUCCESS);
11919 	return (ISC_R_SUCCESS);
11920 
11921 cleanup:
11922 	dumpcontext_destroy(dctx);
11923 	return (result);
11924 }
11925 
11926 isc_result_t
11927 named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex,
11928 			  isc_buffer_t **text) {
11929 	dns_view_t *view;
11930 	dns_keytable_t *secroots = NULL;
11931 	dns_ntatable_t *ntatable = NULL;
11932 	isc_result_t result;
11933 	char *ptr;
11934 	FILE *fp = NULL;
11935 	isc_time_t now;
11936 	char tbuf[64];
11937 	unsigned int used = isc_buffer_usedlength(*text);
11938 	bool first = true;
11939 
11940 	REQUIRE(text != NULL);
11941 
11942 	/* Skip the command name. */
11943 	ptr = next_token(lex, text);
11944 	if (ptr == NULL) {
11945 		return (ISC_R_UNEXPECTEDEND);
11946 	}
11947 
11948 	/* "-" here means print the output instead of dumping to file */
11949 	ptr = next_token(lex, text);
11950 	if (ptr != NULL && strcmp(ptr, "-") == 0) {
11951 		ptr = next_token(lex, text);
11952 	} else {
11953 		result = isc_stdio_open(server->secrootsfile, "w", &fp);
11954 		if (result != ISC_R_SUCCESS) {
11955 			(void)putstr(text, "could not open ");
11956 			(void)putstr(text, server->secrootsfile);
11957 			CHECKMF(result, "could not open secroots dump file",
11958 				server->secrootsfile);
11959 		}
11960 	}
11961 
11962 	TIME_NOW(&now);
11963 	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
11964 	CHECK(putstr(text, "secure roots as of "));
11965 	CHECK(putstr(text, tbuf));
11966 	CHECK(putstr(text, ":\n"));
11967 	used = isc_buffer_usedlength(*text);
11968 
11969 	do {
11970 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11971 		     view = ISC_LIST_NEXT(view, link))
11972 		{
11973 			if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11974 				continue;
11975 			}
11976 			if (secroots != NULL) {
11977 				dns_keytable_detach(&secroots);
11978 			}
11979 			result = dns_view_getsecroots(view, &secroots);
11980 			if (result == ISC_R_NOTFOUND) {
11981 				result = ISC_R_SUCCESS;
11982 				continue;
11983 			}
11984 			if (first || used != isc_buffer_usedlength(*text)) {
11985 				CHECK(putstr(text, "\n"));
11986 				first = false;
11987 			}
11988 			CHECK(putstr(text, " Start view "));
11989 			CHECK(putstr(text, view->name));
11990 			CHECK(putstr(text, "\n   Secure roots:\n\n"));
11991 			used = isc_buffer_usedlength(*text);
11992 			CHECK(dns_keytable_totext(secroots, text));
11993 
11994 			if (ntatable != NULL) {
11995 				dns_ntatable_detach(&ntatable);
11996 			}
11997 			result = dns_view_getntatable(view, &ntatable);
11998 			if (result == ISC_R_NOTFOUND) {
11999 				result = ISC_R_SUCCESS;
12000 				continue;
12001 			}
12002 			if (used != isc_buffer_usedlength(*text)) {
12003 				CHECK(putstr(text, "\n"));
12004 			}
12005 			CHECK(putstr(text, "   Negative trust anchors:\n\n"));
12006 			used = isc_buffer_usedlength(*text);
12007 			CHECK(dns_ntatable_totext(ntatable, NULL, text));
12008 		}
12009 
12010 		if (ptr != NULL) {
12011 			ptr = next_token(lex, text);
12012 		}
12013 	} while (ptr != NULL);
12014 
12015 cleanup:
12016 	if (secroots != NULL) {
12017 		dns_keytable_detach(&secroots);
12018 	}
12019 	if (ntatable != NULL) {
12020 		dns_ntatable_detach(&ntatable);
12021 	}
12022 
12023 	if (fp != NULL) {
12024 		if (used != isc_buffer_usedlength(*text)) {
12025 			(void)putstr(text, "\n");
12026 		}
12027 		fprintf(fp, "%.*s", (int)isc_buffer_usedlength(*text),
12028 			(char *)isc_buffer_base(*text));
12029 		isc_buffer_clear(*text);
12030 		(void)isc_stdio_close(fp);
12031 	} else if (isc_buffer_usedlength(*text) > 0) {
12032 		(void)putnull(text);
12033 	}
12034 
12035 	if (result == ISC_R_SUCCESS) {
12036 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12037 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12038 			      "dumpsecroots complete");
12039 	} else {
12040 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12041 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12042 			      "dumpsecroots failed: %s",
12043 			      isc_result_totext(result));
12044 	}
12045 	return (result);
12046 }
12047 
12048 isc_result_t
12049 named_server_dumprecursing(named_server_t *server) {
12050 	FILE *fp = NULL;
12051 	dns_view_t *view;
12052 	isc_result_t result;
12053 
12054 	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
12055 		"could not open dump file", server->recfile);
12056 	fprintf(fp, ";\n; Recursing Queries\n;\n");
12057 	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
12058 
12059 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12060 	     view = ISC_LIST_NEXT(view, link))
12061 	{
12062 		fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
12063 			view->name);
12064 		dns_resolver_dumpfetches(view->resolver, isc_statsformat_file,
12065 					 fp);
12066 	}
12067 
12068 	fprintf(fp, "; Dump complete\n");
12069 
12070 cleanup:
12071 	if (fp != NULL) {
12072 		result = isc_stdio_close(fp);
12073 	}
12074 	if (result == ISC_R_SUCCESS) {
12075 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12076 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12077 			      "dumprecursing complete");
12078 	} else {
12079 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12080 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12081 			      "dumprecursing failed: %s",
12082 			      isc_result_totext(result));
12083 	}
12084 	return (result);
12085 }
12086 
12087 isc_result_t
12088 named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
12089 	char *ptr;
12090 	char *endp;
12091 	long newlevel;
12092 
12093 	UNUSED(server);
12094 
12095 	/* Skip the command name. */
12096 	ptr = next_token(lex, NULL);
12097 	if (ptr == NULL) {
12098 		return (ISC_R_UNEXPECTEDEND);
12099 	}
12100 
12101 	/* Look for the new level name. */
12102 	ptr = next_token(lex, NULL);
12103 	if (ptr == NULL) {
12104 		if (named_g_debuglevel < 99) {
12105 			named_g_debuglevel++;
12106 		}
12107 	} else {
12108 		newlevel = strtol(ptr, &endp, 10);
12109 		if (*endp != '\0' || newlevel < 0 || newlevel > 99) {
12110 			return (ISC_R_RANGE);
12111 		}
12112 		named_g_debuglevel = (unsigned int)newlevel;
12113 	}
12114 	isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel);
12115 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12116 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12117 		      "debug level is now %u", named_g_debuglevel);
12118 	return (ISC_R_SUCCESS);
12119 }
12120 
12121 isc_result_t
12122 named_server_validation(named_server_t *server, isc_lex_t *lex,
12123 			isc_buffer_t **text) {
12124 	char *ptr;
12125 	dns_view_t *view;
12126 	bool changed = false;
12127 	isc_result_t result;
12128 	bool enable = true, set = true, first = true;
12129 
12130 	REQUIRE(text != NULL);
12131 
12132 	/* Skip the command name. */
12133 	ptr = next_token(lex, text);
12134 	if (ptr == NULL) {
12135 		return (ISC_R_UNEXPECTEDEND);
12136 	}
12137 
12138 	/* Find out what we are to do. */
12139 	ptr = next_token(lex, text);
12140 	if (ptr == NULL) {
12141 		return (ISC_R_UNEXPECTEDEND);
12142 	}
12143 
12144 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
12145 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
12146 	{
12147 		enable = true;
12148 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
12149 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
12150 	{
12151 		enable = false;
12152 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
12153 		set = false;
12154 	} else {
12155 		return (DNS_R_SYNTAX);
12156 	}
12157 
12158 	/* Look for the view name. */
12159 	ptr = next_token(lex, text);
12160 
12161 	result = isc_task_beginexclusive(server->task);
12162 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12163 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12164 	     view = ISC_LIST_NEXT(view, link))
12165 	{
12166 		if ((ptr != NULL && strcasecmp(ptr, view->name) != 0) ||
12167 		    strcasecmp("_bind", view->name) == 0)
12168 		{
12169 			continue;
12170 		}
12171 
12172 		if (set) {
12173 			CHECK(dns_view_flushcache(view, false));
12174 			view->enablevalidation = enable;
12175 			changed = true;
12176 		} else {
12177 			if (!first) {
12178 				CHECK(putstr(text, "\n"));
12179 			}
12180 			CHECK(putstr(text, "DNSSEC validation is "));
12181 			CHECK(putstr(text, view->enablevalidation
12182 						   ? "enabled"
12183 						   : "disabled"));
12184 			CHECK(putstr(text, " (view "));
12185 			CHECK(putstr(text, view->name));
12186 			CHECK(putstr(text, ")"));
12187 			first = false;
12188 		}
12189 	}
12190 	CHECK(putnull(text));
12191 
12192 	if (!set) {
12193 		result = ISC_R_SUCCESS;
12194 	} else if (changed) {
12195 		result = ISC_R_SUCCESS;
12196 	} else {
12197 		result = ISC_R_FAILURE;
12198 	}
12199 cleanup:
12200 	isc_task_endexclusive(server->task);
12201 	return (result);
12202 }
12203 
12204 isc_result_t
12205 named_server_flushcache(named_server_t *server, isc_lex_t *lex) {
12206 	char *ptr;
12207 	dns_view_t *view;
12208 	bool flushed;
12209 	bool found;
12210 	isc_result_t result;
12211 	named_cache_t *nsc;
12212 
12213 	/* Skip the command name. */
12214 	ptr = next_token(lex, NULL);
12215 	if (ptr == NULL) {
12216 		return (ISC_R_UNEXPECTEDEND);
12217 	}
12218 
12219 	/* Look for the view name. */
12220 	ptr = next_token(lex, NULL);
12221 
12222 	result = isc_task_beginexclusive(server->task);
12223 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12224 	flushed = true;
12225 	found = false;
12226 
12227 	/*
12228 	 * Flushing a cache is tricky when caches are shared by multiple views.
12229 	 * We first identify which caches should be flushed in the local cache
12230 	 * list, flush these caches, and then update other views that refer to
12231 	 * the flushed cache DB.
12232 	 */
12233 	if (ptr != NULL) {
12234 		/*
12235 		 * Mark caches that need to be flushed.  This is an O(#view^2)
12236 		 * operation in the very worst case, but should be normally
12237 		 * much more lightweight because only a few (most typically just
12238 		 * one) views will match.
12239 		 */
12240 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12241 		     view = ISC_LIST_NEXT(view, link))
12242 		{
12243 			if (strcasecmp(ptr, view->name) != 0) {
12244 				continue;
12245 			}
12246 			found = true;
12247 			for (nsc = ISC_LIST_HEAD(server->cachelist);
12248 			     nsc != NULL; nsc = ISC_LIST_NEXT(nsc, link))
12249 			{
12250 				if (nsc->cache == view->cache) {
12251 					break;
12252 				}
12253 			}
12254 			INSIST(nsc != NULL);
12255 			nsc->needflush = true;
12256 		}
12257 	} else {
12258 		found = true;
12259 	}
12260 
12261 	/* Perform flush */
12262 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12263 	     nsc = ISC_LIST_NEXT(nsc, link))
12264 	{
12265 		if (ptr != NULL && !nsc->needflush) {
12266 			continue;
12267 		}
12268 		nsc->needflush = true;
12269 		result = dns_view_flushcache(nsc->primaryview, false);
12270 		if (result != ISC_R_SUCCESS) {
12271 			flushed = false;
12272 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12273 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12274 				      "flushing cache in view '%s' failed: %s",
12275 				      nsc->primaryview->name,
12276 				      isc_result_totext(result));
12277 		}
12278 	}
12279 
12280 	/*
12281 	 * Fix up views that share a flushed cache: let the views update the
12282 	 * cache DB they're referring to.  This could also be an expensive
12283 	 * operation, but should typically be marginal: the inner loop is only
12284 	 * necessary for views that share a cache, and if there are many such
12285 	 * views the number of shared cache should normally be small.
12286 	 * A worst case is that we have n views and n/2 caches, each shared by
12287 	 * two views.  Then this will be a O(n^2/4) operation.
12288 	 */
12289 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12290 	     view = ISC_LIST_NEXT(view, link))
12291 	{
12292 		if (!dns_view_iscacheshared(view)) {
12293 			continue;
12294 		}
12295 		for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12296 		     nsc = ISC_LIST_NEXT(nsc, link))
12297 		{
12298 			if (!nsc->needflush || nsc->cache != view->cache) {
12299 				continue;
12300 			}
12301 			result = dns_view_flushcache(view, true);
12302 			if (result != ISC_R_SUCCESS) {
12303 				flushed = false;
12304 				isc_log_write(
12305 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12306 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12307 					"fixing cache in view '%s' "
12308 					"failed: %s",
12309 					view->name, isc_result_totext(result));
12310 			}
12311 		}
12312 	}
12313 
12314 	/* Cleanup the cache list. */
12315 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12316 	     nsc = ISC_LIST_NEXT(nsc, link))
12317 	{
12318 		nsc->needflush = false;
12319 	}
12320 
12321 	if (flushed && found) {
12322 		if (ptr != NULL) {
12323 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12324 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12325 				      "flushing cache in view '%s' succeeded",
12326 				      ptr);
12327 		} else {
12328 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12329 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12330 				      "flushing caches in all views succeeded");
12331 		}
12332 		result = ISC_R_SUCCESS;
12333 	} else {
12334 		if (!found) {
12335 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12336 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12337 				      "flushing cache in view '%s' failed: "
12338 				      "view not found",
12339 				      ptr);
12340 			result = ISC_R_NOTFOUND;
12341 		} else {
12342 			result = ISC_R_FAILURE;
12343 		}
12344 	}
12345 	isc_task_endexclusive(server->task);
12346 	return (result);
12347 }
12348 
12349 isc_result_t
12350 named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) {
12351 	char *ptr, *viewname;
12352 	char target[DNS_NAME_FORMATSIZE];
12353 	dns_view_t *view;
12354 	bool flushed;
12355 	bool found;
12356 	isc_result_t result;
12357 	isc_buffer_t b;
12358 	dns_fixedname_t fixed;
12359 	dns_name_t *name;
12360 
12361 	/* Skip the command name. */
12362 	ptr = next_token(lex, NULL);
12363 	if (ptr == NULL) {
12364 		return (ISC_R_UNEXPECTEDEND);
12365 	}
12366 
12367 	/* Find the domain name to flush. */
12368 	ptr = next_token(lex, NULL);
12369 	if (ptr == NULL) {
12370 		return (ISC_R_UNEXPECTEDEND);
12371 	}
12372 
12373 	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
12374 	isc_buffer_constinit(&b, target, strlen(target));
12375 	isc_buffer_add(&b, strlen(target));
12376 	name = dns_fixedname_initname(&fixed);
12377 	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
12378 	if (result != ISC_R_SUCCESS) {
12379 		return (result);
12380 	}
12381 
12382 	/* Look for the view name. */
12383 	viewname = next_token(lex, NULL);
12384 
12385 	result = isc_task_beginexclusive(server->task);
12386 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12387 	flushed = true;
12388 	found = false;
12389 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12390 	     view = ISC_LIST_NEXT(view, link))
12391 	{
12392 		if (viewname != NULL && strcasecmp(viewname, view->name) != 0) {
12393 			continue;
12394 		}
12395 		found = true;
12396 		/*
12397 		 * It's a little inefficient to try flushing name for all views
12398 		 * if some of the views share a single cache.  But since the
12399 		 * operation is lightweight we prefer simplicity here.
12400 		 */
12401 		result = dns_view_flushnode(view, name, tree);
12402 		if (result != ISC_R_SUCCESS) {
12403 			flushed = false;
12404 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12405 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12406 				      "flushing %s '%s' in cache view '%s' "
12407 				      "failed: %s",
12408 				      tree ? "tree" : "name", target,
12409 				      view->name, isc_result_totext(result));
12410 		}
12411 	}
12412 	if (flushed && found) {
12413 		if (viewname != NULL) {
12414 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12415 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12416 				      "flushing %s '%s' in cache view '%s' "
12417 				      "succeeded",
12418 				      tree ? "tree" : "name", target, viewname);
12419 		} else {
12420 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12421 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12422 				      "flushing %s '%s' in all cache views "
12423 				      "succeeded",
12424 				      tree ? "tree" : "name", target);
12425 		}
12426 		result = ISC_R_SUCCESS;
12427 	} else {
12428 		if (!found) {
12429 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12430 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12431 				      "flushing %s '%s' in cache view '%s' "
12432 				      "failed: view not found",
12433 				      tree ? "tree" : "name", target, viewname);
12434 		}
12435 		result = ISC_R_FAILURE;
12436 	}
12437 	isc_task_endexclusive(server->task);
12438 	return (result);
12439 }
12440 
12441 isc_result_t
12442 named_server_status(named_server_t *server, isc_buffer_t **text) {
12443 	isc_result_t result;
12444 	unsigned int zonecount, xferrunning, xferdeferred, soaqueries;
12445 	unsigned int automatic;
12446 	const char *ob = "", *cb = "", *alt = "";
12447 	char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
12448 	char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
12449 	char line[1024], hostname[256];
12450 	named_reload_t reload_status;
12451 
12452 	REQUIRE(text != NULL);
12453 
12454 	if (named_g_server->version_set) {
12455 		ob = " (";
12456 		cb = ")";
12457 		if (named_g_server->version == NULL) {
12458 			alt = "version.bind/txt/ch disabled";
12459 		} else {
12460 			alt = named_g_server->version;
12461 		}
12462 	}
12463 	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
12464 	xferrunning = dns_zonemgr_getcount(server->zonemgr,
12465 					   DNS_ZONESTATE_XFERRUNNING);
12466 	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
12467 					    DNS_ZONESTATE_XFERDEFERRED);
12468 	soaqueries = dns_zonemgr_getcount(server->zonemgr,
12469 					  DNS_ZONESTATE_SOAQUERY);
12470 	automatic = dns_zonemgr_getcount(server->zonemgr,
12471 					 DNS_ZONESTATE_AUTOMATIC);
12472 
12473 	isc_time_formathttptimestamp(&named_g_boottime, boottime,
12474 				     sizeof(boottime));
12475 	isc_time_formathttptimestamp(&named_g_configtime, configtime,
12476 				     sizeof(configtime));
12477 
12478 	snprintf(line, sizeof(line), "version: %s%s <id:%s>%s%s%s\n",
12479 		 PACKAGE_STRING, PACKAGE_DESCRIPTION, PACKAGE_SRCID, ob, alt,
12480 		 cb);
12481 	CHECK(putstr(text, line));
12482 
12483 	if (gethostname(hostname, sizeof(hostname)) == 0) {
12484 		strlcpy(hostname, "localhost", sizeof(hostname));
12485 	}
12486 	snprintf(line, sizeof(line), "running on %s: %s\n", hostname,
12487 		 named_os_uname());
12488 	CHECK(putstr(text, line));
12489 
12490 	snprintf(line, sizeof(line), "boot time: %s\n", boottime);
12491 	CHECK(putstr(text, line));
12492 
12493 	snprintf(line, sizeof(line), "last configured: %s\n", configtime);
12494 	CHECK(putstr(text, line));
12495 
12496 	if (named_g_chrootdir != NULL) {
12497 		snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n",
12498 			 named_g_conffile, named_g_chrootdir, named_g_conffile);
12499 	} else {
12500 		snprintf(line, sizeof(line), "configuration file: %s\n",
12501 			 named_g_conffile);
12502 	}
12503 	CHECK(putstr(text, line));
12504 
12505 	snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected);
12506 	CHECK(putstr(text, line));
12507 
12508 	snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
12509 	CHECK(putstr(text, line));
12510 
12511 	snprintf(line, sizeof(line), "UDP listeners per interface: %u\n",
12512 		 named_g_udpdisp);
12513 	CHECK(putstr(text, line));
12514 
12515 	snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
12516 		 zonecount, automatic);
12517 	CHECK(putstr(text, line));
12518 
12519 	snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel);
12520 	CHECK(putstr(text, line));
12521 
12522 	snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
12523 	CHECK(putstr(text, line));
12524 
12525 	snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
12526 	CHECK(putstr(text, line));
12527 
12528 	snprintf(line, sizeof(line), "soa queries in progress: %u\n",
12529 		 soaqueries);
12530 	CHECK(putstr(text, line));
12531 
12532 	snprintf(line, sizeof(line), "query logging is %s\n",
12533 		 ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES)
12534 			 ? "ON"
12535 			 : "OFF");
12536 	CHECK(putstr(text, line));
12537 
12538 	snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
12539 		 isc_quota_getused(&server->sctx->recursionquota),
12540 		 isc_quota_getsoft(&server->sctx->recursionquota),
12541 		 isc_quota_getmax(&server->sctx->recursionquota));
12542 	CHECK(putstr(text, line));
12543 
12544 	snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
12545 		 isc_quota_getused(&server->sctx->tcpquota),
12546 		 isc_quota_getmax(&server->sctx->tcpquota));
12547 	CHECK(putstr(text, line));
12548 
12549 	snprintf(line, sizeof(line), "TCP high-water: %u\n",
12550 		 (unsigned)ns_stats_get_counter(server->sctx->nsstats,
12551 						ns_statscounter_tcphighwater));
12552 	CHECK(putstr(text, line));
12553 
12554 	reload_status = atomic_load(&server->reload_status);
12555 	if (reload_status != NAMED_RELOAD_DONE) {
12556 		snprintf(line, sizeof(line), "reload/reconfig %s\n",
12557 			 (reload_status == NAMED_RELOAD_FAILED
12558 				  ? "failed"
12559 				  : "in progress"));
12560 		CHECK(putstr(text, line));
12561 	}
12562 
12563 	CHECK(putstr(text, "server is up and running"));
12564 	CHECK(putnull(text));
12565 
12566 	return (ISC_R_SUCCESS);
12567 cleanup:
12568 	return (result);
12569 }
12570 
12571 isc_result_t
12572 named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) {
12573 	isc_result_t result;
12574 	char *ptr;
12575 	unsigned long count;
12576 	unsigned long i;
12577 	const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
12578 
12579 	REQUIRE(text != NULL);
12580 
12581 	/* Skip the command name. */
12582 	ptr = next_token(lex, text);
12583 	if (ptr == NULL) {
12584 		return (ISC_R_UNEXPECTEDEND);
12585 	}
12586 
12587 	ptr = next_token(lex, text);
12588 	if (ptr == NULL) {
12589 		count = 26;
12590 	} else {
12591 		count = strtoul(ptr, NULL, 10);
12592 	}
12593 
12594 	CHECK(isc_buffer_reserve(text, count));
12595 	for (i = 0; i < count; i++) {
12596 		CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
12597 	}
12598 
12599 	CHECK(putnull(text));
12600 
12601 cleanup:
12602 	return (result);
12603 }
12604 
12605 static isc_result_t
12606 delete_keynames(dns_tsig_keyring_t *ring, char *target,
12607 		unsigned int *foundkeys) {
12608 	char namestr[DNS_NAME_FORMATSIZE];
12609 	isc_result_t result;
12610 	dns_rbtnodechain_t chain;
12611 	dns_name_t foundname;
12612 	dns_fixedname_t fixedorigin;
12613 	dns_name_t *origin;
12614 	dns_rbtnode_t *node;
12615 	dns_tsigkey_t *tkey;
12616 
12617 	dns_name_init(&foundname, NULL);
12618 	origin = dns_fixedname_initname(&fixedorigin);
12619 
12620 again:
12621 	dns_rbtnodechain_init(&chain);
12622 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12623 	if (result == ISC_R_NOTFOUND) {
12624 		dns_rbtnodechain_invalidate(&chain);
12625 		return (ISC_R_SUCCESS);
12626 	}
12627 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12628 		dns_rbtnodechain_invalidate(&chain);
12629 		return (result);
12630 	}
12631 
12632 	for (;;) {
12633 		node = NULL;
12634 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12635 		tkey = node->data;
12636 
12637 		if (tkey != NULL) {
12638 			if (!tkey->generated) {
12639 				goto nextkey;
12640 			}
12641 
12642 			dns_name_format(&tkey->name, namestr, sizeof(namestr));
12643 			if (strcmp(namestr, target) == 0) {
12644 				(*foundkeys)++;
12645 				dns_rbtnodechain_invalidate(&chain);
12646 				(void)dns_rbt_deletename(ring->keys,
12647 							 &tkey->name, false);
12648 				goto again;
12649 			}
12650 		}
12651 
12652 	nextkey:
12653 		result = dns_rbtnodechain_next(&chain, &foundname, origin);
12654 		if (result == ISC_R_NOMORE) {
12655 			break;
12656 		}
12657 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12658 			dns_rbtnodechain_invalidate(&chain);
12659 			return (result);
12660 		}
12661 	}
12662 
12663 	return (ISC_R_SUCCESS);
12664 }
12665 
12666 isc_result_t
12667 named_server_tsigdelete(named_server_t *server, isc_lex_t *lex,
12668 			isc_buffer_t **text) {
12669 	isc_result_t result;
12670 	dns_view_t *view;
12671 	unsigned int foundkeys = 0;
12672 	char *ptr, *viewname;
12673 	char target[DNS_NAME_FORMATSIZE];
12674 	char fbuf[16];
12675 
12676 	REQUIRE(text != NULL);
12677 
12678 	(void)next_token(lex, text); /* skip command name */
12679 
12680 	ptr = next_token(lex, text);
12681 	if (ptr == NULL) {
12682 		return (ISC_R_UNEXPECTEDEND);
12683 	}
12684 	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
12685 
12686 	viewname = next_token(lex, text);
12687 
12688 	result = isc_task_beginexclusive(server->task);
12689 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12690 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12691 	     view = ISC_LIST_NEXT(view, link))
12692 	{
12693 		if (viewname == NULL || strcmp(view->name, viewname) == 0) {
12694 			RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
12695 			result = delete_keynames(view->dynamickeys, target,
12696 						 &foundkeys);
12697 			RWUNLOCK(&view->dynamickeys->lock,
12698 				 isc_rwlocktype_write);
12699 			if (result != ISC_R_SUCCESS) {
12700 				isc_task_endexclusive(server->task);
12701 				return (result);
12702 			}
12703 		}
12704 	}
12705 	isc_task_endexclusive(server->task);
12706 
12707 	snprintf(fbuf, sizeof(fbuf), "%u", foundkeys);
12708 
12709 	CHECK(putstr(text, fbuf));
12710 	CHECK(putstr(text, " tsig keys deleted."));
12711 	CHECK(putnull(text));
12712 
12713 cleanup:
12714 	return (result);
12715 }
12716 
12717 static isc_result_t
12718 list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t **text,
12719 	      unsigned int *foundkeys) {
12720 	char namestr[DNS_NAME_FORMATSIZE];
12721 	char creatorstr[DNS_NAME_FORMATSIZE];
12722 	isc_result_t result;
12723 	dns_rbtnodechain_t chain;
12724 	dns_name_t foundname;
12725 	dns_fixedname_t fixedorigin;
12726 	dns_name_t *origin;
12727 	dns_rbtnode_t *node;
12728 	dns_tsigkey_t *tkey;
12729 	const char *viewname;
12730 
12731 	if (view != NULL) {
12732 		viewname = view->name;
12733 	} else {
12734 		viewname = "(global)";
12735 	}
12736 
12737 	dns_name_init(&foundname, NULL);
12738 	origin = dns_fixedname_initname(&fixedorigin);
12739 	dns_rbtnodechain_init(&chain);
12740 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12741 	if (result == ISC_R_NOTFOUND) {
12742 		dns_rbtnodechain_invalidate(&chain);
12743 		return (ISC_R_SUCCESS);
12744 	}
12745 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12746 		dns_rbtnodechain_invalidate(&chain);
12747 		return (result);
12748 	}
12749 
12750 	for (;;) {
12751 		node = NULL;
12752 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12753 		tkey = node->data;
12754 
12755 		if (tkey != NULL) {
12756 			dns_name_format(&tkey->name, namestr, sizeof(namestr));
12757 			if (tkey->generated) {
12758 				dns_name_format(tkey->creator, creatorstr,
12759 						sizeof(creatorstr));
12760 				if (*foundkeys != 0) {
12761 					CHECK(putstr(text, "\n"));
12762 				}
12763 				CHECK(putstr(text, "view \""));
12764 				CHECK(putstr(text, viewname));
12765 				CHECK(putstr(text, "\"; type \"dynamic\"; key "
12766 						   "\""));
12767 				CHECK(putstr(text, namestr));
12768 				CHECK(putstr(text, "\"; creator \""));
12769 				CHECK(putstr(text, creatorstr));
12770 				CHECK(putstr(text, "\";"));
12771 			} else {
12772 				if (*foundkeys != 0) {
12773 					CHECK(putstr(text, "\n"));
12774 				}
12775 				CHECK(putstr(text, "view \""));
12776 				CHECK(putstr(text, viewname));
12777 				CHECK(putstr(text, "\"; type \"static\"; key "
12778 						   "\""));
12779 				CHECK(putstr(text, namestr));
12780 				CHECK(putstr(text, "\";"));
12781 			}
12782 			(*foundkeys)++;
12783 		}
12784 		result = dns_rbtnodechain_next(&chain, &foundname, origin);
12785 		if (result == ISC_R_NOMORE || result == DNS_R_NEWORIGIN) {
12786 			break;
12787 		}
12788 	}
12789 
12790 	return (ISC_R_SUCCESS);
12791 cleanup:
12792 	dns_rbtnodechain_invalidate(&chain);
12793 	return (result);
12794 }
12795 
12796 isc_result_t
12797 named_server_tsiglist(named_server_t *server, isc_buffer_t **text) {
12798 	isc_result_t result = ISC_R_SUCCESS;
12799 	dns_view_t *view;
12800 	unsigned int foundkeys = 0;
12801 
12802 	REQUIRE(text != NULL);
12803 
12804 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12805 	     view = ISC_LIST_NEXT(view, link))
12806 	{
12807 		RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12808 		result = list_keynames(view, view->statickeys, text,
12809 				       &foundkeys);
12810 		RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12811 		if (result != ISC_R_SUCCESS) {
12812 			return (result);
12813 		}
12814 		RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12815 		result = list_keynames(view, view->dynamickeys, text,
12816 				       &foundkeys);
12817 		RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12818 		if (result != ISC_R_SUCCESS) {
12819 			return (result);
12820 		}
12821 	}
12822 
12823 	if (foundkeys == 0) {
12824 		CHECK(putstr(text, "no tsig keys found."));
12825 	}
12826 
12827 	if (isc_buffer_usedlength(*text) > 0) {
12828 		CHECK(putnull(text));
12829 	}
12830 
12831 cleanup:
12832 	return (result);
12833 }
12834 
12835 /*
12836  * Act on a "sign" or "loadkeys" command from the command channel.
12837  */
12838 isc_result_t
12839 named_server_rekey(named_server_t *server, isc_lex_t *lex,
12840 		   isc_buffer_t **text) {
12841 	isc_result_t result;
12842 	dns_zone_t *zone = NULL;
12843 	dns_zonetype_t type;
12844 	uint16_t keyopts;
12845 	bool fullsign = false;
12846 	char *ptr;
12847 
12848 	REQUIRE(text != NULL);
12849 
12850 	ptr = next_token(lex, text);
12851 	if (ptr == NULL) {
12852 		return (ISC_R_UNEXPECTEDEND);
12853 	}
12854 
12855 	if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0) {
12856 		fullsign = true;
12857 	}
12858 
12859 	REQUIRE(text != NULL);
12860 
12861 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, false);
12862 	if (result != ISC_R_SUCCESS) {
12863 		return (result);
12864 	}
12865 	if (zone == NULL) {
12866 		return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */
12867 	}
12868 
12869 	type = dns_zone_gettype(zone);
12870 	if (type != dns_zone_primary) {
12871 		dns_zone_detach(&zone);
12872 		return (DNS_R_NOTPRIMARY);
12873 	}
12874 
12875 	keyopts = dns_zone_getkeyopts(zone);
12876 
12877 	/*
12878 	 * "rndc loadkeys" requires "auto-dnssec maintain"
12879 	 * or a "dnssec-policy".
12880 	 */
12881 	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) {
12882 		result = ISC_R_NOPERM;
12883 	} else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) {
12884 		result = ISC_R_NOPERM;
12885 	} else {
12886 		dns_zone_rekey(zone, fullsign);
12887 	}
12888 
12889 	dns_zone_detach(&zone);
12890 	return (result);
12891 }
12892 
12893 /*
12894  * Act on a "sync" command from the command channel.
12895  */
12896 static isc_result_t
12897 synczone(dns_zone_t *zone, void *uap) {
12898 	bool cleanup = *(bool *)uap;
12899 	isc_result_t result;
12900 	dns_zone_t *raw = NULL;
12901 	char *journal;
12902 
12903 	dns_zone_getraw(zone, &raw);
12904 	if (raw != NULL) {
12905 		synczone(raw, uap);
12906 		dns_zone_detach(&raw);
12907 	}
12908 
12909 	result = dns_zone_flush(zone);
12910 	if (result != ISC_R_SUCCESS) {
12911 		cleanup = false;
12912 	}
12913 	if (cleanup) {
12914 		journal = dns_zone_getjournal(zone);
12915 		if (journal != NULL) {
12916 			(void)isc_file_remove(journal);
12917 		}
12918 	}
12919 
12920 	return (result);
12921 }
12922 
12923 isc_result_t
12924 named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
12925 	isc_result_t result, tresult;
12926 	dns_view_t *view;
12927 	dns_zone_t *zone = NULL;
12928 	char classstr[DNS_RDATACLASS_FORMATSIZE];
12929 	char zonename[DNS_NAME_FORMATSIZE];
12930 	const char *vname, *sep, *arg;
12931 	bool cleanup = false;
12932 
12933 	REQUIRE(text != NULL);
12934 
12935 	(void)next_token(lex, text);
12936 
12937 	arg = next_token(lex, text);
12938 	if (arg != NULL &&
12939 	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0))
12940 	{
12941 		cleanup = true;
12942 		arg = next_token(lex, text);
12943 	}
12944 
12945 	REQUIRE(text != NULL);
12946 
12947 	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
12948 	if (result != ISC_R_SUCCESS) {
12949 		return (result);
12950 	}
12951 
12952 	if (zone == NULL) {
12953 		result = isc_task_beginexclusive(server->task);
12954 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
12955 		tresult = ISC_R_SUCCESS;
12956 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12957 		     view = ISC_LIST_NEXT(view, link))
12958 		{
12959 			result = dns_zt_apply(view->zonetable,
12960 					      isc_rwlocktype_none, false, NULL,
12961 					      synczone, &cleanup);
12962 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12963 			{
12964 				tresult = result;
12965 			}
12966 		}
12967 		isc_task_endexclusive(server->task);
12968 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12969 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12970 			      "dumping all zones%s: %s",
12971 			      cleanup ? ", removing journal files" : "",
12972 			      isc_result_totext(result));
12973 		return (tresult);
12974 	}
12975 
12976 	result = isc_task_beginexclusive(server->task);
12977 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12978 	result = synczone(zone, &cleanup);
12979 	isc_task_endexclusive(server->task);
12980 
12981 	view = dns_zone_getview(zone);
12982 	if (strcmp(view->name, "_default") == 0 ||
12983 	    strcmp(view->name, "_bind") == 0)
12984 	{
12985 		vname = "";
12986 		sep = "";
12987 	} else {
12988 		vname = view->name;
12989 		sep = " ";
12990 	}
12991 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
12992 			      sizeof(classstr));
12993 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
12994 	isc_log_write(
12995 		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12996 		ISC_LOG_INFO, "sync: dumping zone '%s/%s'%s%s%s: %s", zonename,
12997 		classstr, sep, vname, cleanup ? ", removing journal file" : "",
12998 		isc_result_totext(result));
12999 	dns_zone_detach(&zone);
13000 	return (result);
13001 }
13002 
13003 /*
13004  * Act on a "freeze" or "thaw" command from the command channel.
13005  */
13006 isc_result_t
13007 named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex,
13008 		    isc_buffer_t **text) {
13009 	isc_result_t result, tresult;
13010 	dns_zone_t *mayberaw = NULL, *raw = NULL;
13011 	dns_zonetype_t type;
13012 	char classstr[DNS_RDATACLASS_FORMATSIZE];
13013 	char zonename[DNS_NAME_FORMATSIZE];
13014 	dns_view_t *view;
13015 	const char *vname, *sep;
13016 	bool frozen;
13017 	const char *msg = NULL;
13018 
13019 	REQUIRE(text != NULL);
13020 
13021 	result = zone_from_args(server, lex, NULL, &mayberaw, NULL, text, true);
13022 	if (result != ISC_R_SUCCESS) {
13023 		return (result);
13024 	}
13025 	if (mayberaw == NULL) {
13026 		result = isc_task_beginexclusive(server->task);
13027 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
13028 		tresult = ISC_R_SUCCESS;
13029 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
13030 		     view = ISC_LIST_NEXT(view, link))
13031 		{
13032 			result = dns_view_freezezones(view, freeze);
13033 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
13034 			{
13035 				tresult = result;
13036 			}
13037 		}
13038 		isc_task_endexclusive(server->task);
13039 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13040 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13041 			      "%s all zones: %s",
13042 			      freeze ? "freezing" : "thawing",
13043 			      isc_result_totext(tresult));
13044 		return (tresult);
13045 	}
13046 	dns_zone_getraw(mayberaw, &raw);
13047 	if (raw != NULL) {
13048 		dns_zone_detach(&mayberaw);
13049 		dns_zone_attach(raw, &mayberaw);
13050 		dns_zone_detach(&raw);
13051 	}
13052 	type = dns_zone_gettype(mayberaw);
13053 	if (type != dns_zone_primary) {
13054 		dns_zone_detach(&mayberaw);
13055 		return (DNS_R_NOTPRIMARY);
13056 	}
13057 
13058 	if (freeze && !dns_zone_isdynamic(mayberaw, true)) {
13059 		dns_zone_detach(&mayberaw);
13060 		return (DNS_R_NOTDYNAMIC);
13061 	}
13062 
13063 	result = isc_task_beginexclusive(server->task);
13064 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
13065 	frozen = dns_zone_getupdatedisabled(mayberaw);
13066 	if (freeze) {
13067 		if (frozen) {
13068 			msg = "WARNING: The zone was already frozen.\n"
13069 			      "Someone else may be editing it or "
13070 			      "it may still be re-loading.";
13071 			result = DNS_R_FROZEN;
13072 		}
13073 		if (result == ISC_R_SUCCESS) {
13074 			result = dns_zone_flush(mayberaw);
13075 			if (result != ISC_R_SUCCESS) {
13076 				msg = "Flushing the zone updates to "
13077 				      "disk failed.";
13078 			}
13079 		}
13080 		if (result == ISC_R_SUCCESS) {
13081 			dns_zone_setupdatedisabled(mayberaw, freeze);
13082 		}
13083 	} else {
13084 		if (frozen) {
13085 			result = dns_zone_loadandthaw(mayberaw);
13086 			switch (result) {
13087 			case ISC_R_SUCCESS:
13088 			case DNS_R_UPTODATE:
13089 				msg = "The zone reload and thaw was "
13090 				      "successful.";
13091 				result = ISC_R_SUCCESS;
13092 				break;
13093 			case DNS_R_CONTINUE:
13094 				msg = "A zone reload and thaw was started.\n"
13095 				      "Check the logs to see the result.";
13096 				result = ISC_R_SUCCESS;
13097 				break;
13098 			default:
13099 				break;
13100 			}
13101 		}
13102 	}
13103 	isc_task_endexclusive(server->task);
13104 
13105 	if (msg != NULL) {
13106 		(void)putstr(text, msg);
13107 		(void)putnull(text);
13108 	}
13109 
13110 	view = dns_zone_getview(mayberaw);
13111 	if (strcmp(view->name, "_default") == 0 ||
13112 	    strcmp(view->name, "_bind") == 0)
13113 	{
13114 		vname = "";
13115 		sep = "";
13116 	} else {
13117 		vname = view->name;
13118 		sep = " ";
13119 	}
13120 	dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr,
13121 			      sizeof(classstr));
13122 	dns_name_format(dns_zone_getorigin(mayberaw), zonename,
13123 			sizeof(zonename));
13124 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13125 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13126 		      "%s zone '%s/%s'%s%s: %s",
13127 		      freeze ? "freezing" : "thawing", zonename, classstr, sep,
13128 		      vname, isc_result_totext(result));
13129 	dns_zone_detach(&mayberaw);
13130 	return (result);
13131 }
13132 
13133 #ifdef HAVE_LIBSCF
13134 /*
13135  * This function adds a message for rndc to echo if named
13136  * is managed by smf and is also running chroot.
13137  */
13138 isc_result_t
13139 named_smf_add_message(isc_buffer_t **text) {
13140 	REQUIRE(text != NULL);
13141 
13142 	return (putstr(text, "use svcadm(1M) to manage named"));
13143 }
13144 #endif /* HAVE_LIBSCF */
13145 
13146 #ifndef HAVE_LMDB
13147 
13148 /*
13149  * Emit a comment at the top of the nzf file containing the viewname
13150  * Expects the fp to already be open for writing
13151  */
13152 #define HEADER1 "# New zone file for view: "
13153 #define HEADER2                                                     \
13154 	"\n# This file contains configuration for zones added by\n" \
13155 	"# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
13156 static isc_result_t
13157 add_comment(FILE *fp, const char *viewname) {
13158 	isc_result_t result;
13159 	CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
13160 	CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
13161 	CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
13162 cleanup:
13163 	return (result);
13164 }
13165 
13166 static void
13167 dumpzone(void *arg, const char *buf, int len) {
13168 	FILE *fp = arg;
13169 
13170 	(void)isc_stdio_write(buf, len, 1, fp, NULL);
13171 }
13172 
13173 static isc_result_t
13174 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
13175 	isc_result_t result;
13176 	off_t offset;
13177 	FILE *fp = NULL;
13178 	bool offsetok = false;
13179 
13180 	LOCK(&view->new_zone_lock);
13181 
13182 	CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
13183 	CHECK(isc_stdio_seek(fp, 0, SEEK_END));
13184 
13185 	CHECK(isc_stdio_tell(fp, &offset));
13186 	offsetok = true;
13187 	if (offset == 0) {
13188 		CHECK(add_comment(fp, view->name));
13189 	}
13190 
13191 	CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
13192 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
13193 	CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
13194 	CHECK(isc_stdio_flush(fp));
13195 	result = isc_stdio_close(fp);
13196 	fp = NULL;
13197 
13198 cleanup:
13199 	if (fp != NULL) {
13200 		(void)isc_stdio_close(fp);
13201 		if (offsetok) {
13202 			isc_result_t result2;
13203 
13204 			result2 = isc_file_truncate(view->new_zone_file,
13205 						    offset);
13206 			if (result2 != ISC_R_SUCCESS) {
13207 				isc_log_write(
13208 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13209 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13210 					"Error truncating NZF file '%s' "
13211 					"during rollback from append: "
13212 					"%s",
13213 					view->new_zone_file,
13214 					isc_result_totext(result2));
13215 			}
13216 		}
13217 	}
13218 	UNLOCK(&view->new_zone_lock);
13219 	return (result);
13220 }
13221 
13222 static isc_result_t
13223 nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
13224 	const cfg_obj_t *zl = NULL;
13225 	cfg_list_t *list;
13226 	const cfg_listelt_t *elt;
13227 
13228 	FILE *fp = NULL;
13229 	char tmp[1024];
13230 	isc_result_t result;
13231 
13232 	result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp,
13233 				   sizeof(tmp));
13234 	if (result == ISC_R_SUCCESS) {
13235 		result = isc_file_openunique(tmp, &fp);
13236 	}
13237 	if (result != ISC_R_SUCCESS) {
13238 		return (result);
13239 	}
13240 
13241 	cfg_map_get(config, "zone", &zl);
13242 	if (!cfg_obj_islist(zl)) {
13243 		CHECK(ISC_R_FAILURE);
13244 	}
13245 
13246 	DE_CONST(&zl->value.list, list);
13247 
13248 	CHECK(add_comment(fp, view->name)); /* force a comment */
13249 
13250 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13251 	     elt = ISC_LIST_NEXT(elt, link))
13252 	{
13253 		const cfg_obj_t *zconfig = cfg_listelt_value(elt);
13254 
13255 		CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
13256 		cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
13257 		CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
13258 	}
13259 
13260 	CHECK(isc_stdio_flush(fp));
13261 	result = isc_stdio_close(fp);
13262 	fp = NULL;
13263 	if (result != ISC_R_SUCCESS) {
13264 		goto cleanup;
13265 	}
13266 	CHECK(isc_file_rename(tmp, view->new_zone_file));
13267 	return (result);
13268 
13269 cleanup:
13270 	if (fp != NULL) {
13271 		(void)isc_stdio_close(fp);
13272 	}
13273 	(void)isc_file_remove(tmp);
13274 	return (result);
13275 }
13276 
13277 #else /* HAVE_LMDB */
13278 
13279 static void
13280 nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
13281 	dns_fixedname_t fixed;
13282 
13283 	dns_fixedname_init(&fixed);
13284 	dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
13285 	dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
13286 
13287 	key->mv_data = namebuf;
13288 	key->mv_size = strlen(namebuf);
13289 }
13290 
13291 static void
13292 dumpzone(void *arg, const char *buf, int len) {
13293 	ns_dzarg_t *dzarg = arg;
13294 	isc_result_t result;
13295 
13296 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
13297 
13298 	result = putmem(dzarg->text, buf, len);
13299 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
13300 		dzarg->result = result;
13301 	}
13302 }
13303 
13304 static isc_result_t
13305 nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
13306 	 const cfg_obj_t *zconfig) {
13307 	isc_result_t result;
13308 	int status;
13309 	dns_view_t *view;
13310 	bool commit = false;
13311 	isc_buffer_t *text = NULL;
13312 	char namebuf[1024];
13313 	MDB_val key, data;
13314 	ns_dzarg_t dzarg;
13315 
13316 	view = dns_zone_getview(zone);
13317 
13318 	nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
13319 
13320 	if (zconfig == NULL) {
13321 		/* We're deleting the zone from the database */
13322 		status = mdb_del(*txnp, dbi, &key, NULL);
13323 		if (status != MDB_SUCCESS && status != MDB_NOTFOUND) {
13324 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13325 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13326 				      "Error deleting zone %s "
13327 				      "from NZD database: %s",
13328 				      namebuf, mdb_strerror(status));
13329 			result = ISC_R_FAILURE;
13330 			goto cleanup;
13331 		} else if (status != MDB_NOTFOUND) {
13332 			commit = true;
13333 		}
13334 	} else {
13335 		/* We're creating or overwriting the zone */
13336 		const cfg_obj_t *zoptions;
13337 
13338 		isc_buffer_allocate(view->mctx, &text, 256);
13339 
13340 		zoptions = cfg_tuple_get(zconfig, "options");
13341 		if (zoptions == NULL) {
13342 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13343 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13344 				      "Unable to get options from config in "
13345 				      "nzd_save()");
13346 			result = ISC_R_FAILURE;
13347 			goto cleanup;
13348 		}
13349 
13350 		dzarg.magic = DZARG_MAGIC;
13351 		dzarg.text = &text;
13352 		dzarg.result = ISC_R_SUCCESS;
13353 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13354 		if (dzarg.result != ISC_R_SUCCESS) {
13355 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13356 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13357 				      "Error writing zone config to "
13358 				      "buffer in nzd_save(): %s",
13359 				      isc_result_totext(dzarg.result));
13360 			result = dzarg.result;
13361 			goto cleanup;
13362 		}
13363 
13364 		data.mv_data = isc_buffer_base(text);
13365 		data.mv_size = isc_buffer_usedlength(text);
13366 
13367 		status = mdb_put(*txnp, dbi, &key, &data, 0);
13368 		if (status != MDB_SUCCESS) {
13369 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13370 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13371 				      "Error inserting zone in "
13372 				      "NZD database: %s",
13373 				      mdb_strerror(status));
13374 			result = ISC_R_FAILURE;
13375 			goto cleanup;
13376 		}
13377 
13378 		commit = true;
13379 	}
13380 
13381 	result = ISC_R_SUCCESS;
13382 
13383 cleanup:
13384 	if (!commit || result != ISC_R_SUCCESS) {
13385 		(void)mdb_txn_abort(*txnp);
13386 	} else {
13387 		status = mdb_txn_commit(*txnp);
13388 		if (status != MDB_SUCCESS) {
13389 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13390 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13391 				      "Error committing "
13392 				      "NZD database: %s",
13393 				      mdb_strerror(status));
13394 			result = ISC_R_FAILURE;
13395 		}
13396 	}
13397 	*txnp = NULL;
13398 
13399 	if (text != NULL) {
13400 		isc_buffer_free(&text);
13401 	}
13402 
13403 	return (result);
13404 }
13405 
13406 /*
13407  * Check whether the new zone database for 'view' can be opened for writing.
13408  *
13409  * Caller must hold 'view->new_zone_lock'.
13410  */
13411 static isc_result_t
13412 nzd_writable(dns_view_t *view) {
13413 	isc_result_t result = ISC_R_SUCCESS;
13414 	int status;
13415 	MDB_dbi dbi;
13416 	MDB_txn *txn = NULL;
13417 
13418 	REQUIRE(view != NULL);
13419 
13420 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn);
13421 	if (status != MDB_SUCCESS) {
13422 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13423 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13424 			      "mdb_txn_begin: %s", mdb_strerror(status));
13425 		return (ISC_R_FAILURE);
13426 	}
13427 
13428 	status = mdb_dbi_open(txn, NULL, 0, &dbi);
13429 	if (status != MDB_SUCCESS) {
13430 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13431 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13432 			      "mdb_dbi_open: %s", mdb_strerror(status));
13433 		result = ISC_R_FAILURE;
13434 	}
13435 
13436 	mdb_txn_abort(txn);
13437 	return (result);
13438 }
13439 
13440 /*
13441  * Open the new zone database for 'view' and start a transaction for it.
13442  *
13443  * Caller must hold 'view->new_zone_lock'.
13444  */
13445 static isc_result_t
13446 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
13447 	int status;
13448 	MDB_txn *txn = NULL;
13449 
13450 	REQUIRE(view != NULL);
13451 	REQUIRE(txnp != NULL && *txnp == NULL);
13452 	REQUIRE(dbi != NULL);
13453 
13454 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn);
13455 	if (status != MDB_SUCCESS) {
13456 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13457 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13458 			      "mdb_txn_begin: %s", mdb_strerror(status));
13459 		goto cleanup;
13460 	}
13461 
13462 	status = mdb_dbi_open(txn, NULL, 0, dbi);
13463 	if (status != MDB_SUCCESS) {
13464 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13465 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13466 			      "mdb_dbi_open: %s", mdb_strerror(status));
13467 		goto cleanup;
13468 	}
13469 
13470 	*txnp = txn;
13471 
13472 cleanup:
13473 	if (status != MDB_SUCCESS) {
13474 		if (txn != NULL) {
13475 			mdb_txn_abort(txn);
13476 		}
13477 		return (ISC_R_FAILURE);
13478 	}
13479 
13480 	return (ISC_R_SUCCESS);
13481 }
13482 
13483 /*
13484  * nzd_env_close() and nzd_env_reopen are a kluge to address the
13485  * problem of an NZD file possibly being created before we drop
13486  * root privileges.
13487  */
13488 static void
13489 nzd_env_close(dns_view_t *view) {
13490 	const char *dbpath = NULL;
13491 	char dbpath_copy[PATH_MAX];
13492 	char lockpath[PATH_MAX];
13493 	int status, ret;
13494 
13495 	if (view->new_zone_dbenv == NULL) {
13496 		return;
13497 	}
13498 
13499 	status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
13500 	INSIST(status == MDB_SUCCESS);
13501 	snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
13502 	strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
13503 	mdb_env_close((MDB_env *)view->new_zone_dbenv);
13504 
13505 	/*
13506 	 * Database files must be owned by the eventual user, not by root.
13507 	 */
13508 	ret = chown(dbpath_copy, ns_os_uid(), -1);
13509 	UNUSED(ret);
13510 
13511 	/*
13512 	 * Some platforms need the lockfile not to exist when we reopen the
13513 	 * environment.
13514 	 */
13515 	(void)isc_file_remove(lockpath);
13516 
13517 	view->new_zone_dbenv = NULL;
13518 }
13519 
13520 static isc_result_t
13521 nzd_env_reopen(dns_view_t *view) {
13522 	isc_result_t result;
13523 	MDB_env *env = NULL;
13524 	int status;
13525 
13526 	if (view->new_zone_db == NULL) {
13527 		return (ISC_R_SUCCESS);
13528 	}
13529 
13530 	nzd_env_close(view);
13531 
13532 	status = mdb_env_create(&env);
13533 	if (status != MDB_SUCCESS) {
13534 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13535 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13536 			      "mdb_env_create failed: %s",
13537 			      mdb_strerror(status));
13538 		CHECK(ISC_R_FAILURE);
13539 	}
13540 
13541 	if (view->new_zone_mapsize != 0ULL) {
13542 		status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
13543 		if (status != MDB_SUCCESS) {
13544 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13545 				      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13546 				      "mdb_env_set_mapsize failed: %s",
13547 				      mdb_strerror(status));
13548 			CHECK(ISC_R_FAILURE);
13549 		}
13550 	}
13551 
13552 	status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
13553 	if (status != MDB_SUCCESS) {
13554 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13555 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13556 			      "mdb_env_open of '%s' failed: %s",
13557 			      view->new_zone_db, mdb_strerror(status));
13558 		CHECK(ISC_R_FAILURE);
13559 	}
13560 
13561 	view->new_zone_dbenv = env;
13562 	env = NULL;
13563 	result = ISC_R_SUCCESS;
13564 
13565 cleanup:
13566 	if (env != NULL) {
13567 		mdb_env_close(env);
13568 	}
13569 	return (result);
13570 }
13571 
13572 /*
13573  * If 'commit' is true, commit the new zone database transaction pointed to by
13574  * 'txnp'; otherwise, abort that transaction.
13575  *
13576  * Caller must hold 'view->new_zone_lock' for the view that the transaction
13577  * pointed to by 'txnp' was started for.
13578  */
13579 static isc_result_t
13580 nzd_close(MDB_txn **txnp, bool commit) {
13581 	isc_result_t result = ISC_R_SUCCESS;
13582 	int status;
13583 
13584 	REQUIRE(txnp != NULL);
13585 
13586 	if (*txnp != NULL) {
13587 		if (commit) {
13588 			status = mdb_txn_commit(*txnp);
13589 			if (status != MDB_SUCCESS) {
13590 				result = ISC_R_FAILURE;
13591 			}
13592 		} else {
13593 			mdb_txn_abort(*txnp);
13594 		}
13595 		*txnp = NULL;
13596 	}
13597 
13598 	return (result);
13599 }
13600 
13601 /*
13602  * Count the zones configured in the new zone database for 'view' and store the
13603  * result in 'countp'.
13604  *
13605  * Caller must hold 'view->new_zone_lock'.
13606  */
13607 static isc_result_t
13608 nzd_count(dns_view_t *view, int *countp) {
13609 	isc_result_t result;
13610 	int status;
13611 	MDB_txn *txn = NULL;
13612 	MDB_dbi dbi;
13613 	MDB_stat statbuf;
13614 
13615 	REQUIRE(countp != NULL);
13616 
13617 	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
13618 	if (result != ISC_R_SUCCESS) {
13619 		goto cleanup;
13620 	}
13621 
13622 	status = mdb_stat(txn, dbi, &statbuf);
13623 	if (status != MDB_SUCCESS) {
13624 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13625 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13626 			      "mdb_stat: %s", mdb_strerror(status));
13627 		result = ISC_R_FAILURE;
13628 		goto cleanup;
13629 	}
13630 
13631 	*countp = statbuf.ms_entries;
13632 
13633 cleanup:
13634 	(void)nzd_close(&txn, false);
13635 
13636 	return (result);
13637 }
13638 
13639 /*
13640  * Migrate zone configuration from an NZF file to an NZD database.
13641  * Caller must hold view->new_zone_lock.
13642  */
13643 static isc_result_t
13644 migrate_nzf(dns_view_t *view) {
13645 	isc_result_t result;
13646 	cfg_obj_t *nzf_config = NULL;
13647 	int status, n;
13648 	isc_buffer_t *text = NULL;
13649 	bool commit = false;
13650 	const cfg_obj_t *zonelist;
13651 	const cfg_listelt_t *element;
13652 	char tempname[PATH_MAX];
13653 	MDB_txn *txn = NULL;
13654 	MDB_dbi dbi;
13655 	MDB_val key, data;
13656 	ns_dzarg_t dzarg;
13657 
13658 	/*
13659 	 * If NZF file doesn't exist, or NZD DB exists and already
13660 	 * has data, return without attempting migration.
13661 	 */
13662 	if (!isc_file_exists(view->new_zone_file)) {
13663 		result = ISC_R_SUCCESS;
13664 		goto cleanup;
13665 	}
13666 
13667 	result = nzd_count(view, &n);
13668 	if (result == ISC_R_SUCCESS && n > 0) {
13669 		result = ISC_R_SUCCESS;
13670 		goto cleanup;
13671 	}
13672 
13673 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13674 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13675 		      "Migrating zones from NZF file '%s' to "
13676 		      "NZD database '%s'",
13677 		      view->new_zone_file, view->new_zone_db);
13678 	/*
13679 	 * Instead of blindly copying lines, we parse the NZF file using
13680 	 * the configuration parser, because it validates it against the
13681 	 * config type, giving us a guarantee that valid configuration
13682 	 * will be written to DB.
13683 	 */
13684 	cfg_parser_reset(named_g_addparser);
13685 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
13686 				&cfg_type_addzoneconf, &nzf_config);
13687 	if (result != ISC_R_SUCCESS) {
13688 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13689 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13690 			      "Error parsing NZF file '%s': %s",
13691 			      view->new_zone_file, isc_result_totext(result));
13692 		goto cleanup;
13693 	}
13694 
13695 	zonelist = NULL;
13696 	CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
13697 	if (!cfg_obj_islist(zonelist)) {
13698 		CHECK(ISC_R_FAILURE);
13699 	}
13700 
13701 	CHECK(nzd_open(view, 0, &txn, &dbi));
13702 
13703 	isc_buffer_allocate(view->mctx, &text, 256);
13704 
13705 	for (element = cfg_list_first(zonelist); element != NULL;
13706 	     element = cfg_list_next(element))
13707 	{
13708 		const cfg_obj_t *zconfig;
13709 		const cfg_obj_t *zoptions;
13710 		char zname[DNS_NAME_FORMATSIZE];
13711 		dns_fixedname_t fname;
13712 		dns_name_t *name;
13713 		const char *origin;
13714 		isc_buffer_t b;
13715 
13716 		zconfig = cfg_listelt_value(element);
13717 
13718 		origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
13719 		if (origin == NULL) {
13720 			result = ISC_R_FAILURE;
13721 			goto cleanup;
13722 		}
13723 
13724 		/* Normalize zone name */
13725 		isc_buffer_constinit(&b, origin, strlen(origin));
13726 		isc_buffer_add(&b, strlen(origin));
13727 		name = dns_fixedname_initname(&fname);
13728 		CHECK(dns_name_fromtext(name, &b, dns_rootname,
13729 					DNS_NAME_DOWNCASE, NULL));
13730 		dns_name_format(name, zname, sizeof(zname));
13731 
13732 		key.mv_data = zname;
13733 		key.mv_size = strlen(zname);
13734 
13735 		zoptions = cfg_tuple_get(zconfig, "options");
13736 		if (zoptions == NULL) {
13737 			result = ISC_R_FAILURE;
13738 			goto cleanup;
13739 		}
13740 
13741 		isc_buffer_clear(text);
13742 		dzarg.magic = DZARG_MAGIC;
13743 		dzarg.text = &text;
13744 		dzarg.result = ISC_R_SUCCESS;
13745 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13746 		if (dzarg.result != ISC_R_SUCCESS) {
13747 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13748 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13749 				      "Error writing zone config to "
13750 				      "buffer in migrate_nzf(): %s",
13751 				      isc_result_totext(result));
13752 			result = dzarg.result;
13753 			goto cleanup;
13754 		}
13755 
13756 		data.mv_data = isc_buffer_base(text);
13757 		data.mv_size = isc_buffer_usedlength(text);
13758 
13759 		status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
13760 		if (status != MDB_SUCCESS) {
13761 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13762 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13763 				      "Error inserting zone in "
13764 				      "NZD database: %s",
13765 				      mdb_strerror(status));
13766 			result = ISC_R_FAILURE;
13767 			goto cleanup;
13768 		}
13769 
13770 		commit = true;
13771 	}
13772 
13773 	result = ISC_R_SUCCESS;
13774 
13775 	/*
13776 	 * Leaving the NZF file in place is harmless as we won't use it
13777 	 * if an NZD database is found for the view. But we rename NZF file
13778 	 * to a backup name here.
13779 	 */
13780 	strlcpy(tempname, view->new_zone_file, sizeof(tempname));
13781 	if (strlen(tempname) < sizeof(tempname) - 1) {
13782 		strlcat(tempname, "~", sizeof(tempname));
13783 		isc_file_rename(view->new_zone_file, tempname);
13784 	}
13785 
13786 cleanup:
13787 	if (result != ISC_R_SUCCESS) {
13788 		(void)nzd_close(&txn, false);
13789 	} else {
13790 		result = nzd_close(&txn, commit);
13791 	}
13792 
13793 	if (text != NULL) {
13794 		isc_buffer_free(&text);
13795 	}
13796 
13797 	if (nzf_config != NULL) {
13798 		cfg_obj_destroy(named_g_addparser, &nzf_config);
13799 	}
13800 
13801 	return (result);
13802 }
13803 
13804 #endif /* HAVE_LMDB */
13805 
13806 static isc_result_t
13807 newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
13808 	      cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
13809 	      bool *redirectp, isc_buffer_t **text) {
13810 	isc_result_t result;
13811 	isc_buffer_t argbuf;
13812 	bool redirect = false;
13813 	cfg_obj_t *zoneconf = NULL;
13814 	const cfg_obj_t *zlist = NULL;
13815 	const cfg_obj_t *zoneobj = NULL;
13816 	const cfg_obj_t *zoptions = NULL;
13817 	const cfg_obj_t *obj = NULL;
13818 	const char *viewname = NULL;
13819 	dns_rdataclass_t rdclass;
13820 	dns_view_t *view = NULL;
13821 	const char *bn = NULL;
13822 
13823 	REQUIRE(viewp != NULL && *viewp == NULL);
13824 	REQUIRE(zoneobjp != NULL && *zoneobjp == NULL);
13825 	REQUIRE(zoneconfp != NULL && *zoneconfp == NULL);
13826 	REQUIRE(redirectp != NULL);
13827 
13828 	/* Try to parse the argument string */
13829 	isc_buffer_init(&argbuf, command, (unsigned int)strlen(command));
13830 	isc_buffer_add(&argbuf, strlen(command));
13831 
13832 	if (strncasecmp(command, "add", 3) == 0) {
13833 		bn = "addzone";
13834 	} else if (strncasecmp(command, "mod", 3) == 0) {
13835 		bn = "modzone";
13836 	} else {
13837 		UNREACHABLE();
13838 	}
13839 
13840 	/*
13841 	 * Convert the "addzone" or "modzone" to just "zone", for
13842 	 * the benefit of the parser
13843 	 */
13844 	isc_buffer_forward(&argbuf, 3);
13845 
13846 	cfg_parser_reset(named_g_addparser);
13847 	CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0,
13848 			       &cfg_type_addzoneconf, 0, &zoneconf));
13849 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
13850 	if (!cfg_obj_islist(zlist)) {
13851 		CHECK(ISC_R_FAILURE);
13852 	}
13853 
13854 	/* For now we only support adding one zone at a time */
13855 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
13856 
13857 	/* Check the zone type for ones that are not supported by addzone. */
13858 	zoptions = cfg_tuple_get(zoneobj, "options");
13859 
13860 	obj = NULL;
13861 	(void)cfg_map_get(zoptions, "type", &obj);
13862 	if (obj == NULL) {
13863 		(void)cfg_map_get(zoptions, "in-view", &obj);
13864 		if (obj != NULL) {
13865 			(void)putstr(text, "'in-view' zones not supported by ");
13866 			(void)putstr(text, bn);
13867 		} else {
13868 			(void)putstr(text, "zone type not specified");
13869 		}
13870 		CHECK(ISC_R_FAILURE);
13871 	}
13872 
13873 	if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
13874 	    strcasecmp(cfg_obj_asstring(obj), "forward") == 0 ||
13875 	    strcasecmp(cfg_obj_asstring(obj), "delegation-only") == 0)
13876 	{
13877 		(void)putstr(text, "'");
13878 		(void)putstr(text, cfg_obj_asstring(obj));
13879 		(void)putstr(text, "' zones not supported by ");
13880 		(void)putstr(text, bn);
13881 		CHECK(ISC_R_FAILURE);
13882 	}
13883 
13884 	if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0) {
13885 		redirect = true;
13886 	}
13887 
13888 	/* Make sense of optional class argument */
13889 	obj = cfg_tuple_get(zoneobj, "class");
13890 	CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass));
13891 
13892 	/* Make sense of optional view argument */
13893 	obj = cfg_tuple_get(zoneobj, "view");
13894 	if (obj && cfg_obj_isstring(obj)) {
13895 		viewname = cfg_obj_asstring(obj);
13896 	}
13897 	if (viewname == NULL || *viewname == '\0') {
13898 		viewname = "_default";
13899 	}
13900 	result = dns_viewlist_find(&server->viewlist, viewname, rdclass, &view);
13901 	if (result == ISC_R_NOTFOUND) {
13902 		(void)putstr(text, "no matching view found for '");
13903 		(void)putstr(text, viewname);
13904 		(void)putstr(text, "'");
13905 		goto cleanup;
13906 	} else if (result != ISC_R_SUCCESS) {
13907 		goto cleanup;
13908 	}
13909 
13910 	*viewp = view;
13911 	*zoneobjp = zoneobj;
13912 	*zoneconfp = zoneconf;
13913 	*redirectp = redirect;
13914 
13915 	return (ISC_R_SUCCESS);
13916 
13917 cleanup:
13918 	if (zoneconf != NULL) {
13919 		cfg_obj_destroy(named_g_addparser, &zoneconf);
13920 	}
13921 	if (view != NULL) {
13922 		dns_view_detach(&view);
13923 	}
13924 
13925 	return (result);
13926 }
13927 
13928 static isc_result_t
13929 delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config,
13930 		const dns_name_t *zname, nzfwriter_t nzfwriter) {
13931 	isc_result_t result = ISC_R_NOTFOUND;
13932 	const cfg_listelt_t *elt = NULL;
13933 	const cfg_obj_t *zl = NULL;
13934 	cfg_list_t *list;
13935 	dns_fixedname_t myfixed;
13936 	dns_name_t *myname;
13937 
13938 	REQUIRE(view != NULL);
13939 	REQUIRE(pctx != NULL);
13940 	REQUIRE(config != NULL);
13941 	REQUIRE(zname != NULL);
13942 
13943 	LOCK(&view->new_zone_lock);
13944 
13945 	cfg_map_get(config, "zone", &zl);
13946 
13947 	if (!cfg_obj_islist(zl)) {
13948 		CHECK(ISC_R_FAILURE);
13949 	}
13950 
13951 	DE_CONST(&zl->value.list, list);
13952 
13953 	myname = dns_fixedname_initname(&myfixed);
13954 
13955 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13956 	     elt = ISC_LIST_NEXT(elt, link))
13957 	{
13958 		const cfg_obj_t *zconf = cfg_listelt_value(elt);
13959 		const char *zn;
13960 		cfg_listelt_t *e;
13961 
13962 		zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
13963 		result = dns_name_fromstring(myname, zn, 0, NULL);
13964 		if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname)) {
13965 			continue;
13966 		}
13967 
13968 		DE_CONST(elt, e);
13969 		ISC_LIST_UNLINK(*list, e, link);
13970 		cfg_obj_destroy(pctx, &e->obj);
13971 		isc_mem_put(pctx->mctx, e, sizeof(*e));
13972 		result = ISC_R_SUCCESS;
13973 		break;
13974 	}
13975 
13976 	/*
13977 	 * Write config to NZF file if appropriate
13978 	 */
13979 	if (nzfwriter != NULL && view->new_zone_file != NULL) {
13980 		result = nzfwriter(config, view);
13981 	}
13982 
13983 cleanup:
13984 	UNLOCK(&view->new_zone_lock);
13985 	return (result);
13986 }
13987 
13988 static isc_result_t
13989 do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13990 	   dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
13991 	   bool redirect, isc_buffer_t **text) {
13992 	isc_result_t result, tresult;
13993 	dns_zone_t *zone = NULL;
13994 #ifndef HAVE_LMDB
13995 	FILE *fp = NULL;
13996 	bool cleanup_config = false;
13997 #else /* HAVE_LMDB */
13998 	MDB_txn *txn = NULL;
13999 	MDB_dbi dbi;
14000 	bool locked = false;
14001 
14002 	UNUSED(zoneconf);
14003 #endif
14004 
14005 	/* Zone shouldn't already exist */
14006 	if (redirect) {
14007 		result = (view->redirect != NULL) ? ISC_R_SUCCESS
14008 						  : ISC_R_NOTFOUND;
14009 	} else {
14010 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
14011 	}
14012 	if (result == ISC_R_SUCCESS) {
14013 		result = ISC_R_EXISTS;
14014 		goto cleanup;
14015 	} else if (result == DNS_R_PARTIALMATCH) {
14016 		/* Create our sub-zone anyway */
14017 		dns_zone_detach(&zone);
14018 		zone = NULL;
14019 	} else if (result != ISC_R_NOTFOUND) {
14020 		goto cleanup;
14021 	}
14022 
14023 	result = isc_task_beginexclusive(server->task);
14024 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
14025 
14026 #ifndef HAVE_LMDB
14027 	/*
14028 	 * Make sure we can open the configuration save file
14029 	 */
14030 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
14031 	if (result != ISC_R_SUCCESS) {
14032 		isc_task_endexclusive(server->task);
14033 		TCHECK(putstr(text, "unable to create '"));
14034 		TCHECK(putstr(text, view->new_zone_file));
14035 		TCHECK(putstr(text, "': "));
14036 		TCHECK(putstr(text, isc_result_totext(result)));
14037 		goto cleanup;
14038 	}
14039 
14040 	(void)isc_stdio_close(fp);
14041 	fp = NULL;
14042 #else  /* HAVE_LMDB */
14043 	LOCK(&view->new_zone_lock);
14044 	locked = true;
14045 	/* Make sure we can open the NZD database */
14046 	result = nzd_writable(view);
14047 	if (result != ISC_R_SUCCESS) {
14048 		isc_task_endexclusive(server->task);
14049 		TCHECK(putstr(text, "unable to open NZD database for '"));
14050 		TCHECK(putstr(text, view->new_zone_db));
14051 		TCHECK(putstr(text, "'"));
14052 		result = ISC_R_FAILURE;
14053 		goto cleanup;
14054 	}
14055 #endif /* HAVE_LMDB */
14056 
14057 	/* Mark view unfrozen and configure zone */
14058 	dns_view_thaw(view);
14059 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
14060 				server->mctx, view, &server->viewlist,
14061 				&server->kasplist, cfg->actx, true, false,
14062 				false, false);
14063 	dns_view_freeze(view);
14064 
14065 	isc_task_endexclusive(server->task);
14066 
14067 	if (result != ISC_R_SUCCESS) {
14068 		TCHECK(putstr(text, "configure_zone failed: "));
14069 		TCHECK(putstr(text, isc_result_totext(result)));
14070 		goto cleanup;
14071 	}
14072 
14073 	/* Is it there yet? */
14074 	if (redirect) {
14075 		if (view->redirect == NULL) {
14076 			CHECK(ISC_R_NOTFOUND);
14077 		}
14078 		dns_zone_attach(view->redirect, &zone);
14079 	} else {
14080 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
14081 		if (result != ISC_R_SUCCESS) {
14082 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14083 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14084 				      "added new zone was not found: %s",
14085 				      isc_result_totext(result));
14086 			goto cleanup;
14087 		}
14088 	}
14089 
14090 #ifndef HAVE_LMDB
14091 	/*
14092 	 * If there wasn't a previous newzone config, just save the one
14093 	 * we've created. If there was a previous one, merge the new
14094 	 * zone into it.
14095 	 */
14096 	if (cfg->nzf_config == NULL) {
14097 		cfg_obj_attach(zoneconf, &cfg->nzf_config);
14098 	} else {
14099 		cfg_obj_t *z;
14100 		DE_CONST(zoneobj, z);
14101 		CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z,
14102 					"zone"));
14103 	}
14104 	cleanup_config = true;
14105 #endif /* HAVE_LMDB */
14106 
14107 	/*
14108 	 * Load the zone from the master file.  If this fails, we'll
14109 	 * need to undo the configuration we've done already.
14110 	 */
14111 	result = dns_zone_load(zone, true);
14112 	if (result != ISC_R_SUCCESS) {
14113 		dns_db_t *dbp = NULL;
14114 
14115 		TCHECK(putstr(text, "dns_zone_loadnew failed: "));
14116 		TCHECK(putstr(text, isc_result_totext(result)));
14117 
14118 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14119 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14120 			      "addzone failed; reverting.");
14121 
14122 		/* If the zone loaded partially, unload it */
14123 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14124 			dns_db_detach(&dbp);
14125 			dns_zone_unload(zone);
14126 		}
14127 
14128 		/* Remove the zone from the zone table */
14129 		dns_zt_unmount(view->zonetable, zone);
14130 		goto cleanup;
14131 	}
14132 
14133 	/* Flag the zone as having been added at runtime */
14134 	dns_zone_setadded(zone, true);
14135 
14136 #ifdef HAVE_LMDB
14137 	/* Save the new zone configuration into the NZD */
14138 	CHECK(nzd_open(view, 0, &txn, &dbi));
14139 	CHECK(nzd_save(&txn, dbi, zone, zoneobj));
14140 #else  /* ifdef HAVE_LMDB */
14141 	/* Append the zone configuration to the NZF */
14142 	result = nzf_append(view, zoneobj);
14143 #endif /* HAVE_LMDB */
14144 
14145 cleanup:
14146 
14147 #ifndef HAVE_LMDB
14148 	if (fp != NULL) {
14149 		(void)isc_stdio_close(fp);
14150 	}
14151 	if (result != ISC_R_SUCCESS && cleanup_config) {
14152 		tresult = delete_zoneconf(view, cfg->add_parser,
14153 					  cfg->nzf_config, name, NULL);
14154 		RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
14155 	}
14156 #else  /* HAVE_LMDB */
14157 	if (txn != NULL) {
14158 		(void)nzd_close(&txn, false);
14159 	}
14160 	if (locked) {
14161 		UNLOCK(&view->new_zone_lock);
14162 	}
14163 #endif /* HAVE_LMDB */
14164 
14165 	if (zone != NULL) {
14166 		dns_zone_detach(&zone);
14167 	}
14168 
14169 	return (result);
14170 }
14171 
14172 static isc_result_t
14173 do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
14174 	   dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
14175 	   bool redirect, isc_buffer_t **text) {
14176 	isc_result_t result, tresult;
14177 	dns_zone_t *zone = NULL;
14178 	bool added;
14179 	bool exclusive = false;
14180 #ifndef HAVE_LMDB
14181 	FILE *fp = NULL;
14182 	cfg_obj_t *z;
14183 #else  /* HAVE_LMDB */
14184 	MDB_txn *txn = NULL;
14185 	MDB_dbi dbi;
14186 	bool locked = false;
14187 #endif /* HAVE_LMDB */
14188 
14189 	/* Zone must already exist */
14190 	if (redirect) {
14191 		if (view->redirect != NULL) {
14192 			dns_zone_attach(view->redirect, &zone);
14193 			result = ISC_R_SUCCESS;
14194 		} else {
14195 			result = ISC_R_NOTFOUND;
14196 		}
14197 	} else {
14198 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
14199 	}
14200 	if (result != ISC_R_SUCCESS) {
14201 		goto cleanup;
14202 	}
14203 
14204 	added = dns_zone_getadded(zone);
14205 	dns_zone_detach(&zone);
14206 
14207 #ifndef HAVE_LMDB
14208 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14209 	if (cfg == NULL) {
14210 		TCHECK(putstr(text, "new zone config is not set"));
14211 		CHECK(ISC_R_FAILURE);
14212 	}
14213 #endif /* ifndef HAVE_LMDB */
14214 
14215 	result = isc_task_beginexclusive(server->task);
14216 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
14217 	exclusive = true;
14218 
14219 #ifndef HAVE_LMDB
14220 	/* Make sure we can open the configuration save file */
14221 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
14222 	if (result != ISC_R_SUCCESS) {
14223 		TCHECK(putstr(text, "unable to open '"));
14224 		TCHECK(putstr(text, view->new_zone_file));
14225 		TCHECK(putstr(text, "': "));
14226 		TCHECK(putstr(text, isc_result_totext(result)));
14227 		goto cleanup;
14228 	}
14229 	(void)isc_stdio_close(fp);
14230 	fp = NULL;
14231 #else  /* HAVE_LMDB */
14232 	LOCK(&view->new_zone_lock);
14233 	locked = true;
14234 	/* Make sure we can open the NZD database */
14235 	result = nzd_writable(view);
14236 	if (result != ISC_R_SUCCESS) {
14237 		TCHECK(putstr(text, "unable to open NZD database for '"));
14238 		TCHECK(putstr(text, view->new_zone_db));
14239 		TCHECK(putstr(text, "'"));
14240 		result = ISC_R_FAILURE;
14241 		goto cleanup;
14242 	}
14243 #endif /* HAVE_LMDB */
14244 
14245 	/* Reconfigure the zone */
14246 	dns_view_thaw(view);
14247 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
14248 				server->mctx, view, &server->viewlist,
14249 				&server->kasplist, cfg->actx, true, false,
14250 				false, true);
14251 	dns_view_freeze(view);
14252 
14253 	exclusive = false;
14254 	isc_task_endexclusive(server->task);
14255 
14256 	if (result != ISC_R_SUCCESS) {
14257 		TCHECK(putstr(text, "configure_zone failed: "));
14258 		TCHECK(putstr(text, isc_result_totext(result)));
14259 		goto cleanup;
14260 	}
14261 
14262 	/* Is it there yet? */
14263 	if (redirect) {
14264 		if (view->redirect == NULL) {
14265 			CHECK(ISC_R_NOTFOUND);
14266 		}
14267 		dns_zone_attach(view->redirect, &zone);
14268 	} else {
14269 		CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
14270 	}
14271 
14272 #ifndef HAVE_LMDB
14273 	/* Remove old zone from configuration (and NZF file if applicable) */
14274 	if (added) {
14275 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
14276 					 dns_zone_getorigin(zone),
14277 					 nzf_writeconf);
14278 		if (result != ISC_R_SUCCESS) {
14279 			TCHECK(putstr(text, "former zone configuration "
14280 					    "not deleted: "));
14281 			TCHECK(putstr(text, isc_result_totext(result)));
14282 			goto cleanup;
14283 		}
14284 	}
14285 #endif /* HAVE_LMDB */
14286 
14287 	if (!added) {
14288 		if (cfg->vconfig == NULL) {
14289 			result = delete_zoneconf(
14290 				view, cfg->conf_parser, cfg->config,
14291 				dns_zone_getorigin(zone), NULL);
14292 		} else {
14293 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14294 								  "options");
14295 			result = delete_zoneconf(
14296 				view, cfg->conf_parser, voptions,
14297 				dns_zone_getorigin(zone), NULL);
14298 		}
14299 
14300 		if (result != ISC_R_SUCCESS) {
14301 			TCHECK(putstr(text, "former zone configuration "
14302 					    "not deleted: "));
14303 			TCHECK(putstr(text, isc_result_totext(result)));
14304 			goto cleanup;
14305 		}
14306 	}
14307 
14308 	/* Load the zone from the master file if it needs reloading. */
14309 	result = dns_zone_load(zone, true);
14310 
14311 	/*
14312 	 * Dynamic zones need no reloading, so we can pass this result.
14313 	 */
14314 	if (result == DNS_R_DYNAMIC) {
14315 		result = ISC_R_SUCCESS;
14316 	}
14317 
14318 	if (result != ISC_R_SUCCESS) {
14319 		dns_db_t *dbp = NULL;
14320 
14321 		TCHECK(putstr(text, "failed to load zone '"));
14322 		TCHECK(putstr(text, zname));
14323 		TCHECK(putstr(text, "': "));
14324 		TCHECK(putstr(text, isc_result_totext(result)));
14325 		TCHECK(putstr(text, "\nThe zone is no longer being served. "));
14326 		TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
14327 		TCHECK(putstr(text, "the problem and restore service."));
14328 
14329 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14330 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14331 			      "modzone failed; removing zone.");
14332 
14333 		/* If the zone loaded partially, unload it */
14334 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14335 			dns_db_detach(&dbp);
14336 			dns_zone_unload(zone);
14337 		}
14338 
14339 		/* Remove the zone from the zone table */
14340 		dns_zt_unmount(view->zonetable, zone);
14341 		goto cleanup;
14342 	}
14343 
14344 #ifndef HAVE_LMDB
14345 	/* Store the new zone configuration; also in NZF if applicable */
14346 	DE_CONST(zoneobj, z);
14347 	CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone"));
14348 #endif /* HAVE_LMDB */
14349 
14350 	if (added) {
14351 #ifdef HAVE_LMDB
14352 		CHECK(nzd_open(view, 0, &txn, &dbi));
14353 		CHECK(nzd_save(&txn, dbi, zone, zoneobj));
14354 #else  /* ifdef HAVE_LMDB */
14355 		result = nzf_append(view, zoneobj);
14356 		if (result != ISC_R_SUCCESS) {
14357 			TCHECK(putstr(text, "\nNew zone config not saved: "));
14358 			TCHECK(putstr(text, isc_result_totext(result)));
14359 			goto cleanup;
14360 		}
14361 #endif /* HAVE_LMDB */
14362 
14363 		TCHECK(putstr(text, "zone '"));
14364 		TCHECK(putstr(text, zname));
14365 		TCHECK(putstr(text, "' reconfigured."));
14366 	} else {
14367 		TCHECK(putstr(text, "zone '"));
14368 		TCHECK(putstr(text, zname));
14369 		TCHECK(putstr(text, "' must also be reconfigured in\n"));
14370 		TCHECK(putstr(text, "named.conf to make changes permanent."));
14371 	}
14372 
14373 cleanup:
14374 	if (exclusive) {
14375 		isc_task_endexclusive(server->task);
14376 	}
14377 
14378 #ifndef HAVE_LMDB
14379 	if (fp != NULL) {
14380 		(void)isc_stdio_close(fp);
14381 	}
14382 #else  /* HAVE_LMDB */
14383 	if (txn != NULL) {
14384 		(void)nzd_close(&txn, false);
14385 	}
14386 	if (locked) {
14387 		UNLOCK(&view->new_zone_lock);
14388 	}
14389 #endif /* HAVE_LMDB */
14390 
14391 	if (zone != NULL) {
14392 		dns_zone_detach(&zone);
14393 	}
14394 
14395 	return (result);
14396 }
14397 
14398 /*
14399  * Act on an "addzone" or "modzone" command from the command channel.
14400  */
14401 isc_result_t
14402 named_server_changezone(named_server_t *server, char *command,
14403 			isc_buffer_t **text) {
14404 	isc_result_t result;
14405 	bool addzone;
14406 	bool redirect = false;
14407 	ns_cfgctx_t *cfg = NULL;
14408 	cfg_obj_t *zoneconf = NULL;
14409 	const cfg_obj_t *zoneobj = NULL;
14410 	const char *zonename;
14411 	dns_view_t *view = NULL;
14412 	isc_buffer_t buf;
14413 	dns_fixedname_t fname;
14414 	dns_name_t *dnsname;
14415 
14416 	REQUIRE(text != NULL);
14417 
14418 	if (strncasecmp(command, "add", 3) == 0) {
14419 		addzone = true;
14420 	} else {
14421 		INSIST(strncasecmp(command, "mod", 3) == 0);
14422 		addzone = false;
14423 	}
14424 
14425 	CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj,
14426 			    &redirect, text));
14427 
14428 	/* Are we accepting new zones in this view? */
14429 #ifdef HAVE_LMDB
14430 	if (view->new_zone_db == NULL)
14431 #else  /* ifdef HAVE_LMDB */
14432 	if (view->new_zone_file == NULL)
14433 #endif /* HAVE_LMDB */
14434 	{
14435 		(void)putstr(text, "Not allowing new zones in view '");
14436 		(void)putstr(text, view->name);
14437 		(void)putstr(text, "'");
14438 		result = ISC_R_NOPERM;
14439 		goto cleanup;
14440 	}
14441 
14442 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14443 	if (cfg == NULL) {
14444 		result = ISC_R_FAILURE;
14445 		goto cleanup;
14446 	}
14447 
14448 	zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
14449 	isc_buffer_constinit(&buf, zonename, strlen(zonename));
14450 	isc_buffer_add(&buf, strlen(zonename));
14451 
14452 	dnsname = dns_fixedname_initname(&fname);
14453 	CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL));
14454 
14455 	if (redirect) {
14456 		if (!dns_name_equal(dnsname, dns_rootname)) {
14457 			(void)putstr(text, "redirect zones must be called "
14458 					   "\".\"");
14459 			CHECK(ISC_R_FAILURE);
14460 		}
14461 	}
14462 
14463 	if (addzone) {
14464 		CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj,
14465 				 redirect, text));
14466 	} else {
14467 		CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj,
14468 				 redirect, text));
14469 	}
14470 
14471 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14472 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14473 		      "%s zone %s in view %s via %s",
14474 		      addzone ? "added" : "updated", zonename, view->name,
14475 		      addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
14476 
14477 	/* Changing a zone counts as reconfiguration */
14478 	CHECK(isc_time_now(&named_g_configtime));
14479 
14480 cleanup:
14481 	if (isc_buffer_usedlength(*text) > 0) {
14482 		(void)putnull(text);
14483 	}
14484 	if (zoneconf != NULL) {
14485 		cfg_obj_destroy(named_g_addparser, &zoneconf);
14486 	}
14487 	if (view != NULL) {
14488 		dns_view_detach(&view);
14489 	}
14490 
14491 	return (result);
14492 }
14493 
14494 static bool
14495 inuse(const char *file, bool first, isc_buffer_t **text) {
14496 	if (file != NULL && isc_file_exists(file)) {
14497 		if (first) {
14498 			(void)putstr(text, "The following files were in use "
14499 					   "and may now be removed:\n");
14500 		} else {
14501 			(void)putstr(text, "\n");
14502 		}
14503 		(void)putstr(text, file);
14504 		(void)putnull(text);
14505 		return (false);
14506 	}
14507 	return (first);
14508 }
14509 
14510 typedef struct {
14511 	dns_zone_t *zone;
14512 	bool cleanup;
14513 } ns_dzctx_t;
14514 
14515 /*
14516  * Carry out a zone deletion scheduled by named_server_delzone().
14517  */
14518 static void
14519 rmzone(isc_task_t *task, isc_event_t *event) {
14520 	ns_dzctx_t *dz = (ns_dzctx_t *)event->ev_arg;
14521 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
14522 	dns_catz_zone_t *catz = NULL;
14523 	char zonename[DNS_NAME_FORMATSIZE];
14524 	dns_view_t *view = NULL;
14525 	ns_cfgctx_t *cfg = NULL;
14526 	dns_db_t *dbp = NULL;
14527 	bool added;
14528 	isc_result_t result;
14529 #ifdef HAVE_LMDB
14530 	MDB_txn *txn = NULL;
14531 	MDB_dbi dbi;
14532 #endif /* ifdef HAVE_LMDB */
14533 
14534 	REQUIRE(dz != NULL);
14535 
14536 	isc_event_free(&event);
14537 
14538 	/* Dig out configuration for this zone */
14539 	zone = dz->zone;
14540 	view = dns_zone_getview(zone);
14541 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14542 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
14543 
14544 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14545 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14546 		      "deleting zone %s in view %s via delzone", zonename,
14547 		      view->name);
14548 
14549 	/*
14550 	 * Remove the zone from configuration (and NZF file if applicable)
14551 	 * (If this is a catalog zone member then nzf_config can be NULL)
14552 	 */
14553 	added = dns_zone_getadded(zone);
14554 	catz = dns_zone_get_parentcatz(zone);
14555 
14556 	if (added && catz == NULL && cfg != NULL) {
14557 #ifdef HAVE_LMDB
14558 		/* Make sure we can open the NZD database */
14559 		LOCK(&view->new_zone_lock);
14560 		result = nzd_open(view, 0, &txn, &dbi);
14561 		if (result != ISC_R_SUCCESS) {
14562 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14563 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14564 				      "unable to open NZD database for '%s'",
14565 				      view->new_zone_db);
14566 		} else {
14567 			result = nzd_save(&txn, dbi, zone, NULL);
14568 		}
14569 
14570 		if (result != ISC_R_SUCCESS) {
14571 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14572 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14573 				      "unable to delete zone configuration: %s",
14574 				      isc_result_totext(result));
14575 		}
14576 
14577 		if (txn != NULL) {
14578 			(void)nzd_close(&txn, false);
14579 		}
14580 		UNLOCK(&view->new_zone_lock);
14581 #else  /* ifdef HAVE_LMDB */
14582 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
14583 					 dns_zone_getorigin(zone),
14584 					 nzf_writeconf);
14585 		if (result != ISC_R_SUCCESS) {
14586 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14587 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14588 				      "unable to delete zone configuration: %s",
14589 				      isc_result_totext(result));
14590 		}
14591 #endif /* HAVE_LMDB */
14592 	}
14593 
14594 	if (!added && cfg != NULL) {
14595 		if (cfg->vconfig != NULL) {
14596 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14597 								  "options");
14598 			result = delete_zoneconf(
14599 				view, cfg->conf_parser, voptions,
14600 				dns_zone_getorigin(zone), NULL);
14601 		} else {
14602 			result = delete_zoneconf(
14603 				view, cfg->conf_parser, cfg->config,
14604 				dns_zone_getorigin(zone), NULL);
14605 		}
14606 		if (result != ISC_R_SUCCESS) {
14607 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14608 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14609 				      "unable to delete zone configuration: %s",
14610 				      isc_result_totext(result));
14611 		}
14612 	}
14613 
14614 	/* Unload zone database */
14615 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14616 		dns_db_detach(&dbp);
14617 		dns_zone_unload(zone);
14618 	}
14619 
14620 	/* Clean up stub/secondary zone files if requested to do so */
14621 	dns_zone_getraw(zone, &raw);
14622 	mayberaw = (raw != NULL) ? raw : zone;
14623 
14624 	if (added && dz->cleanup) {
14625 		const char *file;
14626 
14627 		file = dns_zone_getfile(mayberaw);
14628 		result = isc_file_remove(file);
14629 		if (result != ISC_R_SUCCESS) {
14630 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14631 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14632 				      "file %s not removed: %s", file,
14633 				      isc_result_totext(result));
14634 		}
14635 
14636 		file = dns_zone_getjournal(mayberaw);
14637 		result = isc_file_remove(file);
14638 		if (result != ISC_R_SUCCESS) {
14639 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14640 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14641 				      "file %s not removed: %s", file,
14642 				      isc_result_totext(result));
14643 		}
14644 
14645 		if (zone != mayberaw) {
14646 			file = dns_zone_getfile(zone);
14647 			result = isc_file_remove(file);
14648 			if (result != ISC_R_SUCCESS) {
14649 				isc_log_write(
14650 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14651 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14652 					"file %s not removed: %s", file,
14653 					isc_result_totext(result));
14654 			}
14655 
14656 			file = dns_zone_getjournal(zone);
14657 			result = isc_file_remove(file);
14658 			if (result != ISC_R_SUCCESS) {
14659 				isc_log_write(
14660 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14661 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14662 					"file %s not removed: %s", file,
14663 					isc_result_totext(result));
14664 			}
14665 		}
14666 	}
14667 
14668 	if (raw != NULL) {
14669 		dns_zone_detach(&raw);
14670 	}
14671 	dns_zone_detach(&zone);
14672 	isc_mem_put(named_g_mctx, dz, sizeof(*dz));
14673 	isc_task_detach(&task);
14674 }
14675 
14676 /*
14677  * Act on a "delzone" command from the command channel.
14678  */
14679 isc_result_t
14680 named_server_delzone(named_server_t *server, isc_lex_t *lex,
14681 		     isc_buffer_t **text) {
14682 	isc_result_t result, tresult;
14683 	dns_zone_t *zone = NULL;
14684 	dns_zone_t *raw = NULL;
14685 	dns_zone_t *mayberaw;
14686 	dns_view_t *view = NULL;
14687 	char zonename[DNS_NAME_FORMATSIZE];
14688 	bool cleanup = false;
14689 	const char *ptr;
14690 	bool added;
14691 	ns_dzctx_t *dz = NULL;
14692 	isc_event_t *dzevent = NULL;
14693 	isc_task_t *task = NULL;
14694 
14695 	REQUIRE(text != NULL);
14696 
14697 	/* Skip the command name. */
14698 	ptr = next_token(lex, text);
14699 	if (ptr == NULL) {
14700 		return (ISC_R_UNEXPECTEDEND);
14701 	}
14702 
14703 	/* Find out what we are to do. */
14704 	ptr = next_token(lex, text);
14705 	if (ptr == NULL) {
14706 		return (ISC_R_UNEXPECTEDEND);
14707 	}
14708 
14709 	if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) {
14710 		cleanup = true;
14711 		ptr = next_token(lex, text);
14712 	}
14713 
14714 	CHECK(zone_from_args(server, lex, ptr, &zone, zonename, text, false));
14715 	if (zone == NULL) {
14716 		result = ISC_R_UNEXPECTEDEND;
14717 		goto cleanup;
14718 	}
14719 
14720 	INSIST(zonename != NULL);
14721 
14722 	/* Is this a policy zone? */
14723 	if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
14724 		TCHECK(putstr(text, "zone '"));
14725 		TCHECK(putstr(text, zonename));
14726 		TCHECK(putstr(text,
14727 			      "' cannot be deleted: response-policy zone."));
14728 		result = ISC_R_FAILURE;
14729 		goto cleanup;
14730 	}
14731 
14732 	view = dns_zone_getview(zone);
14733 	if (dns_zone_gettype(zone) == dns_zone_redirect) {
14734 		dns_zone_detach(&view->redirect);
14735 	} else {
14736 		CHECK(dns_zt_unmount(view->zonetable, zone));
14737 	}
14738 
14739 	/* Send cleanup event */
14740 	dz = isc_mem_get(named_g_mctx, sizeof(*dz));
14741 
14742 	dz->cleanup = cleanup;
14743 	dz->zone = NULL;
14744 	dns_zone_attach(zone, &dz->zone);
14745 	dzevent = isc_event_allocate(named_g_mctx, server, NAMED_EVENT_DELZONE,
14746 				     rmzone, dz, sizeof(isc_event_t));
14747 
14748 	dns_zone_gettask(zone, &task);
14749 	isc_task_send(task, &dzevent);
14750 	dz = NULL;
14751 
14752 	/* Inform user about cleaning up stub/secondary zone files */
14753 	dns_zone_getraw(zone, &raw);
14754 	mayberaw = (raw != NULL) ? raw : zone;
14755 
14756 	added = dns_zone_getadded(zone);
14757 	if (!added) {
14758 		TCHECK(putstr(text, "zone '"));
14759 		TCHECK(putstr(text, zonename));
14760 		TCHECK(putstr(text, "' is no longer active and will be "
14761 				    "deleted.\n"));
14762 		TCHECK(putstr(text, "To keep it from returning "));
14763 		TCHECK(putstr(text, "when the server is restarted, it\n"));
14764 		TCHECK(putstr(text, "must also be removed from named.conf."));
14765 	} else if (cleanup) {
14766 		TCHECK(putstr(text, "zone '"));
14767 		TCHECK(putstr(text, zonename));
14768 		TCHECK(putstr(text, "' and associated files will be deleted."));
14769 	} else if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
14770 		   dns_zone_gettype(mayberaw) == dns_zone_mirror ||
14771 		   dns_zone_gettype(mayberaw) == dns_zone_stub)
14772 	{
14773 		bool first;
14774 		const char *file;
14775 
14776 		TCHECK(putstr(text, "zone '"));
14777 		TCHECK(putstr(text, zonename));
14778 		TCHECK(putstr(text, "' will be deleted."));
14779 
14780 		file = dns_zone_getfile(mayberaw);
14781 		first = inuse(file, true, text);
14782 
14783 		file = dns_zone_getjournal(mayberaw);
14784 		first = inuse(file, first, text);
14785 
14786 		if (zone != mayberaw) {
14787 			file = dns_zone_getfile(zone);
14788 			first = inuse(file, first, text);
14789 
14790 			file = dns_zone_getjournal(zone);
14791 			(void)inuse(file, first, text);
14792 		}
14793 	}
14794 
14795 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14796 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14797 		      "zone %s scheduled for removal via delzone", zonename);
14798 
14799 	/* Removing a zone counts as reconfiguration */
14800 	CHECK(isc_time_now(&named_g_configtime));
14801 
14802 	result = ISC_R_SUCCESS;
14803 
14804 cleanup:
14805 	if (isc_buffer_usedlength(*text) > 0) {
14806 		(void)putnull(text);
14807 	}
14808 	if (raw != NULL) {
14809 		dns_zone_detach(&raw);
14810 	}
14811 	if (zone != NULL) {
14812 		dns_zone_detach(&zone);
14813 	}
14814 
14815 	return (result);
14816 }
14817 
14818 static const cfg_obj_t *
14819 find_name_in_list_from_map(const cfg_obj_t *config,
14820 			   const char *map_key_for_list, const char *name,
14821 			   bool redirect) {
14822 	const cfg_obj_t *list = NULL;
14823 	const cfg_listelt_t *element;
14824 	const cfg_obj_t *obj = NULL;
14825 	dns_fixedname_t fixed1, fixed2;
14826 	dns_name_t *name1 = NULL, *name2 = NULL;
14827 	isc_result_t result;
14828 
14829 	if (strcmp(map_key_for_list, "zone") == 0) {
14830 		name1 = dns_fixedname_initname(&fixed1);
14831 		name2 = dns_fixedname_initname(&fixed2);
14832 		result = dns_name_fromstring(name1, name, 0, NULL);
14833 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
14834 	}
14835 
14836 	cfg_map_get(config, map_key_for_list, &list);
14837 	for (element = cfg_list_first(list); element != NULL;
14838 	     element = cfg_list_next(element))
14839 	{
14840 		const char *vname;
14841 
14842 		obj = cfg_listelt_value(element);
14843 		INSIST(obj != NULL);
14844 		vname = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
14845 		if (vname == NULL) {
14846 			obj = NULL;
14847 			continue;
14848 		}
14849 
14850 		if (name1 != NULL) {
14851 			result = dns_name_fromstring(name2, vname, 0, NULL);
14852 			if (result == ISC_R_SUCCESS &&
14853 			    dns_name_equal(name1, name2))
14854 			{
14855 				const cfg_obj_t *zoptions;
14856 				const cfg_obj_t *typeobj = NULL;
14857 				zoptions = cfg_tuple_get(obj, "options");
14858 
14859 				if (zoptions != NULL) {
14860 					cfg_map_get(zoptions, "type", &typeobj);
14861 				}
14862 				if (redirect && typeobj != NULL &&
14863 				    strcasecmp(cfg_obj_asstring(typeobj),
14864 					       "redirect") == 0)
14865 				{
14866 					break;
14867 				} else if (!redirect) {
14868 					break;
14869 				}
14870 			}
14871 		} else if (strcasecmp(vname, name) == 0) {
14872 			break;
14873 		}
14874 
14875 		obj = NULL;
14876 	}
14877 
14878 	return (obj);
14879 }
14880 
14881 static void
14882 emitzone(void *arg, const char *buf, int len) {
14883 	ns_dzarg_t *dzarg = arg;
14884 	isc_result_t result;
14885 
14886 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
14887 	result = putmem(dzarg->text, buf, len);
14888 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
14889 		dzarg->result = result;
14890 	}
14891 }
14892 
14893 /*
14894  * Act on a "showzone" command from the command channel.
14895  */
14896 isc_result_t
14897 named_server_showzone(named_server_t *server, isc_lex_t *lex,
14898 		      isc_buffer_t **text) {
14899 	isc_result_t result;
14900 	const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
14901 	char zonename[DNS_NAME_FORMATSIZE];
14902 	const cfg_obj_t *map;
14903 	dns_view_t *view = NULL;
14904 	dns_zone_t *zone = NULL;
14905 	ns_cfgctx_t *cfg = NULL;
14906 #ifdef HAVE_LMDB
14907 	cfg_obj_t *nzconfig = NULL;
14908 #endif /* HAVE_LMDB */
14909 	bool added, redirect;
14910 	ns_dzarg_t dzarg;
14911 
14912 	REQUIRE(text != NULL);
14913 
14914 	/* Parse parameters */
14915 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
14916 	if (zone == NULL) {
14917 		result = ISC_R_UNEXPECTEDEND;
14918 		goto cleanup;
14919 	}
14920 
14921 	redirect = dns_zone_gettype(zone) == dns_zone_redirect;
14922 	added = dns_zone_getadded(zone);
14923 	view = dns_zone_getview(zone);
14924 	dns_zone_detach(&zone);
14925 
14926 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14927 	if (cfg == NULL) {
14928 		result = ISC_R_FAILURE;
14929 		goto cleanup;
14930 	}
14931 
14932 	if (!added) {
14933 		/* Find the view statement */
14934 		vconfig = find_name_in_list_from_map(cfg->config, "view",
14935 						     view->name, false);
14936 
14937 		/* Find the zone statement */
14938 		if (vconfig != NULL) {
14939 			map = cfg_tuple_get(vconfig, "options");
14940 		} else {
14941 			map = cfg->config;
14942 		}
14943 
14944 		zconfig = find_name_in_list_from_map(map, "zone", zonename,
14945 						     redirect);
14946 	}
14947 
14948 #ifndef HAVE_LMDB
14949 	if (zconfig == NULL && cfg->nzf_config != NULL) {
14950 		zconfig = find_name_in_list_from_map(cfg->nzf_config, "zone",
14951 						     zonename, redirect);
14952 	}
14953 #else  /* HAVE_LMDB */
14954 	if (zconfig == NULL) {
14955 		const cfg_obj_t *zlist = NULL;
14956 		CHECK(get_newzone_config(view, zonename, &nzconfig));
14957 		CHECK(cfg_map_get(nzconfig, "zone", &zlist));
14958 		if (!cfg_obj_islist(zlist)) {
14959 			CHECK(ISC_R_FAILURE);
14960 		}
14961 
14962 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
14963 	}
14964 #endif /* HAVE_LMDB */
14965 
14966 	if (zconfig == NULL) {
14967 		CHECK(ISC_R_NOTFOUND);
14968 	}
14969 
14970 	CHECK(putstr(text, "zone "));
14971 	dzarg.magic = DZARG_MAGIC;
14972 	dzarg.text = text;
14973 	dzarg.result = ISC_R_SUCCESS;
14974 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
14975 	CHECK(dzarg.result);
14976 
14977 	CHECK(putstr(text, ";"));
14978 
14979 	result = ISC_R_SUCCESS;
14980 
14981 cleanup:
14982 #ifdef HAVE_LMDB
14983 	if (nzconfig != NULL) {
14984 		cfg_obj_destroy(named_g_addparser, &nzconfig);
14985 	}
14986 #endif /* HAVE_LMDB */
14987 	if (isc_buffer_usedlength(*text) > 0) {
14988 		(void)putnull(text);
14989 	}
14990 
14991 	return (result);
14992 }
14993 
14994 static void
14995 newzone_cfgctx_destroy(void **cfgp) {
14996 	ns_cfgctx_t *cfg;
14997 
14998 	REQUIRE(cfgp != NULL && *cfgp != NULL);
14999 
15000 	cfg = *cfgp;
15001 
15002 	if (cfg->conf_parser != NULL) {
15003 		if (cfg->config != NULL) {
15004 			cfg_obj_destroy(cfg->conf_parser, &cfg->config);
15005 		}
15006 		if (cfg->vconfig != NULL) {
15007 			cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
15008 		}
15009 		cfg_parser_destroy(&cfg->conf_parser);
15010 	}
15011 	if (cfg->add_parser != NULL) {
15012 		if (cfg->nzf_config != NULL) {
15013 			cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
15014 		}
15015 		cfg_parser_destroy(&cfg->add_parser);
15016 	}
15017 
15018 	if (cfg->actx != NULL) {
15019 		cfg_aclconfctx_detach(&cfg->actx);
15020 	}
15021 
15022 	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
15023 	*cfgp = NULL;
15024 }
15025 
15026 isc_result_t
15027 named_server_signing(named_server_t *server, isc_lex_t *lex,
15028 		     isc_buffer_t **text) {
15029 	isc_result_t result = ISC_R_SUCCESS;
15030 	dns_zone_t *zone = NULL;
15031 	dns_name_t *origin;
15032 	dns_db_t *db = NULL;
15033 	dns_dbnode_t *node = NULL;
15034 	dns_dbversion_t *version = NULL;
15035 	dns_rdatatype_t privatetype;
15036 	dns_rdataset_t privset;
15037 	bool first = true;
15038 	bool list = false, clear = false;
15039 	bool chain = false;
15040 	bool setserial = false;
15041 	bool resalt = false;
15042 	uint32_t serial = 0;
15043 	char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
15044 	unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
15045 	unsigned char salt[255];
15046 	const char *ptr;
15047 	size_t n;
15048 
15049 	REQUIRE(text != NULL);
15050 
15051 	dns_rdataset_init(&privset);
15052 
15053 	/* Skip the command name. */
15054 	ptr = next_token(lex, text);
15055 	if (ptr == NULL) {
15056 		return (ISC_R_UNEXPECTEDEND);
15057 	}
15058 
15059 	/* Find out what we are to do. */
15060 	ptr = next_token(lex, text);
15061 	if (ptr == NULL) {
15062 		return (ISC_R_UNEXPECTEDEND);
15063 	}
15064 
15065 	if (strcasecmp(ptr, "-list") == 0) {
15066 		list = true;
15067 	} else if ((strcasecmp(ptr, "-clear") == 0) ||
15068 		   (strcasecmp(ptr, "-clean") == 0))
15069 	{
15070 		clear = true;
15071 		ptr = next_token(lex, text);
15072 		if (ptr == NULL) {
15073 			return (ISC_R_UNEXPECTEDEND);
15074 		}
15075 		strlcpy(keystr, ptr, sizeof(keystr));
15076 	} else if (strcasecmp(ptr, "-nsec3param") == 0) {
15077 		char hashbuf[64], flagbuf[64], iterbuf[64];
15078 		char nbuf[256];
15079 
15080 		chain = true;
15081 		ptr = next_token(lex, text);
15082 		if (ptr == NULL) {
15083 			return (ISC_R_UNEXPECTEDEND);
15084 		}
15085 
15086 		if (strcasecmp(ptr, "none") == 0) {
15087 			hash = 0;
15088 		} else {
15089 			strlcpy(hashbuf, ptr, sizeof(hashbuf));
15090 
15091 			ptr = next_token(lex, text);
15092 			if (ptr == NULL) {
15093 				return (ISC_R_UNEXPECTEDEND);
15094 			}
15095 			strlcpy(flagbuf, ptr, sizeof(flagbuf));
15096 
15097 			ptr = next_token(lex, text);
15098 			if (ptr == NULL) {
15099 				return (ISC_R_UNEXPECTEDEND);
15100 			}
15101 			strlcpy(iterbuf, ptr, sizeof(iterbuf));
15102 			n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", hashbuf,
15103 				     flagbuf, iterbuf);
15104 			if (n == sizeof(nbuf)) {
15105 				return (ISC_R_NOSPACE);
15106 			}
15107 			n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
15108 			if (n != 3U) {
15109 				return (ISC_R_BADNUMBER);
15110 			}
15111 
15112 			if (hash > 0xffU || flags > 0xffU ||
15113 			    iter > dns_nsec3_maxiterations())
15114 			{
15115 				return (ISC_R_RANGE);
15116 			}
15117 
15118 			ptr = next_token(lex, text);
15119 			if (ptr == NULL) {
15120 				return (ISC_R_UNEXPECTEDEND);
15121 			} else if (strcasecmp(ptr, "auto") == 0) {
15122 				/* Auto-generate a random salt.
15123 				 * XXXMUKS: This currently uses the
15124 				 * minimum recommended length by RFC
15125 				 * 5155 (64 bits). It should be made
15126 				 * configurable.
15127 				 */
15128 				saltlen = 8;
15129 				resalt = true;
15130 			} else if (strcmp(ptr, "-") != 0) {
15131 				isc_buffer_t buf;
15132 
15133 				isc_buffer_init(&buf, salt, sizeof(salt));
15134 				CHECK(isc_hex_decodestring(ptr, &buf));
15135 				saltlen = isc_buffer_usedlength(&buf);
15136 			}
15137 		}
15138 	} else if (strcasecmp(ptr, "-serial") == 0) {
15139 		ptr = next_token(lex, text);
15140 		if (ptr == NULL) {
15141 			return (ISC_R_UNEXPECTEDEND);
15142 		}
15143 		CHECK(isc_parse_uint32(&serial, ptr, 10));
15144 		setserial = true;
15145 	} else {
15146 		CHECK(DNS_R_SYNTAX);
15147 	}
15148 
15149 	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
15150 	if (zone == NULL) {
15151 		CHECK(ISC_R_UNEXPECTEDEND);
15152 	}
15153 
15154 	if (dns_zone_getkasp(zone) != NULL) {
15155 		(void)putstr(text, "zone uses dnssec-policy, use rndc dnssec "
15156 				   "command instead");
15157 		(void)putnull(text);
15158 		goto cleanup;
15159 	}
15160 
15161 	if (clear) {
15162 		CHECK(dns_zone_keydone(zone, keystr));
15163 		(void)putstr(text, "request queued");
15164 		(void)putnull(text);
15165 	} else if (chain) {
15166 		CHECK(dns_zone_setnsec3param(
15167 			zone, (uint8_t)hash, (uint8_t)flags, iter,
15168 			(uint8_t)saltlen, salt, true, resalt));
15169 		(void)putstr(text, "nsec3param request queued");
15170 		(void)putnull(text);
15171 	} else if (setserial) {
15172 		CHECK(dns_zone_setserial(zone, serial));
15173 		(void)putstr(text, "serial request queued");
15174 		(void)putnull(text);
15175 	} else if (list) {
15176 		privatetype = dns_zone_getprivatetype(zone);
15177 		origin = dns_zone_getorigin(zone);
15178 		CHECK(dns_zone_getdb(zone, &db));
15179 		CHECK(dns_db_findnode(db, origin, false, &node));
15180 		dns_db_currentversion(db, &version);
15181 
15182 		result = dns_db_findrdataset(db, node, version, privatetype,
15183 					     dns_rdatatype_none, 0, &privset,
15184 					     NULL);
15185 		if (result == ISC_R_NOTFOUND) {
15186 			(void)putstr(text, "No signing records found");
15187 			(void)putnull(text);
15188 			result = ISC_R_SUCCESS;
15189 			goto cleanup;
15190 		}
15191 
15192 		for (result = dns_rdataset_first(&privset);
15193 		     result == ISC_R_SUCCESS;
15194 		     result = dns_rdataset_next(&privset))
15195 		{
15196 			dns_rdata_t priv = DNS_RDATA_INIT;
15197 			/*
15198 			 * In theory, the output buffer could hold a full RDATA
15199 			 * record which is 16-bit and then some text around
15200 			 * it
15201 			 */
15202 			char output[UINT16_MAX + BUFSIZ];
15203 			isc_buffer_t buf;
15204 
15205 			dns_rdataset_current(&privset, &priv);
15206 
15207 			isc_buffer_init(&buf, output, sizeof(output));
15208 			CHECK(dns_private_totext(&priv, &buf));
15209 			if (!first) {
15210 				CHECK(putstr(text, "\n"));
15211 			}
15212 			CHECK(putstr(text, output));
15213 			first = false;
15214 		}
15215 		if (!first) {
15216 			CHECK(putnull(text));
15217 		}
15218 
15219 		if (result == ISC_R_NOMORE) {
15220 			result = ISC_R_SUCCESS;
15221 		}
15222 	}
15223 
15224 cleanup:
15225 	if (dns_rdataset_isassociated(&privset)) {
15226 		dns_rdataset_disassociate(&privset);
15227 	}
15228 	if (node != NULL) {
15229 		dns_db_detachnode(db, &node);
15230 	}
15231 	if (version != NULL) {
15232 		dns_db_closeversion(db, &version, false);
15233 	}
15234 	if (db != NULL) {
15235 		dns_db_detach(&db);
15236 	}
15237 	if (zone != NULL) {
15238 		dns_zone_detach(&zone);
15239 	}
15240 
15241 	return (result);
15242 }
15243 
15244 static bool
15245 argcheck(char *cmd, const char *full) {
15246 	size_t l;
15247 
15248 	if (cmd == NULL || cmd[0] != '-') {
15249 		return (false);
15250 	}
15251 
15252 	cmd++;
15253 	l = strlen(cmd);
15254 	if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
15255 		return (false);
15256 	}
15257 
15258 	return (true);
15259 }
15260 
15261 isc_result_t
15262 named_server_dnssec(named_server_t *server, isc_lex_t *lex,
15263 		    isc_buffer_t **text) {
15264 	isc_result_t result = ISC_R_SUCCESS;
15265 	dns_zone_t *zone = NULL;
15266 	dns_kasp_t *kasp = NULL;
15267 	dns_dnsseckeylist_t keys;
15268 	dns_dnsseckey_t *key;
15269 	char *ptr, *zonetext = NULL;
15270 	const char *msg = NULL;
15271 	/* variables for -checkds */
15272 	bool checkds = false, dspublish = false;
15273 	/* variables for -rollover */
15274 	bool rollover = false;
15275 	/* variables for -key */
15276 	bool use_keyid = false;
15277 	dns_keytag_t keyid = 0;
15278 	uint8_t algorithm = 0;
15279 	/* variables for -status */
15280 	bool status = false;
15281 	char output[4096];
15282 	isc_stdtime_t now, when;
15283 	isc_time_t timenow, timewhen;
15284 	const char *dir;
15285 	dns_db_t *db = NULL;
15286 	dns_dbversion_t *version = NULL;
15287 
15288 	REQUIRE(text != NULL);
15289 
15290 	/* Skip the command name. */
15291 	ptr = next_token(lex, text);
15292 	if (ptr == NULL) {
15293 		return (ISC_R_UNEXPECTEDEND);
15294 	}
15295 
15296 	/* Find out what we are to do. */
15297 	ptr = next_token(lex, text);
15298 	if (ptr == NULL) {
15299 		return (ISC_R_UNEXPECTEDEND);
15300 	}
15301 
15302 	/* Initialize current time and key list. */
15303 	TIME_NOW(&timenow);
15304 	now = isc_time_seconds(&timenow);
15305 	when = now;
15306 
15307 	ISC_LIST_INIT(keys);
15308 
15309 	if (strcasecmp(ptr, "-status") == 0) {
15310 		status = true;
15311 	} else if (strcasecmp(ptr, "-rollover") == 0) {
15312 		rollover = true;
15313 	} else if (strcasecmp(ptr, "-checkds") == 0) {
15314 		checkds = true;
15315 	} else {
15316 		CHECK(DNS_R_SYNTAX);
15317 	}
15318 
15319 	if (rollover || checkds) {
15320 		/* Check for options */
15321 		for (;;) {
15322 			ptr = next_token(lex, text);
15323 			if (ptr == NULL) {
15324 				msg = "Bad format";
15325 				CHECK(ISC_R_UNEXPECTEDEND);
15326 			} else if (argcheck(ptr, "alg")) {
15327 				isc_consttextregion_t alg;
15328 				ptr = next_token(lex, text);
15329 				if (ptr == NULL) {
15330 					msg = "No key algorithm specified";
15331 					CHECK(ISC_R_UNEXPECTEDEND);
15332 				}
15333 				alg.base = ptr;
15334 				alg.length = strlen(alg.base);
15335 				result = dns_secalg_fromtext(
15336 					&algorithm, (isc_textregion_t *)&alg);
15337 				if (result != ISC_R_SUCCESS) {
15338 					msg = "Bad algorithm";
15339 					CHECK(DNS_R_SYNTAX);
15340 				}
15341 				continue;
15342 			} else if (argcheck(ptr, "key")) {
15343 				uint16_t id;
15344 				ptr = next_token(lex, text);
15345 				if (ptr == NULL) {
15346 					msg = "No key identifier specified";
15347 					CHECK(ISC_R_UNEXPECTEDEND);
15348 				}
15349 				CHECK(isc_parse_uint16(&id, ptr, 10));
15350 				keyid = (dns_keytag_t)id;
15351 				use_keyid = true;
15352 				continue;
15353 			} else if (argcheck(ptr, "when")) {
15354 				uint32_t tw;
15355 				ptr = next_token(lex, text);
15356 				if (ptr == NULL) {
15357 					msg = "No time specified";
15358 					CHECK(ISC_R_UNEXPECTEDEND);
15359 				}
15360 				CHECK(dns_time32_fromtext(ptr, &tw));
15361 				when = (isc_stdtime_t)tw;
15362 				continue;
15363 			} else if (ptr[0] == '-') {
15364 				msg = "Unknown option";
15365 				CHECK(DNS_R_SYNTAX);
15366 			} else if (checkds) {
15367 				/*
15368 				 * No arguments provided, so we must be
15369 				 * parsing "published|withdrawn".
15370 				 */
15371 				if (strcasecmp(ptr, "published") == 0) {
15372 					dspublish = true;
15373 				} else if (strcasecmp(ptr, "withdrawn") != 0) {
15374 					CHECK(DNS_R_SYNTAX);
15375 				}
15376 			} else if (rollover) {
15377 				/*
15378 				 * No arguments provided, so we must be
15379 				 * parsing the zone.
15380 				 */
15381 				zonetext = ptr;
15382 			}
15383 			break;
15384 		}
15385 
15386 		if (rollover && !use_keyid) {
15387 			msg = "Key id is required when scheduling rollover";
15388 			CHECK(DNS_R_SYNTAX);
15389 		}
15390 
15391 		if (algorithm > 0 && !use_keyid) {
15392 			msg = "Key id is required when setting algorithm";
15393 			CHECK(DNS_R_SYNTAX);
15394 		}
15395 	}
15396 
15397 	/* Get zone. */
15398 	CHECK(zone_from_args(server, lex, zonetext, &zone, NULL, text, false));
15399 	if (zone == NULL) {
15400 		msg = "Zone not found";
15401 		CHECK(ISC_R_UNEXPECTEDEND);
15402 	}
15403 
15404 	/* Trailing garbage? */
15405 	ptr = next_token(lex, text);
15406 	if (ptr != NULL) {
15407 		msg = "Too many arguments";
15408 		CHECK(DNS_R_SYNTAX);
15409 	}
15410 
15411 	/* Get dnssec-policy. */
15412 	kasp = dns_zone_getkasp(zone);
15413 	if (kasp == NULL) {
15414 		msg = "Zone does not have dnssec-policy";
15415 		goto cleanup;
15416 	}
15417 
15418 	/* Get DNSSEC keys. */
15419 	dir = dns_zone_getkeydirectory(zone);
15420 	CHECK(dns_zone_getdb(zone, &db));
15421 	dns_db_currentversion(db, &version);
15422 	LOCK(&kasp->lock);
15423 	result = dns_zone_getdnsseckeys(zone, db, version, now, &keys);
15424 	UNLOCK(&kasp->lock);
15425 	if (result != ISC_R_SUCCESS) {
15426 		if (result != ISC_R_NOTFOUND) {
15427 			goto cleanup;
15428 		}
15429 	}
15430 
15431 	if (status) {
15432 		/*
15433 		 * Output the DNSSEC status of the key and signing policy.
15434 		 */
15435 		LOCK(&kasp->lock);
15436 		dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
15437 		UNLOCK(&kasp->lock);
15438 		CHECK(putstr(text, output));
15439 	} else if (checkds) {
15440 		/*
15441 		 * Mark DS record has been seen, so it may move to the
15442 		 * rumoured state.
15443 		 */
15444 		char whenbuf[80];
15445 		isc_time_set(&timewhen, when, 0);
15446 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
15447 		isc_result_t ret;
15448 
15449 		LOCK(&kasp->lock);
15450 		if (use_keyid) {
15451 			result = dns_keymgr_checkds_id(kasp, &keys, dir, now,
15452 						       when, dspublish, keyid,
15453 						       (unsigned int)algorithm);
15454 		} else {
15455 			result = dns_keymgr_checkds(kasp, &keys, dir, now, when,
15456 						    dspublish);
15457 		}
15458 		UNLOCK(&kasp->lock);
15459 
15460 		switch (result) {
15461 		case ISC_R_SUCCESS:
15462 			/*
15463 			 * Rekey after checkds command because the next key
15464 			 * event may have changed.
15465 			 */
15466 			dns_zone_rekey(zone, false);
15467 
15468 			if (use_keyid) {
15469 				char tagbuf[6];
15470 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
15471 				CHECK(putstr(text, "KSK "));
15472 				CHECK(putstr(text, tagbuf));
15473 				CHECK(putstr(text, ": "));
15474 			}
15475 			CHECK(putstr(text, "Marked DS as "));
15476 			if (dspublish) {
15477 				CHECK(putstr(text, "published "));
15478 			} else {
15479 				CHECK(putstr(text, "withdrawn "));
15480 			}
15481 			CHECK(putstr(text, "since "));
15482 			CHECK(putstr(text, whenbuf));
15483 			break;
15484 		case DNS_R_TOOMANYKEYS:
15485 			CHECK(putstr(text,
15486 				     "Error: multiple possible keys found, "
15487 				     "retry command with -key id"));
15488 			break;
15489 		default:
15490 			ret = result;
15491 			CHECK(putstr(text,
15492 				     "Error executing checkds command: "));
15493 			CHECK(putstr(text, isc_result_totext(ret)));
15494 			break;
15495 		}
15496 	} else if (rollover) {
15497 		/*
15498 		 * Manually rollover a key.
15499 		 */
15500 		char whenbuf[80];
15501 		isc_time_set(&timewhen, when, 0);
15502 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
15503 		isc_result_t ret;
15504 
15505 		LOCK(&kasp->lock);
15506 		result = dns_keymgr_rollover(kasp, &keys, dir, now, when, keyid,
15507 					     (unsigned int)algorithm);
15508 		UNLOCK(&kasp->lock);
15509 
15510 		switch (result) {
15511 		case ISC_R_SUCCESS:
15512 			/*
15513 			 * Rekey after rollover command because the next key
15514 			 * event may have changed.
15515 			 */
15516 			dns_zone_rekey(zone, false);
15517 
15518 			if (use_keyid) {
15519 				char tagbuf[6];
15520 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
15521 				CHECK(putstr(text, "Key "));
15522 				CHECK(putstr(text, tagbuf));
15523 				CHECK(putstr(text, ": "));
15524 			}
15525 			CHECK(putstr(text, "Rollover scheduled on "));
15526 			CHECK(putstr(text, whenbuf));
15527 			break;
15528 		case DNS_R_TOOMANYKEYS:
15529 			CHECK(putstr(text,
15530 				     "Error: multiple possible keys found, "
15531 				     "retry command with -alg algorithm"));
15532 			break;
15533 		default:
15534 			ret = result;
15535 			CHECK(putstr(text,
15536 				     "Error executing rollover command: "));
15537 			CHECK(putstr(text, isc_result_totext(ret)));
15538 			break;
15539 		}
15540 	}
15541 	CHECK(putnull(text));
15542 
15543 cleanup:
15544 	if (msg != NULL) {
15545 		(void)putstr(text, msg);
15546 		(void)putnull(text);
15547 	}
15548 
15549 	if (version != NULL) {
15550 		dns_db_closeversion(db, &version, false);
15551 	}
15552 	if (db != NULL) {
15553 		dns_db_detach(&db);
15554 	}
15555 
15556 	while (!ISC_LIST_EMPTY(keys)) {
15557 		key = ISC_LIST_HEAD(keys);
15558 		ISC_LIST_UNLINK(keys, key, link);
15559 		dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
15560 	}
15561 
15562 	if (zone != NULL) {
15563 		dns_zone_detach(&zone);
15564 	}
15565 
15566 	return (result);
15567 }
15568 
15569 static isc_result_t
15570 putmem(isc_buffer_t **b, const char *str, size_t len) {
15571 	isc_result_t result;
15572 
15573 	result = isc_buffer_reserve(b, (unsigned int)len);
15574 	if (result != ISC_R_SUCCESS) {
15575 		return (ISC_R_NOSPACE);
15576 	}
15577 
15578 	isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
15579 	return (ISC_R_SUCCESS);
15580 }
15581 
15582 static isc_result_t
15583 putstr(isc_buffer_t **b, const char *str) {
15584 	return (putmem(b, str, strlen(str)));
15585 }
15586 
15587 static isc_result_t
15588 putuint8(isc_buffer_t **b, uint8_t val) {
15589 	isc_result_t result;
15590 
15591 	result = isc_buffer_reserve(b, 1);
15592 	if (result != ISC_R_SUCCESS) {
15593 		return (ISC_R_NOSPACE);
15594 	}
15595 
15596 	isc_buffer_putuint8(*b, val);
15597 	return (ISC_R_SUCCESS);
15598 }
15599 
15600 static isc_result_t
15601 putnull(isc_buffer_t **b) {
15602 	return (putuint8(b, 0));
15603 }
15604 
15605 isc_result_t
15606 named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
15607 			isc_buffer_t **text) {
15608 	isc_result_t result = ISC_R_SUCCESS;
15609 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
15610 	const char *type, *file;
15611 	char zonename[DNS_NAME_FORMATSIZE];
15612 	uint32_t serial, signed_serial, nodes;
15613 	char serbuf[16], sserbuf[16], nodebuf[16];
15614 	char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2];
15615 	char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15616 	char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15617 	char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15618 	char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15619 	char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15620 	isc_time_t loadtime, expiretime, refreshtime;
15621 	isc_time_t refreshkeytime, resigntime;
15622 	dns_zonetype_t zonetype;
15623 	bool dynamic = false, frozen = false;
15624 	bool hasraw = false;
15625 	bool secure, maintain, allow;
15626 	dns_db_t *db = NULL, *rawdb = NULL;
15627 	char **incfiles = NULL;
15628 	int nfiles = 0;
15629 
15630 	REQUIRE(text != NULL);
15631 
15632 	isc_time_settoepoch(&loadtime);
15633 	isc_time_settoepoch(&refreshtime);
15634 	isc_time_settoepoch(&expiretime);
15635 	isc_time_settoepoch(&refreshkeytime);
15636 	isc_time_settoepoch(&resigntime);
15637 
15638 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
15639 	if (zone == NULL) {
15640 		result = ISC_R_UNEXPECTEDEND;
15641 		goto cleanup;
15642 	}
15643 
15644 	/* Inline signing? */
15645 	CHECK(dns_zone_getdb(zone, &db));
15646 	dns_zone_getraw(zone, &raw);
15647 	hasraw = (raw != NULL);
15648 	if (hasraw) {
15649 		mayberaw = raw;
15650 		zonetype = dns_zone_gettype(raw);
15651 		CHECK(dns_zone_getdb(raw, &rawdb));
15652 	} else {
15653 		mayberaw = zone;
15654 		zonetype = dns_zone_gettype(zone);
15655 	}
15656 
15657 	type = dns_zonetype_name(zonetype);
15658 
15659 	/* Serial number */
15660 	result = dns_zone_getserial(mayberaw, &serial);
15661 
15662 	/* This is to mirror old behavior with dns_zone_getserial */
15663 	if (result != ISC_R_SUCCESS) {
15664 		serial = 0;
15665 	}
15666 
15667 	snprintf(serbuf, sizeof(serbuf), "%u", serial);
15668 	if (hasraw) {
15669 		result = dns_zone_getserial(zone, &signed_serial);
15670 		if (result != ISC_R_SUCCESS) {
15671 			serial = 0;
15672 		}
15673 		snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial);
15674 	}
15675 
15676 	/* Database node count */
15677 	nodes = dns_db_nodecount(hasraw ? rawdb : db, dns_dbtree_main);
15678 	snprintf(nodebuf, sizeof(nodebuf), "%u", nodes);
15679 
15680 	/* Security */
15681 	secure = dns_db_issecure(db);
15682 	allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
15683 	maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
15684 
15685 	/* Master files */
15686 	file = dns_zone_getfile(mayberaw);
15687 	nfiles = dns_zone_getincludes(mayberaw, &incfiles);
15688 
15689 	/* Load time */
15690 	dns_zone_getloadtime(zone, &loadtime);
15691 	isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
15692 
15693 	/* Refresh/expire times */
15694 	if (zonetype == dns_zone_secondary || zonetype == dns_zone_mirror ||
15695 	    zonetype == dns_zone_stub || zonetype == dns_zone_redirect)
15696 	{
15697 		dns_zone_getexpiretime(mayberaw, &expiretime);
15698 		isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
15699 		dns_zone_getrefreshtime(mayberaw, &refreshtime);
15700 		isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
15701 	}
15702 
15703 	/* Key refresh time */
15704 	if (zonetype == dns_zone_primary ||
15705 	    (zonetype == dns_zone_secondary && hasraw))
15706 	{
15707 		dns_zone_getrefreshkeytime(zone, &refreshkeytime);
15708 		isc_time_formathttptimestamp(&refreshkeytime, kbuf,
15709 					     sizeof(kbuf));
15710 	}
15711 
15712 	/* Dynamic? */
15713 	if (zonetype == dns_zone_primary) {
15714 		dynamic = dns_zone_isdynamic(mayberaw, true);
15715 		frozen = dynamic && !dns_zone_isdynamic(mayberaw, false);
15716 	}
15717 
15718 	/* Next resign event */
15719 	if (secure &&
15720 	    (zonetype == dns_zone_primary ||
15721 	     (zonetype == dns_zone_secondary && hasraw)) &&
15722 	    ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0))
15723 	{
15724 		dns_name_t *name;
15725 		dns_fixedname_t fixed;
15726 		dns_rdataset_t next;
15727 
15728 		dns_rdataset_init(&next);
15729 		name = dns_fixedname_initname(&fixed);
15730 
15731 		result = dns_db_getsigningtime(db, &next, name);
15732 		if (result == ISC_R_SUCCESS) {
15733 			isc_stdtime_t timenow;
15734 			char namebuf[DNS_NAME_FORMATSIZE];
15735 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
15736 
15737 			isc_stdtime_get(&timenow);
15738 			dns_name_format(name, namebuf, sizeof(namebuf));
15739 			dns_rdatatype_format(next.covers, typebuf,
15740 					     sizeof(typebuf));
15741 			snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf,
15742 				 typebuf);
15743 			isc_time_set(
15744 				&resigntime,
15745 				next.resign -
15746 					dns_zone_getsigresigninginterval(zone),
15747 				0);
15748 			isc_time_formathttptimestamp(&resigntime, rtbuf,
15749 						     sizeof(rtbuf));
15750 			dns_rdataset_disassociate(&next);
15751 		}
15752 	}
15753 
15754 	/* Create text */
15755 	CHECK(putstr(text, "name: "));
15756 	CHECK(putstr(text, zonename));
15757 
15758 	CHECK(putstr(text, "\ntype: "));
15759 	CHECK(putstr(text, type));
15760 
15761 	if (file != NULL) {
15762 		int i;
15763 		CHECK(putstr(text, "\nfiles: "));
15764 		CHECK(putstr(text, file));
15765 		for (i = 0; i < nfiles; i++) {
15766 			CHECK(putstr(text, ", "));
15767 			if (incfiles[i] != NULL) {
15768 				CHECK(putstr(text, incfiles[i]));
15769 			}
15770 		}
15771 	}
15772 
15773 	CHECK(putstr(text, "\nserial: "));
15774 	CHECK(putstr(text, serbuf));
15775 	if (hasraw) {
15776 		CHECK(putstr(text, "\nsigned serial: "));
15777 		CHECK(putstr(text, sserbuf));
15778 	}
15779 
15780 	CHECK(putstr(text, "\nnodes: "));
15781 	CHECK(putstr(text, nodebuf));
15782 
15783 	if (!isc_time_isepoch(&loadtime)) {
15784 		CHECK(putstr(text, "\nlast loaded: "));
15785 		CHECK(putstr(text, lbuf));
15786 	}
15787 
15788 	if (!isc_time_isepoch(&refreshtime)) {
15789 		CHECK(putstr(text, "\nnext refresh: "));
15790 		CHECK(putstr(text, rbuf));
15791 	}
15792 
15793 	if (!isc_time_isepoch(&expiretime)) {
15794 		CHECK(putstr(text, "\nexpires: "));
15795 		CHECK(putstr(text, xbuf));
15796 	}
15797 
15798 	if (secure) {
15799 		CHECK(putstr(text, "\nsecure: yes"));
15800 		if (hasraw) {
15801 			CHECK(putstr(text, "\ninline signing: yes"));
15802 		} else {
15803 			CHECK(putstr(text, "\ninline signing: no"));
15804 		}
15805 	} else {
15806 		CHECK(putstr(text, "\nsecure: no"));
15807 	}
15808 
15809 	if (maintain) {
15810 		CHECK(putstr(text, "\nkey maintenance: automatic"));
15811 		if (!isc_time_isepoch(&refreshkeytime)) {
15812 			CHECK(putstr(text, "\nnext key event: "));
15813 			CHECK(putstr(text, kbuf));
15814 		}
15815 	} else if (allow) {
15816 		CHECK(putstr(text, "\nkey maintenance: on command"));
15817 	} else if (secure || hasraw) {
15818 		CHECK(putstr(text, "\nkey maintenance: none"));
15819 	}
15820 
15821 	if (!isc_time_isepoch(&resigntime)) {
15822 		CHECK(putstr(text, "\nnext resign node: "));
15823 		CHECK(putstr(text, resignbuf));
15824 		CHECK(putstr(text, "\nnext resign time: "));
15825 		CHECK(putstr(text, rtbuf));
15826 	}
15827 
15828 	if (dynamic) {
15829 		CHECK(putstr(text, "\ndynamic: yes"));
15830 		if (frozen) {
15831 			CHECK(putstr(text, "\nfrozen: yes"));
15832 		} else {
15833 			CHECK(putstr(text, "\nfrozen: no"));
15834 		}
15835 	} else {
15836 		CHECK(putstr(text, "\ndynamic: no"));
15837 	}
15838 
15839 	CHECK(putstr(text, "\nreconfigurable via modzone: "));
15840 	CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
15841 
15842 cleanup:
15843 	/* Indicate truncated output if possible. */
15844 	if (result == ISC_R_NOSPACE) {
15845 		(void)putstr(text, "\n...");
15846 	}
15847 	if ((result == ISC_R_SUCCESS || result == ISC_R_NOSPACE)) {
15848 		(void)putnull(text);
15849 	}
15850 
15851 	if (db != NULL) {
15852 		dns_db_detach(&db);
15853 	}
15854 	if (rawdb != NULL) {
15855 		dns_db_detach(&rawdb);
15856 	}
15857 	if (incfiles != NULL && mayberaw != NULL) {
15858 		int i;
15859 		isc_mem_t *mctx = dns_zone_getmctx(mayberaw);
15860 
15861 		for (i = 0; i < nfiles; i++) {
15862 			if (incfiles[i] != NULL) {
15863 				isc_mem_free(mctx, incfiles[i]);
15864 			}
15865 		}
15866 		isc_mem_free(mctx, incfiles);
15867 	}
15868 	if (raw != NULL) {
15869 		dns_zone_detach(&raw);
15870 	}
15871 	if (zone != NULL) {
15872 		dns_zone_detach(&zone);
15873 	}
15874 	return (result);
15875 }
15876 
15877 isc_result_t
15878 named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
15879 		 isc_buffer_t **text) {
15880 	dns_view_t *view;
15881 	dns_ntatable_t *ntatable = NULL;
15882 	isc_result_t result = ISC_R_SUCCESS;
15883 	char *ptr, *nametext = NULL, *viewname;
15884 	char namebuf[DNS_NAME_FORMATSIZE];
15885 	char viewbuf[DNS_NAME_FORMATSIZE];
15886 	isc_stdtime_t now, when;
15887 	isc_time_t t;
15888 	char tbuf[64];
15889 	const char *msg = NULL;
15890 	bool dump = false, force = false;
15891 	dns_fixedname_t fn;
15892 	const dns_name_t *ntaname;
15893 	dns_name_t *fname;
15894 	dns_ttl_t ntattl;
15895 	bool ttlset = false, excl = false, viewfound = false;
15896 	dns_rdataclass_t rdclass = dns_rdataclass_in;
15897 	bool first = true;
15898 
15899 	REQUIRE(text != NULL);
15900 
15901 	UNUSED(force);
15902 
15903 	fname = dns_fixedname_initname(&fn);
15904 
15905 	/* Skip the command name. */
15906 	ptr = next_token(lex, text);
15907 	if (ptr == NULL) {
15908 		return (ISC_R_UNEXPECTEDEND);
15909 	}
15910 
15911 	for (;;) {
15912 		/* Check for options */
15913 		ptr = next_token(lex, text);
15914 		if (ptr == NULL) {
15915 			return (ISC_R_UNEXPECTEDEND);
15916 		}
15917 
15918 		if (strcmp(ptr, "--") == 0) {
15919 			break;
15920 		} else if (argcheck(ptr, "dump")) {
15921 			dump = true;
15922 		} else if (argcheck(ptr, "remove")) {
15923 			ntattl = 0;
15924 			ttlset = true;
15925 		} else if (argcheck(ptr, "force")) {
15926 			force = true;
15927 			continue;
15928 		} else if (argcheck(ptr, "lifetime")) {
15929 			isc_textregion_t tr;
15930 
15931 			ptr = next_token(lex, text);
15932 			if (ptr == NULL) {
15933 				msg = "No lifetime specified";
15934 				CHECK(ISC_R_UNEXPECTEDEND);
15935 			}
15936 
15937 			tr.base = ptr;
15938 			tr.length = strlen(ptr);
15939 			result = dns_ttl_fromtext(&tr, &ntattl);
15940 			if (result != ISC_R_SUCCESS) {
15941 				msg = "could not parse NTA lifetime";
15942 				CHECK(result);
15943 			}
15944 
15945 			if (ntattl > 604800) {
15946 				msg = "NTA lifetime cannot exceed one week";
15947 				CHECK(ISC_R_RANGE);
15948 			}
15949 
15950 			ttlset = true;
15951 			continue;
15952 		} else if (argcheck(ptr, "class")) {
15953 			isc_textregion_t tr;
15954 
15955 			ptr = next_token(lex, text);
15956 			if (ptr == NULL) {
15957 				msg = "No class specified";
15958 				CHECK(ISC_R_UNEXPECTEDEND);
15959 			}
15960 
15961 			tr.base = ptr;
15962 			tr.length = strlen(ptr);
15963 			CHECK(dns_rdataclass_fromtext(&rdclass, &tr));
15964 			continue;
15965 		} else if (ptr[0] == '-') {
15966 			msg = "Unknown option";
15967 			CHECK(DNS_R_SYNTAX);
15968 		} else {
15969 			nametext = ptr;
15970 		}
15971 
15972 		break;
15973 	}
15974 
15975 	/*
15976 	 * If -dump was specified, list NTA's and return
15977 	 */
15978 	if (dump) {
15979 		size_t last = 0;
15980 
15981 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15982 		     view = ISC_LIST_NEXT(view, link))
15983 		{
15984 			if (ntatable != NULL) {
15985 				dns_ntatable_detach(&ntatable);
15986 			}
15987 			result = dns_view_getntatable(view, &ntatable);
15988 			if (result == ISC_R_NOTFOUND) {
15989 				continue;
15990 			}
15991 
15992 			if (last != isc_buffer_usedlength(*text)) {
15993 				CHECK(putstr(text, "\n"));
15994 			}
15995 
15996 			last = isc_buffer_usedlength(*text);
15997 
15998 			CHECK(dns_ntatable_totext(ntatable, view->name, text));
15999 		}
16000 		CHECK(putnull(text));
16001 
16002 		goto cleanup;
16003 	}
16004 
16005 	if (readonly) {
16006 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16007 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
16008 			      "rejecting restricted control channel "
16009 			      "NTA command");
16010 		CHECK(ISC_R_FAILURE);
16011 	}
16012 
16013 	/* Get the NTA name if not found above. */
16014 	if (nametext == NULL) {
16015 		nametext = next_token(lex, text);
16016 	}
16017 	if (nametext == NULL) {
16018 		return (ISC_R_UNEXPECTEDEND);
16019 	}
16020 
16021 	/* Copy nametext as it'll be overwritten by next_token() */
16022 	strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE);
16023 
16024 	if (strcmp(namebuf, ".") == 0) {
16025 		ntaname = dns_rootname;
16026 	} else {
16027 		isc_buffer_t b;
16028 		isc_buffer_init(&b, namebuf, strlen(namebuf));
16029 		isc_buffer_add(&b, strlen(namebuf));
16030 		CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL));
16031 		ntaname = fname;
16032 	}
16033 
16034 	/* Look for the view name. */
16035 	viewname = next_token(lex, text);
16036 	if (viewname != NULL) {
16037 		strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE);
16038 		viewname = viewbuf;
16039 	}
16040 
16041 	if (next_token(lex, text) != NULL) {
16042 		CHECK(DNS_R_SYNTAX);
16043 	}
16044 
16045 	isc_stdtime_get(&now);
16046 
16047 	result = isc_task_beginexclusive(server->task);
16048 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
16049 	excl = true;
16050 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16051 	     view = ISC_LIST_NEXT(view, link))
16052 	{
16053 		if (viewname != NULL && strcmp(view->name, viewname) != 0) {
16054 			continue;
16055 		}
16056 		viewfound = true;
16057 
16058 		if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) {
16059 			continue;
16060 		}
16061 
16062 		if (view->nta_lifetime == 0) {
16063 			continue;
16064 		}
16065 
16066 		if (!ttlset) {
16067 			ntattl = view->nta_lifetime;
16068 		}
16069 
16070 		if (ntatable != NULL) {
16071 			dns_ntatable_detach(&ntatable);
16072 		}
16073 
16074 		result = dns_view_getntatable(view, &ntatable);
16075 		if (result == ISC_R_NOTFOUND) {
16076 			result = ISC_R_SUCCESS;
16077 			continue;
16078 		}
16079 
16080 		result = dns_view_flushnode(view, ntaname, true);
16081 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16082 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
16083 			      "flush tree '%s' in cache view '%s': %s", namebuf,
16084 			      view->name, isc_result_totext(result));
16085 
16086 		if (ntattl != 0) {
16087 			CHECK(dns_ntatable_add(ntatable, ntaname, force, now,
16088 					       ntattl));
16089 
16090 			when = now + ntattl;
16091 			isc_time_set(&t, when, 0);
16092 			isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
16093 
16094 			if (!first) {
16095 				CHECK(putstr(text, "\n"));
16096 			}
16097 			first = false;
16098 
16099 			CHECK(putstr(text, "Negative trust anchor added: "));
16100 			CHECK(putstr(text, namebuf));
16101 			CHECK(putstr(text, "/"));
16102 			CHECK(putstr(text, view->name));
16103 			CHECK(putstr(text, ", expires "));
16104 			CHECK(putstr(text, tbuf));
16105 
16106 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16107 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
16108 				      "added NTA '%s' (%d sec) in view '%s'",
16109 				      namebuf, ntattl, view->name);
16110 		} else {
16111 			bool wasremoved;
16112 
16113 			result = dns_ntatable_delete(ntatable, ntaname);
16114 			if (result == ISC_R_SUCCESS) {
16115 				wasremoved = true;
16116 			} else if (result == ISC_R_NOTFOUND) {
16117 				wasremoved = false;
16118 			} else {
16119 				goto cleanup;
16120 			}
16121 
16122 			if (!first) {
16123 				CHECK(putstr(text, "\n"));
16124 			}
16125 			first = false;
16126 
16127 			CHECK(putstr(text, "Negative trust anchor "));
16128 			CHECK(putstr(text,
16129 				     wasremoved ? "removed: " : "not found: "));
16130 			CHECK(putstr(text, namebuf));
16131 			CHECK(putstr(text, "/"));
16132 			CHECK(putstr(text, view->name));
16133 
16134 			if (wasremoved) {
16135 				isc_log_write(
16136 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16137 					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
16138 					"removed NTA '%s' in view %s", namebuf,
16139 					view->name);
16140 			}
16141 		}
16142 
16143 		result = dns_view_saventa(view);
16144 		if (result != ISC_R_SUCCESS) {
16145 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16146 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
16147 				      "error writing NTA file "
16148 				      "for view '%s': %s",
16149 				      view->name, isc_result_totext(result));
16150 		}
16151 	}
16152 
16153 	if (!viewfound) {
16154 		msg = "No such view";
16155 		CHECK(ISC_R_NOTFOUND);
16156 	}
16157 
16158 	(void)putnull(text);
16159 
16160 cleanup:
16161 	if (msg != NULL) {
16162 		(void)putstr(text, msg);
16163 		(void)putnull(text);
16164 	}
16165 
16166 	if (excl) {
16167 		isc_task_endexclusive(server->task);
16168 	}
16169 	if (ntatable != NULL) {
16170 		dns_ntatable_detach(&ntatable);
16171 	}
16172 	return (result);
16173 }
16174 
16175 isc_result_t
16176 named_server_saventa(named_server_t *server) {
16177 	dns_view_t *view;
16178 
16179 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16180 	     view = ISC_LIST_NEXT(view, link))
16181 	{
16182 		isc_result_t result = dns_view_saventa(view);
16183 
16184 		if (result != ISC_R_SUCCESS) {
16185 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16186 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
16187 				      "error writing NTA file "
16188 				      "for view '%s': %s",
16189 				      view->name, isc_result_totext(result));
16190 		}
16191 	}
16192 
16193 	return (ISC_R_SUCCESS);
16194 }
16195 
16196 isc_result_t
16197 named_server_loadnta(named_server_t *server) {
16198 	dns_view_t *view;
16199 
16200 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16201 	     view = ISC_LIST_NEXT(view, link))
16202 	{
16203 		isc_result_t result = dns_view_loadnta(view);
16204 
16205 		if ((result != ISC_R_SUCCESS) &&
16206 		    (result != ISC_R_FILENOTFOUND) &&
16207 		    (result != ISC_R_NOTFOUND))
16208 		{
16209 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16210 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
16211 				      "error loading NTA file "
16212 				      "for view '%s': %s",
16213 				      view->name, isc_result_totext(result));
16214 		}
16215 	}
16216 
16217 	return (ISC_R_SUCCESS);
16218 }
16219 
16220 static isc_result_t
16221 mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
16222 	isc_result_t result;
16223 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
16224 
16225 	snprintf(msg, sizeof(msg), "refreshing managed keys for '%s'",
16226 		 view->name);
16227 	CHECK(putstr(text, msg));
16228 	CHECK(dns_zone_synckeyzone(view->managed_keys));
16229 
16230 cleanup:
16231 	return (result);
16232 }
16233 
16234 static isc_result_t
16235 mkey_destroy(named_server_t *server, dns_view_t *view, isc_buffer_t **text) {
16236 	isc_result_t result;
16237 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
16238 	bool exclusive = false;
16239 	const char *file = NULL;
16240 	dns_db_t *dbp = NULL;
16241 	dns_zone_t *mkzone = NULL;
16242 	bool removed_a_file = false;
16243 
16244 	if (view->managed_keys == NULL) {
16245 		CHECK(ISC_R_NOTFOUND);
16246 	}
16247 
16248 	snprintf(msg, sizeof(msg), "destroying managed-keys database for '%s'",
16249 		 view->name);
16250 	CHECK(putstr(text, msg));
16251 
16252 	result = isc_task_beginexclusive(server->task);
16253 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
16254 	exclusive = true;
16255 
16256 	/* Remove and clean up managed keys zone from view */
16257 	mkzone = view->managed_keys;
16258 	view->managed_keys = NULL;
16259 	(void)dns_zone_flush(mkzone);
16260 
16261 	/* Unload zone database */
16262 	if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) {
16263 		dns_db_detach(&dbp);
16264 		dns_zone_unload(mkzone);
16265 	}
16266 
16267 	/* Delete files */
16268 	file = dns_zone_getfile(mkzone);
16269 	result = isc_file_remove(file);
16270 	if (result == ISC_R_SUCCESS) {
16271 		removed_a_file = true;
16272 	} else {
16273 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16274 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
16275 			      "file %s not removed: %s", file,
16276 			      isc_result_totext(result));
16277 	}
16278 
16279 	file = dns_zone_getjournal(mkzone);
16280 	result = isc_file_remove(file);
16281 	if (result == ISC_R_SUCCESS) {
16282 		removed_a_file = true;
16283 	} else {
16284 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16285 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
16286 			      "file %s not removed: %s", file,
16287 			      isc_result_totext(result));
16288 	}
16289 
16290 	if (!removed_a_file) {
16291 		CHECK(putstr(text, "error: no files could be removed"));
16292 		CHECK(ISC_R_FAILURE);
16293 	}
16294 
16295 	dns_zone_detach(&mkzone);
16296 	result = ISC_R_SUCCESS;
16297 
16298 cleanup:
16299 	if (exclusive) {
16300 		isc_task_endexclusive(server->task);
16301 	}
16302 	return (result);
16303 }
16304 
16305 static isc_result_t
16306 mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
16307 	isc_result_t result;
16308 	dns_db_t *db = NULL;
16309 	dns_dbversion_t *ver = NULL;
16310 	dns_rriterator_t rrit;
16311 	isc_stdtime_t now;
16312 	dns_name_t *prevname = NULL;
16313 
16314 	isc_stdtime_get(&now);
16315 
16316 	CHECK(dns_zone_getdb(view->managed_keys, &db));
16317 	dns_db_currentversion(db, &ver);
16318 	dns_rriterator_init(&rrit, db, ver, 0);
16319 	for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS;
16320 	     result = dns_rriterator_nextrrset(&rrit))
16321 	{
16322 		char buf[DNS_NAME_FORMATSIZE + 500];
16323 		dns_name_t *name = NULL;
16324 		dns_rdataset_t *kdset = NULL;
16325 		dns_rdata_t rdata = DNS_RDATA_INIT;
16326 		dns_rdata_keydata_t kd;
16327 		uint32_t ttl;
16328 
16329 		dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
16330 		if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
16331 		    !dns_rdataset_isassociated(kdset))
16332 		{
16333 			continue;
16334 		}
16335 
16336 		if (name != prevname) {
16337 			char nbuf[DNS_NAME_FORMATSIZE];
16338 			dns_name_format(name, nbuf, sizeof(nbuf));
16339 			snprintf(buf, sizeof(buf), "\n\n    name: %s", nbuf);
16340 			CHECK(putstr(text, buf));
16341 		}
16342 
16343 		for (result = dns_rdataset_first(kdset);
16344 		     result == ISC_R_SUCCESS; result = dns_rdataset_next(kdset))
16345 		{
16346 			char alg[DNS_SECALG_FORMATSIZE];
16347 			char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
16348 			dns_keytag_t keyid;
16349 			isc_region_t r;
16350 			isc_time_t t;
16351 			bool revoked;
16352 
16353 			dns_rdata_reset(&rdata);
16354 			dns_rdataset_current(kdset, &rdata);
16355 			result = dns_rdata_tostruct(&rdata, &kd, NULL);
16356 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
16357 
16358 			dns_rdata_toregion(&rdata, &r);
16359 			isc_region_consume(&r, 12);
16360 			keyid = dst_region_computeid(&r);
16361 
16362 			snprintf(buf, sizeof(buf), "\n    keyid: %u", keyid);
16363 			CHECK(putstr(text, buf));
16364 
16365 			dns_secalg_format(kd.algorithm, alg, sizeof(alg));
16366 			snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
16367 			CHECK(putstr(text, buf));
16368 
16369 			revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
16370 			snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
16371 				 revoked ? " REVOKE" : "",
16372 				 ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP"
16373 								     : "",
16374 				 (kd.flags == 0) ? " (none)" : "");
16375 			CHECK(putstr(text, buf));
16376 
16377 			isc_time_set(&t, kd.refresh, 0);
16378 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
16379 			snprintf(buf, sizeof(buf), "\n\tnext refresh: %s",
16380 				 tbuf);
16381 			CHECK(putstr(text, buf));
16382 
16383 			if (kd.removehd != 0) {
16384 				isc_time_set(&t, kd.removehd, 0);
16385 				isc_time_formathttptimestamp(&t, tbuf,
16386 							     sizeof(tbuf));
16387 				snprintf(buf, sizeof(buf), "\n\tremove at: %s",
16388 					 tbuf);
16389 				CHECK(putstr(text, buf));
16390 			}
16391 
16392 			isc_time_set(&t, kd.addhd, 0);
16393 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
16394 			if (kd.addhd == 0) {
16395 				snprintf(buf, sizeof(buf), "\n\tno trust");
16396 			} else if (revoked) {
16397 				snprintf(buf, sizeof(buf), "\n\ttrust revoked");
16398 			} else if (kd.addhd <= now) {
16399 				snprintf(buf, sizeof(buf),
16400 					 "\n\ttrusted since: %s", tbuf);
16401 			} else if (kd.addhd > now) {
16402 				snprintf(buf, sizeof(buf),
16403 					 "\n\ttrust pending: %s", tbuf);
16404 			}
16405 			CHECK(putstr(text, buf));
16406 		}
16407 	}
16408 
16409 	if (result == ISC_R_NOMORE) {
16410 		result = ISC_R_SUCCESS;
16411 	}
16412 
16413 cleanup:
16414 	if (ver != NULL) {
16415 		dns_rriterator_destroy(&rrit);
16416 		dns_db_closeversion(db, &ver, false);
16417 	}
16418 	if (db != NULL) {
16419 		dns_db_detach(&db);
16420 	}
16421 
16422 	return (result);
16423 }
16424 
16425 static isc_result_t
16426 mkey_status(dns_view_t *view, isc_buffer_t **text) {
16427 	isc_result_t result;
16428 	char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
16429 	isc_time_t t;
16430 
16431 	CHECK(putstr(text, "view: "));
16432 	CHECK(putstr(text, view->name));
16433 
16434 	CHECK(putstr(text, "\nnext scheduled event: "));
16435 
16436 	dns_zone_getrefreshkeytime(view->managed_keys, &t);
16437 	if (isc_time_isepoch(&t)) {
16438 		CHECK(putstr(text, "never"));
16439 	} else {
16440 		isc_time_formathttptimestamp(&t, msg, sizeof(msg));
16441 		CHECK(putstr(text, msg));
16442 	}
16443 
16444 	CHECK(mkey_dumpzone(view, text));
16445 
16446 cleanup:
16447 	return (result);
16448 }
16449 
16450 isc_result_t
16451 named_server_mkeys(named_server_t *server, isc_lex_t *lex,
16452 		   isc_buffer_t **text) {
16453 	char *cmd, *classtxt, *viewtxt = NULL;
16454 	isc_result_t result = ISC_R_SUCCESS;
16455 	dns_view_t *view = NULL;
16456 	dns_rdataclass_t rdclass;
16457 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
16458 	enum { NONE, STATUS, REFRESH, SYNC, DESTROY } opt = NONE;
16459 	bool found = false;
16460 	bool first = true;
16461 
16462 	REQUIRE(text != NULL);
16463 
16464 	/* Skip rndc command name */
16465 	cmd = next_token(lex, text);
16466 	if (cmd == NULL) {
16467 		return (ISC_R_UNEXPECTEDEND);
16468 	}
16469 
16470 	/* Get managed-keys subcommand */
16471 	cmd = next_token(lex, text);
16472 	if (cmd == NULL) {
16473 		return (ISC_R_UNEXPECTEDEND);
16474 	}
16475 
16476 	if (strcasecmp(cmd, "status") == 0) {
16477 		opt = STATUS;
16478 	} else if (strcasecmp(cmd, "refresh") == 0) {
16479 		opt = REFRESH;
16480 	} else if (strcasecmp(cmd, "sync") == 0) {
16481 		opt = SYNC;
16482 	} else if (strcasecmp(cmd, "destroy") == 0) {
16483 		opt = DESTROY;
16484 	} else {
16485 		snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
16486 		(void)putstr(text, msg);
16487 		result = ISC_R_UNEXPECTED;
16488 		goto cleanup;
16489 	}
16490 
16491 	/* Look for the optional class name. */
16492 	classtxt = next_token(lex, text);
16493 	if (classtxt != NULL) {
16494 		isc_textregion_t r;
16495 		r.base = classtxt;
16496 		r.length = strlen(classtxt);
16497 		result = dns_rdataclass_fromtext(&rdclass, &r);
16498 		if (result != ISC_R_SUCCESS) {
16499 			snprintf(msg, sizeof(msg), "unknown class '%s'",
16500 				 classtxt);
16501 			(void)putstr(text, msg);
16502 			goto cleanup;
16503 		}
16504 		viewtxt = next_token(lex, text);
16505 	}
16506 
16507 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16508 	     view = ISC_LIST_NEXT(view, link))
16509 	{
16510 		if (viewtxt != NULL && (rdclass != view->rdclass ||
16511 					strcmp(view->name, viewtxt) != 0))
16512 		{
16513 			continue;
16514 		}
16515 
16516 		if (view->managed_keys == NULL) {
16517 			if (viewtxt != NULL) {
16518 				snprintf(msg, sizeof(msg),
16519 					 "view '%s': no managed keys", viewtxt);
16520 				CHECK(putstr(text, msg));
16521 				goto cleanup;
16522 			} else {
16523 				continue;
16524 			}
16525 		}
16526 
16527 		found = true;
16528 
16529 		switch (opt) {
16530 		case REFRESH:
16531 			if (!first) {
16532 				CHECK(putstr(text, "\n"));
16533 			}
16534 			CHECK(mkey_refresh(view, text));
16535 			break;
16536 		case STATUS:
16537 			if (!first) {
16538 				CHECK(putstr(text, "\n\n"));
16539 			}
16540 			CHECK(mkey_status(view, text));
16541 			break;
16542 		case SYNC:
16543 			CHECK(dns_zone_flush(view->managed_keys));
16544 			break;
16545 		case DESTROY:
16546 			if (!first) {
16547 				CHECK(putstr(text, "\n"));
16548 			}
16549 			CHECK(mkey_destroy(server, view, text));
16550 			break;
16551 		default:
16552 			UNREACHABLE();
16553 		}
16554 
16555 		if (viewtxt != NULL) {
16556 			break;
16557 		}
16558 		first = false;
16559 	}
16560 
16561 	if (!found) {
16562 		CHECK(putstr(text, "no views with managed keys"));
16563 	}
16564 
16565 cleanup:
16566 	if (isc_buffer_usedlength(*text) > 0) {
16567 		(void)putnull(text);
16568 	}
16569 
16570 	return (result);
16571 }
16572 
16573 isc_result_t
16574 named_server_dnstap(named_server_t *server, isc_lex_t *lex,
16575 		    isc_buffer_t **text) {
16576 #ifdef HAVE_DNSTAP
16577 	char *ptr;
16578 	isc_result_t result;
16579 	bool reopen = false;
16580 	int backups = 0;
16581 
16582 	REQUIRE(text != NULL);
16583 
16584 	if (server->dtenv == NULL) {
16585 		return (ISC_R_NOTFOUND);
16586 	}
16587 
16588 	/* Check the command name. */
16589 	ptr = next_token(lex, text);
16590 	if (ptr == NULL) {
16591 		return (ISC_R_UNEXPECTEDEND);
16592 	}
16593 
16594 	/* "dnstap-reopen" was used in 9.11.0b1 */
16595 	if (strcasecmp(ptr, "dnstap-reopen") == 0) {
16596 		reopen = true;
16597 	} else {
16598 		ptr = next_token(lex, text);
16599 		if (ptr == NULL) {
16600 			return (ISC_R_UNEXPECTEDEND);
16601 		}
16602 	}
16603 
16604 	if (reopen || strcasecmp(ptr, "-reopen") == 0) {
16605 		backups = ISC_LOG_ROLLNEVER;
16606 	} else if ((strcasecmp(ptr, "-roll") == 0)) {
16607 		unsigned int n;
16608 		ptr = next_token(lex, text);
16609 		if (ptr != NULL) {
16610 			unsigned int u;
16611 			n = sscanf(ptr, "%u", &u);
16612 			if (n != 1U || u > INT_MAX) {
16613 				return (ISC_R_BADNUMBER);
16614 			}
16615 			backups = u;
16616 		} else {
16617 			backups = ISC_LOG_ROLLINFINITE;
16618 		}
16619 	} else {
16620 		return (DNS_R_SYNTAX);
16621 	}
16622 
16623 	result = dns_dt_reopen(server->dtenv, backups);
16624 	return (result);
16625 #else  /* ifdef HAVE_DNSTAP */
16626 	UNUSED(server);
16627 	UNUSED(lex);
16628 	UNUSED(text);
16629 	return (ISC_R_NOTIMPLEMENTED);
16630 #endif /* ifdef HAVE_DNSTAP */
16631 }
16632 
16633 isc_result_t
16634 named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) {
16635 	char *ptr;
16636 	isc_result_t result = ISC_R_SUCCESS;
16637 	uint32_t initial, idle, keepalive, advertised;
16638 	char msg[128];
16639 
16640 	/* Skip the command name. */
16641 	ptr = next_token(lex, text);
16642 	if (ptr == NULL) {
16643 		return (ISC_R_UNEXPECTEDEND);
16644 	}
16645 
16646 	isc_nm_gettimeouts(named_g_netmgr, &initial, &idle, &keepalive,
16647 			   &advertised);
16648 
16649 	/* Look for optional arguments. */
16650 	ptr = next_token(lex, NULL);
16651 	if (ptr != NULL) {
16652 		CHECK(isc_parse_uint32(&initial, ptr, 10));
16653 		initial *= 100;
16654 		if (initial > MAX_INITIAL_TIMEOUT) {
16655 			CHECK(ISC_R_RANGE);
16656 		}
16657 		if (initial < MIN_INITIAL_TIMEOUT) {
16658 			CHECK(ISC_R_RANGE);
16659 		}
16660 
16661 		ptr = next_token(lex, text);
16662 		if (ptr == NULL) {
16663 			return (ISC_R_UNEXPECTEDEND);
16664 		}
16665 		CHECK(isc_parse_uint32(&idle, ptr, 10));
16666 		idle *= 100;
16667 		if (idle > MAX_IDLE_TIMEOUT) {
16668 			CHECK(ISC_R_RANGE);
16669 		}
16670 		if (idle < MIN_IDLE_TIMEOUT) {
16671 			CHECK(ISC_R_RANGE);
16672 		}
16673 
16674 		ptr = next_token(lex, text);
16675 		if (ptr == NULL) {
16676 			return (ISC_R_UNEXPECTEDEND);
16677 		}
16678 		CHECK(isc_parse_uint32(&keepalive, ptr, 10));
16679 		keepalive *= 100;
16680 		if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
16681 			CHECK(ISC_R_RANGE);
16682 		}
16683 		if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
16684 			CHECK(ISC_R_RANGE);
16685 		}
16686 
16687 		ptr = next_token(lex, text);
16688 		if (ptr == NULL) {
16689 			return (ISC_R_UNEXPECTEDEND);
16690 		}
16691 		CHECK(isc_parse_uint32(&advertised, ptr, 10));
16692 		advertised *= 100;
16693 		if (advertised > MAX_ADVERTISED_TIMEOUT) {
16694 			CHECK(ISC_R_RANGE);
16695 		}
16696 
16697 		result = isc_task_beginexclusive(named_g_server->task);
16698 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
16699 
16700 		isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
16701 				   advertised);
16702 
16703 		isc_task_endexclusive(named_g_server->task);
16704 	}
16705 
16706 	snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100);
16707 	CHECK(putstr(text, msg));
16708 	snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100);
16709 	CHECK(putstr(text, msg));
16710 	snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n",
16711 		 keepalive / 100);
16712 	CHECK(putstr(text, msg));
16713 	snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u",
16714 		 advertised / 100);
16715 	CHECK(putstr(text, msg));
16716 
16717 cleanup:
16718 	if (isc_buffer_usedlength(*text) > 0) {
16719 		(void)putnull(text);
16720 	}
16721 
16722 	return (result);
16723 }
16724 
16725 isc_result_t
16726 named_server_servestale(named_server_t *server, isc_lex_t *lex,
16727 			isc_buffer_t **text) {
16728 	char *ptr, *classtxt, *viewtxt = NULL;
16729 	char msg[128];
16730 	dns_rdataclass_t rdclass = dns_rdataclass_in;
16731 	dns_view_t *view;
16732 	bool found = false;
16733 	dns_stale_answer_t staleanswersok = dns_stale_answer_conf;
16734 	bool wantstatus = false;
16735 	isc_result_t result = ISC_R_SUCCESS;
16736 	bool exclusive = false;
16737 
16738 	REQUIRE(text != NULL);
16739 
16740 	/* Skip the command name. */
16741 	ptr = next_token(lex, text);
16742 	if (ptr == NULL) {
16743 		return (ISC_R_UNEXPECTEDEND);
16744 	}
16745 
16746 	ptr = next_token(lex, NULL);
16747 	if (ptr == NULL) {
16748 		return (ISC_R_UNEXPECTEDEND);
16749 	}
16750 
16751 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
16752 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
16753 	{
16754 		staleanswersok = dns_stale_answer_yes;
16755 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
16756 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
16757 	{
16758 		staleanswersok = dns_stale_answer_no;
16759 	} else if (strcasecmp(ptr, "reset") == 0) {
16760 		staleanswersok = dns_stale_answer_conf;
16761 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
16762 		wantstatus = true;
16763 	} else {
16764 		return (DNS_R_SYNTAX);
16765 	}
16766 
16767 	/* Look for the optional class name. */
16768 	classtxt = next_token(lex, text);
16769 	if (classtxt != NULL) {
16770 		isc_textregion_t r;
16771 
16772 		/* Look for the optional view name. */
16773 		viewtxt = next_token(lex, text);
16774 
16775 		/*
16776 		 * If 'classtext' is not a valid class then it us a view name.
16777 		 */
16778 		r.base = classtxt;
16779 		r.length = strlen(classtxt);
16780 		result = dns_rdataclass_fromtext(&rdclass, &r);
16781 		if (result != ISC_R_SUCCESS) {
16782 			if (viewtxt != NULL) {
16783 				snprintf(msg, sizeof(msg), "unknown class '%s'",
16784 					 classtxt);
16785 				(void)putstr(text, msg);
16786 				goto cleanup;
16787 			}
16788 
16789 			viewtxt = classtxt;
16790 			classtxt = NULL;
16791 		}
16792 	}
16793 
16794 	result = isc_task_beginexclusive(server->task);
16795 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
16796 	exclusive = true;
16797 
16798 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16799 	     view = ISC_LIST_NEXT(view, link))
16800 	{
16801 		dns_ttl_t stale_ttl = 0;
16802 		uint32_t stale_refresh = 0;
16803 		dns_db_t *db = NULL;
16804 
16805 		if (classtxt != NULL && rdclass != view->rdclass) {
16806 			continue;
16807 		}
16808 
16809 		if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0) {
16810 			continue;
16811 		}
16812 
16813 		if (!wantstatus) {
16814 			view->staleanswersok = staleanswersok;
16815 			found = true;
16816 			continue;
16817 		}
16818 
16819 		db = NULL;
16820 		dns_db_attach(view->cachedb, &db);
16821 		(void)dns_db_getservestalettl(db, &stale_ttl);
16822 		(void)dns_db_getservestalerefresh(db, &stale_refresh);
16823 		dns_db_detach(&db);
16824 		if (found) {
16825 			CHECK(putstr(text, "\n"));
16826 		}
16827 		CHECK(putstr(text, view->name));
16828 		CHECK(putstr(text, ": "));
16829 		switch (view->staleanswersok) {
16830 		case dns_stale_answer_yes:
16831 			if (stale_ttl > 0) {
16832 				CHECK(putstr(text, "stale cache enabled; stale "
16833 						   "answers enabled"));
16834 			} else {
16835 				CHECK(putstr(text,
16836 					     "stale cache disabled; stale "
16837 					     "answers unavailable"));
16838 			}
16839 			break;
16840 		case dns_stale_answer_no:
16841 			if (stale_ttl > 0) {
16842 				CHECK(putstr(text, "stale cache enabled; stale "
16843 						   "answers disabled"));
16844 			} else {
16845 				CHECK(putstr(text,
16846 					     "stale cache disabled; stale "
16847 					     "answers unavailable"));
16848 			}
16849 			break;
16850 		case dns_stale_answer_conf:
16851 			if (view->staleanswersenable && stale_ttl > 0) {
16852 				CHECK(putstr(text, "stale cache enabled; stale "
16853 						   "answers enabled"));
16854 			} else if (stale_ttl > 0) {
16855 				CHECK(putstr(text, "stale cache enabled; stale "
16856 						   "answers disabled"));
16857 			} else {
16858 				CHECK(putstr(text,
16859 					     "stale cache disabled; stale "
16860 					     "answers unavailable"));
16861 			}
16862 			break;
16863 		}
16864 		if (stale_ttl > 0) {
16865 			snprintf(msg, sizeof(msg),
16866 				 " (stale-answer-ttl=%u max-stale-ttl=%u "
16867 				 "stale-refresh-time=%u)",
16868 				 view->staleanswerttl, stale_ttl,
16869 				 stale_refresh);
16870 			CHECK(putstr(text, msg));
16871 		}
16872 		found = true;
16873 	}
16874 
16875 	if (!found) {
16876 		result = ISC_R_NOTFOUND;
16877 	}
16878 
16879 cleanup:
16880 	if (exclusive) {
16881 		isc_task_endexclusive(named_g_server->task);
16882 	}
16883 
16884 	if (isc_buffer_usedlength(*text) > 0) {
16885 		(void)putnull(text);
16886 	}
16887 
16888 	return (result);
16889 }
16890