xref: /netbsd-src/external/mpl/bind/dist/bin/named/server.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: server.c,v 1.23 2025/01/26 16:24:33 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 #include <ctype.h>
19 #include <inttypes.h>
20 #include <limits.h>
21 #include <signal.h>
22 #include <stdbool.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 
29 #ifdef HAVE_DNSTAP
30 #include <fstrm.h>
31 #endif
32 
33 #ifdef HAVE_LIBSYSTEMD
34 #include <systemd/sd-daemon.h>
35 #endif
36 
37 #include <isc/async.h>
38 #include <isc/attributes.h>
39 #include <isc/base64.h>
40 #include <isc/commandline.h>
41 #include <isc/dir.h>
42 #include <isc/file.h>
43 #include <isc/fips.h>
44 #include <isc/hash.h>
45 #include <isc/hex.h>
46 #include <isc/hmac.h>
47 #include <isc/httpd.h>
48 #include <isc/job.h>
49 #include <isc/lex.h>
50 #include <isc/loop.h>
51 #include <isc/meminfo.h>
52 #include <isc/netmgr.h>
53 #include <isc/nonce.h>
54 #include <isc/parseint.h>
55 #include <isc/portset.h>
56 #include <isc/refcount.h>
57 #include <isc/result.h>
58 #include <isc/signal.h>
59 #include <isc/siphash.h>
60 #include <isc/stats.h>
61 #include <isc/stdio.h>
62 #include <isc/string.h>
63 #include <isc/time.h>
64 #include <isc/timer.h>
65 #include <isc/util.h>
66 
67 #include <dns/adb.h>
68 #include <dns/badcache.h>
69 #include <dns/cache.h>
70 #include <dns/catz.h>
71 #include <dns/db.h>
72 #include <dns/dispatch.h>
73 #include <dns/dlz.h>
74 #include <dns/dns64.h>
75 #include <dns/dnsrps.h>
76 #include <dns/dnssec.h>
77 #include <dns/dyndb.h>
78 #include <dns/fixedname.h>
79 #include <dns/forward.h>
80 #include <dns/geoip.h>
81 #include <dns/journal.h>
82 #include <dns/kasp.h>
83 #include <dns/keymgr.h>
84 #include <dns/keystore.h>
85 #include <dns/keytable.h>
86 #include <dns/keyvalues.h>
87 #include <dns/master.h>
88 #include <dns/masterdump.h>
89 #include <dns/nametree.h>
90 #include <dns/nsec3.h>
91 #include <dns/nta.h>
92 #include <dns/order.h>
93 #include <dns/peer.h>
94 #include <dns/private.h>
95 #include <dns/rbt.h>
96 #include <dns/rdataclass.h>
97 #include <dns/rdatalist.h>
98 #include <dns/rdataset.h>
99 #include <dns/rdatastruct.h>
100 #include <dns/resolver.h>
101 #include <dns/rootns.h>
102 #include <dns/rriterator.h>
103 #include <dns/secalg.h>
104 #include <dns/soa.h>
105 #include <dns/stats.h>
106 #include <dns/time.h>
107 #include <dns/tkey.h>
108 #include <dns/tsig.h>
109 #include <dns/ttl.h>
110 #include <dns/view.h>
111 #include <dns/zone.h>
112 #include <dns/zt.h>
113 
114 #include <dst/dst.h>
115 
116 #include <isccfg/check.h>
117 #include <isccfg/grammar.h>
118 #include <isccfg/kaspconf.h>
119 #include <isccfg/namedconf.h>
120 
121 #include <ns/client.h>
122 #include <ns/hooks.h>
123 #include <ns/interfacemgr.h>
124 #include <ns/listenlist.h>
125 
126 #include <named/config.h>
127 #include <named/control.h>
128 #if defined(HAVE_GEOIP2)
129 #include <named/geoip.h>
130 #endif /* HAVE_GEOIP2 */
131 #include <named/log.h>
132 #include <named/logconf.h>
133 #include <named/main.h>
134 #include <named/os.h>
135 #include <named/server.h>
136 #include <named/statschannel.h>
137 #include <named/tkeyconf.h>
138 #include <named/transportconf.h>
139 #include <named/tsigconf.h>
140 #include <named/zoneconf.h>
141 #ifdef HAVE_LIBSCF
142 #include <stdlib.h>
143 
144 #include <named/smf_globals.h>
145 #endif /* ifdef HAVE_LIBSCF */
146 
147 #ifdef HAVE_LMDB
148 #include <lmdb.h>
149 #define configure_newzones configure_newzones_db
150 #define dumpzone	   dumpzone_db
151 #else /* HAVE_LMDB */
152 #define configure_newzones configure_newzones_file
153 #define dumpzone	   dumpzone_file
154 #endif /* HAVE_LMDB */
155 
156 #ifndef SIZE_MAX
157 #define SIZE_MAX ((size_t)-1)
158 #endif /* ifndef SIZE_MAX */
159 
160 #ifndef SIZE_AS_PERCENT
161 #define SIZE_AS_PERCENT ((size_t)-2)
162 #endif /* ifndef SIZE_AS_PERCENT */
163 
164 /* RFC7828 defines timeout as 16-bit value specified in units of 100
165  * milliseconds, so the maximum and minimum advertised and keepalive
166  * timeouts are capped by the data type (it's ~109 minutes)
167  */
168 #define MIN_INITIAL_TIMEOUT    UINT32_C(2500)	/* 2.5 seconds */
169 #define MAX_INITIAL_TIMEOUT    UINT32_C(120000) /* 2 minutes */
170 #define MIN_IDLE_TIMEOUT       UINT32_C(100)	/* 0.1 seconds */
171 #define MAX_IDLE_TIMEOUT       UINT32_C(120000) /* 2 minutes */
172 #define MIN_KEEPALIVE_TIMEOUT  UINT32_C(100)	/* 0.1 seconds */
173 #define MAX_KEEPALIVE_TIMEOUT  UINT32_C(UINT16_MAX * 100)
174 #define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */
175 #define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100)
176 
177 /*%
178  * Check an operation for failure.  Assumes that the function
179  * using it has a 'result' variable and a 'cleanup' label.
180  */
181 #define CHECK(op)                            \
182 	do {                                 \
183 		result = (op);               \
184 		if (result != ISC_R_SUCCESS) \
185 			goto cleanup;        \
186 	} while (0)
187 
188 #define TCHECK(op)                               \
189 	do {                                     \
190 		tresult = (op);                  \
191 		if (tresult != ISC_R_SUCCESS) {  \
192 			isc_buffer_clear(*text); \
193 			goto cleanup;            \
194 		}                                \
195 	} while (0)
196 
197 #define CHECKM(op, msg)                                                        \
198 	do {                                                                   \
199 		result = (op);                                                 \
200 		if (result != ISC_R_SUCCESS) {                                 \
201 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
202 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
203 				      "%s: %s", msg,                           \
204 				      isc_result_totext(result));              \
205 			goto cleanup;                                          \
206 		}                                                              \
207 	} while (0)
208 
209 #define CHECKMF(op, msg, file)                                                 \
210 	do {                                                                   \
211 		result = (op);                                                 \
212 		if (result != ISC_R_SUCCESS) {                                 \
213 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
214 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
215 				      "%s '%s': %s", msg, file,                \
216 				      isc_result_totext(result));              \
217 			goto cleanup;                                          \
218 		}                                                              \
219 	} while (0)
220 
221 #define CHECKFATAL(op, msg)                    \
222 	{                                      \
223 		result = (op);                 \
224 		if (result != ISC_R_SUCCESS) { \
225 			fatal(msg, result);    \
226 		}                              \
227 	}
228 
229 /*%
230  * Maximum ADB size for views that share a cache.  Use this limit to suppress
231  * the total of memory footprint, which should be the main reason for sharing
232  * a cache.  Only effective when a finite max-cache-size is specified.
233  * This is currently defined to be 8MB.
234  */
235 #define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
236 
237 struct named_dispatch {
238 	isc_sockaddr_t addr;
239 	unsigned int dispatchgen;
240 	dns_dispatch_t *dispatch;
241 	ISC_LINK(struct named_dispatch) link;
242 };
243 
244 struct named_cache {
245 	dns_cache_t *cache;
246 	dns_view_t *primaryview;
247 	bool needflush;
248 	bool adbsizeadjusted;
249 	dns_rdataclass_t rdclass;
250 	ISC_LINK(named_cache_t) link;
251 };
252 
253 struct dumpcontext {
254 	isc_mem_t *mctx;
255 	bool dumpcache;
256 	bool dumpzones;
257 	bool dumpadb;
258 	bool dumpexpired;
259 	bool dumpfail;
260 	FILE *fp;
261 	ISC_LIST(struct viewlistentry) viewlist;
262 	struct viewlistentry *view;
263 	struct zonelistentry *zone;
264 	dns_dumpctx_t *mdctx;
265 	dns_db_t *db;
266 	dns_db_t *cache;
267 	isc_loop_t *loop;
268 	dns_dbversion_t *version;
269 };
270 
271 struct viewlistentry {
272 	dns_view_t *view;
273 	ISC_LINK(struct viewlistentry) link;
274 	ISC_LIST(struct zonelistentry) zonelist;
275 };
276 
277 struct zonelistentry {
278 	dns_zone_t *zone;
279 	ISC_LINK(struct zonelistentry) link;
280 };
281 
282 /*%
283  * Message-to-view matching context to run message signature validation
284  * asynchronously.
285  */
286 typedef struct matching_view_ctx {
287 	isc_netaddr_t *srcaddr;
288 	isc_netaddr_t *destaddr;
289 	dns_message_t *message;
290 	dns_aclenv_t *env;
291 	ns_server_t *sctx;
292 	isc_loop_t *loop;
293 	isc_job_cb cb;
294 	void *cbarg;
295 	isc_result_t *sigresult;
296 	isc_result_t *viewmatchresult;
297 	isc_result_t quota_result;
298 	dns_view_t **viewp;
299 	dns_view_t *view;
300 } matching_view_ctx_t;
301 
302 /*%
303  * Configuration context to retain for each view that allows
304  * new zones to be added at runtime.
305  */
306 typedef struct ns_cfgctx {
307 	isc_mem_t *mctx;
308 	cfg_parser_t *conf_parser;
309 	cfg_parser_t *add_parser;
310 	cfg_obj_t *config;
311 	cfg_obj_t *vconfig;
312 	cfg_obj_t *nzf_config;
313 	cfg_aclconfctx_t *actx;
314 } ns_cfgctx_t;
315 
316 /*%
317  * A function to write out added-zone configuration to the new_zone_file
318  * specified in 'view'. Maybe called by delete_zoneconf().
319  */
320 typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
321 
322 /*%
323  * Holds state information for the initial zone loading process.
324  * Uses the isc_refcount structure to count the number of views
325  * with pending zone loads, dereferencing as each view finishes.
326  */
327 typedef struct {
328 	named_server_t *server;
329 	bool reconfig;
330 	isc_refcount_t refs;
331 } ns_zoneload_t;
332 
333 typedef struct {
334 	named_server_t *server;
335 } catz_cb_data_t;
336 
337 typedef struct catz_chgzone {
338 	isc_mem_t *mctx;
339 	dns_catz_entry_t *entry;
340 	dns_catz_zone_t *origin;
341 	dns_view_t *view;
342 	catz_cb_data_t *cbd;
343 	bool mod;
344 } catz_chgzone_t;
345 
346 typedef struct catz_reconfig_data {
347 	dns_catz_zone_t *catz;
348 	const cfg_obj_t *config;
349 	catz_cb_data_t *cbd;
350 } catz_reconfig_data_t;
351 
352 typedef enum {
353 	CATZ_ADDZONE,
354 	CATZ_MODZONE,
355 	CATZ_DELZONE,
356 } catz_type_t;
357 
358 typedef struct {
359 	unsigned int magic;
360 #define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
361 	isc_buffer_t **text;
362 	isc_result_t result;
363 } ns_dzarg_t;
364 
365 /*
366  * These zones should not leak onto the Internet.
367  */
368 const char *empty_zones[] = {
369 	/* RFC 1918 */
370 	"10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
371 	"18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
372 	"21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
373 	"24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
374 	"27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
375 	"30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
376 
377 	/* RFC 6598 */
378 	"64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
379 	"67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
380 	"70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
381 	"73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
382 	"76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
383 	"79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
384 	"82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
385 	"85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
386 	"88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
387 	"91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
388 	"94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
389 	"97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
390 	"100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA", "102.100.IN-ADDR.ARPA",
391 	"103.100.IN-ADDR.ARPA", "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
392 	"106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA", "108.100.IN-ADDR.ARPA",
393 	"109.100.IN-ADDR.ARPA", "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
394 	"112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA", "114.100.IN-ADDR.ARPA",
395 	"115.100.IN-ADDR.ARPA", "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
396 	"118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA", "120.100.IN-ADDR.ARPA",
397 	"121.100.IN-ADDR.ARPA", "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
398 	"124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA", "126.100.IN-ADDR.ARPA",
399 	"127.100.IN-ADDR.ARPA",
400 
401 	/* RFC 5735 and RFC 5737 */
402 	"0.IN-ADDR.ARPA",		/* THIS NETWORK */
403 	"127.IN-ADDR.ARPA",		/* LOOPBACK */
404 	"254.169.IN-ADDR.ARPA",		/* LINK LOCAL */
405 	"2.0.192.IN-ADDR.ARPA",		/* TEST NET */
406 	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
407 	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
408 	"255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
409 
410 	/* Local IPv6 Unicast Addresses */
411 	"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."
412 	"ARPA",
413 	"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."
414 	"ARPA",
415 	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
416 	"D.F.IP6.ARPA", "8.E.F.IP6.ARPA", /* LINK LOCAL */
417 	"9.E.F.IP6.ARPA",		  /* LINK LOCAL */
418 	"A.E.F.IP6.ARPA",		  /* LINK LOCAL */
419 	"B.E.F.IP6.ARPA",		  /* LINK LOCAL */
420 
421 	/* Example Prefix, RFC 3849. */
422 	"8.B.D.0.1.0.0.2.IP6.ARPA",
423 
424 	/* RFC 7534 */
425 	"EMPTY.AS112.ARPA",
426 
427 	/* RFC 8375 */
428 	"HOME.ARPA",
429 
430 	/* RFC 9462 */
431 	"RESOLVER.ARPA",
432 
433 	NULL
434 };
435 
436 noreturn static void
437 fatal(const char *msg, isc_result_t result);
438 
439 static void
440 named_server_reload(void *arg);
441 
442 #ifdef HAVE_LIBNGHTTP2
443 static isc_result_t
444 listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
445 	       const ns_listen_tls_params_t *tls_params,
446 	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
447 	       isc_mem_t *mctx, isc_nm_proxy_type_t proxy,
448 	       ns_listenelt_t **target);
449 #endif
450 
451 static isc_result_t
452 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
453 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
454 		     isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target);
455 
456 static isc_result_t
457 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
458 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
459 		      isc_tlsctx_cache_t *tlsctx_cache,
460 		      ns_listenlist_t **target);
461 
462 static isc_result_t
463 configure_forward(const cfg_obj_t *config, dns_view_t *view,
464 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
465 		  const cfg_obj_t *forwardtype);
466 
467 static isc_result_t
468 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
469 		     const cfg_obj_t *alternates);
470 
471 static isc_result_t
472 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
473 	       const cfg_obj_t *vconfig, dns_view_t *view,
474 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
475 	       dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
476 	       bool added, bool old_rpz_ok, bool is_catz_member, bool modify);
477 
478 static void
479 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
480 			     dns_view_t *view);
481 
482 static isc_result_t
483 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
484 		   cfg_aclconfctx_t *actx);
485 
486 static const cfg_obj_t *
487 find_maplist(const cfg_obj_t *config, const char *listname, const char *name);
488 
489 static isc_result_t
490 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
491 
492 static void
493 newzone_cfgctx_destroy(void **cfgp);
494 
495 static isc_result_t
496 putstr(isc_buffer_t **b, const char *str);
497 
498 static isc_result_t
499 putmem(isc_buffer_t **b, const char *str, size_t len);
500 
501 static isc_result_t
502 putuint8(isc_buffer_t **b, uint8_t val);
503 
504 static isc_result_t
505 putnull(isc_buffer_t **b);
506 
507 #ifdef HAVE_LMDB
508 static isc_result_t
509 nzd_writable(dns_view_t *view);
510 
511 static isc_result_t
512 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
513 
514 static isc_result_t
515 nzd_env_reopen(dns_view_t *view);
516 
517 static void
518 nzd_env_close(dns_view_t *view);
519 
520 static isc_result_t
521 nzd_close(MDB_txn **txnp, bool commit);
522 #else  /* ifdef HAVE_LMDB */
523 static isc_result_t
524 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
525 #endif /* ifdef HAVE_LMDB */
526 
527 static isc_result_t
528 load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg);
529 
530 /*%
531  * Configure a single view ACL at '*aclp'.  Get its configuration from
532  * 'vconfig' (for per-view configuration) and maybe from 'config'
533  */
534 static isc_result_t
535 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
536 		   const cfg_obj_t *gconfig, const char *aclname,
537 		   const char *acltuplename, cfg_aclconfctx_t *actx,
538 		   isc_mem_t *mctx, dns_acl_t **aclp) {
539 	isc_result_t result;
540 	const cfg_obj_t *maps[4];
541 	const cfg_obj_t *aclobj = NULL;
542 	int i = 0;
543 
544 	if (*aclp != NULL) {
545 		dns_acl_detach(aclp);
546 	}
547 	if (vconfig != NULL) {
548 		maps[i++] = cfg_tuple_get(vconfig, "options");
549 	}
550 	if (config != NULL) {
551 		const cfg_obj_t *options = NULL;
552 		(void)cfg_map_get(config, "options", &options);
553 		if (options != NULL) {
554 			maps[i++] = options;
555 		}
556 	}
557 	if (gconfig != NULL) {
558 		const cfg_obj_t *options = NULL;
559 		(void)cfg_map_get(gconfig, "options", &options);
560 		if (options != NULL) {
561 			maps[i++] = options;
562 		}
563 	}
564 	maps[i] = NULL;
565 
566 	(void)named_config_get(maps, aclname, &aclobj);
567 	if (aclobj == NULL) {
568 		/*
569 		 * No value available.	*aclp == NULL.
570 		 */
571 		return ISC_R_SUCCESS;
572 	}
573 
574 	if (acltuplename != NULL) {
575 		/*
576 		 * If the ACL is given in an optional tuple, retrieve it.
577 		 * The parser should have ensured that a valid object be
578 		 * returned.
579 		 */
580 		aclobj = cfg_tuple_get(aclobj, acltuplename);
581 	}
582 
583 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
584 				    aclp);
585 
586 	return result;
587 }
588 
589 /*%
590  * Configure a sortlist at '*aclp'.  Essentially the same as
591  * configure_view_acl() except it calls cfg_acl_fromconfig with a
592  * nest_level value of 2.
593  */
594 static isc_result_t
595 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
596 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
597 			dns_acl_t **aclp) {
598 	isc_result_t result;
599 	const cfg_obj_t *maps[3];
600 	const cfg_obj_t *aclobj = NULL;
601 	int i = 0;
602 
603 	if (*aclp != NULL) {
604 		dns_acl_detach(aclp);
605 	}
606 	if (vconfig != NULL) {
607 		maps[i++] = cfg_tuple_get(vconfig, "options");
608 	}
609 	if (config != NULL) {
610 		const cfg_obj_t *options = NULL;
611 		(void)cfg_map_get(config, "options", &options);
612 		if (options != NULL) {
613 			maps[i++] = options;
614 		}
615 	}
616 	maps[i] = NULL;
617 
618 	(void)named_config_get(maps, "sortlist", &aclobj);
619 	if (aclobj == NULL) {
620 		return ISC_R_SUCCESS;
621 	}
622 
623 	/*
624 	 * Use a nest level of 3 for the "top level" of the sortlist;
625 	 * this means each entry in the top three levels will be stored
626 	 * as lists of separate, nested ACLs, rather than merged together
627 	 * into IP tables as is usually done with ACLs.
628 	 */
629 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
630 				    aclp);
631 
632 	return result;
633 }
634 
635 static isc_result_t
636 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
637 			 const char *confname, const char *conftuplename,
638 			 isc_mem_t *mctx, dns_nametree_t **ntp) {
639 	isc_result_t result = ISC_R_SUCCESS;
640 	const cfg_obj_t *maps[3];
641 	const cfg_obj_t *obj = NULL;
642 	const cfg_listelt_t *element = NULL;
643 	int i = 0;
644 	dns_fixedname_t fixed;
645 	dns_name_t *name = NULL;
646 	isc_buffer_t b;
647 	const char *str = NULL;
648 	const cfg_obj_t *nameobj = NULL;
649 
650 	if (*ntp != NULL) {
651 		dns_nametree_detach(ntp);
652 	}
653 	dns_nametree_create(mctx, DNS_NAMETREE_BOOL, confname, ntp);
654 
655 	if (vconfig != NULL) {
656 		maps[i++] = cfg_tuple_get(vconfig, "options");
657 	}
658 	if (config != NULL) {
659 		const cfg_obj_t *options = NULL;
660 		(void)cfg_map_get(config, "options", &options);
661 		if (options != NULL) {
662 			maps[i++] = options;
663 		}
664 	}
665 	maps[i] = NULL;
666 
667 	(void)named_config_get(maps, confname, &obj);
668 	if (obj == NULL) {
669 		/*
670 		 * No value available.	*ntp == NULL.
671 		 */
672 		return ISC_R_SUCCESS;
673 	}
674 
675 	if (conftuplename != NULL) {
676 		obj = cfg_tuple_get(obj, conftuplename);
677 		if (cfg_obj_isvoid(obj)) {
678 			return ISC_R_SUCCESS;
679 		}
680 	}
681 
682 	name = dns_fixedname_initname(&fixed);
683 	for (element = cfg_list_first(obj); element != NULL;
684 	     element = cfg_list_next(element))
685 	{
686 		nameobj = cfg_listelt_value(element);
687 		str = cfg_obj_asstring(nameobj);
688 		isc_buffer_constinit(&b, str, strlen(str));
689 		isc_buffer_add(&b, strlen(str));
690 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
691 		result = dns_nametree_add(*ntp, name, true);
692 		if (result != ISC_R_SUCCESS) {
693 			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
694 				    "failed to add %s for %s: %s", str,
695 				    confname, isc_result_totext(result));
696 			goto cleanup;
697 		}
698 	}
699 
700 	return ISC_R_SUCCESS;
701 
702 cleanup:
703 	dns_nametree_detach(ntp);
704 	return result;
705 }
706 
707 static isc_result_t
708 ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
709 	      unsigned char *digest, dns_rdata_ds_t *ds) {
710 	isc_result_t result;
711 	dns_rdata_dnskey_t keystruct;
712 	dns_rdata_t rdata = DNS_RDATA_INIT;
713 	uint32_t rdata1, rdata2, rdata3;
714 	const char *datastr = NULL, *namestr = NULL;
715 	unsigned char data[4096];
716 	isc_buffer_t databuf;
717 	unsigned char rrdata[4096];
718 	isc_buffer_t rrdatabuf;
719 	isc_region_t r;
720 	dns_fixedname_t fname;
721 	dns_name_t *name = NULL;
722 	isc_buffer_t namebuf;
723 	const char *atstr = NULL;
724 	enum {
725 		INIT_DNSKEY,
726 		STATIC_DNSKEY,
727 		INIT_DS,
728 		STATIC_DS,
729 		TRUSTED
730 	} anchortype;
731 
732 	REQUIRE(namestrp != NULL && *namestrp == NULL);
733 	REQUIRE(ds != NULL);
734 
735 	/* if DNSKEY, flags; if DS, key tag */
736 	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
737 
738 	/* if DNSKEY, protocol; if DS, algorithm */
739 	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
740 
741 	/* if DNSKEY, algorithm; if DS, digest type */
742 	rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3"));
743 
744 	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
745 	*namestrp = namestr;
746 
747 	name = dns_fixedname_initname(&fname);
748 	isc_buffer_constinit(&namebuf, namestr, strlen(namestr));
749 	isc_buffer_add(&namebuf, strlen(namestr));
750 	CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL));
751 
752 	if (*initialp) {
753 		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
754 
755 		if (strcasecmp(atstr, "static-key") == 0) {
756 			*initialp = false;
757 			anchortype = STATIC_DNSKEY;
758 		} else if (strcasecmp(atstr, "static-ds") == 0) {
759 			*initialp = false;
760 			anchortype = STATIC_DS;
761 		} else if (strcasecmp(atstr, "initial-key") == 0) {
762 			anchortype = INIT_DNSKEY;
763 		} else if (strcasecmp(atstr, "initial-ds") == 0) {
764 			anchortype = INIT_DS;
765 		} else {
766 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
767 				    "key '%s': "
768 				    "invalid initialization method '%s'",
769 				    namestr, atstr);
770 			result = ISC_R_FAILURE;
771 			goto cleanup;
772 		}
773 	} else {
774 		anchortype = TRUSTED;
775 	}
776 
777 	isc_buffer_init(&databuf, data, sizeof(data));
778 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
779 
780 	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
781 				.common.rdtype = dns_rdatatype_ds };
782 
783 	ISC_LINK_INIT(&ds->common, link);
784 
785 	switch (anchortype) {
786 	case INIT_DNSKEY:
787 	case STATIC_DNSKEY:
788 	case TRUSTED:
789 		/*
790 		 * This function should never be reached for view
791 		 * class other than IN
792 		 */
793 		keystruct.common.rdclass = dns_rdataclass_in;
794 		keystruct.common.rdtype = dns_rdatatype_dnskey;
795 
796 		/*
797 		 * The key data in keystruct is not dynamically allocated.
798 		 */
799 		keystruct.mctx = NULL;
800 
801 		ISC_LINK_INIT(&keystruct.common, link);
802 
803 		if (rdata1 > 0xffff) {
804 			CHECKM(ISC_R_RANGE, "key flags");
805 		}
806 		if (rdata1 & DNS_KEYFLAG_REVOKE) {
807 			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
808 		}
809 		if (rdata2 > 0xff) {
810 			CHECKM(ISC_R_RANGE, "key protocol");
811 		}
812 		if (rdata3 > 0xff) {
813 			CHECKM(ISC_R_RANGE, "key algorithm");
814 		}
815 
816 		keystruct.flags = (uint16_t)rdata1;
817 		keystruct.protocol = (uint8_t)rdata2;
818 		keystruct.algorithm = (uint8_t)rdata3;
819 
820 		if (!dst_algorithm_supported(keystruct.algorithm)) {
821 			CHECK(DST_R_UNSUPPORTEDALG);
822 		}
823 
824 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
825 		CHECK(isc_base64_decodestring(datastr, &databuf));
826 		isc_buffer_usedregion(&databuf, &r);
827 		keystruct.datalen = r.length;
828 		keystruct.data = r.base;
829 
830 		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
831 					   keystruct.common.rdtype, &keystruct,
832 					   &rrdatabuf));
833 		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
834 					  digest, ds));
835 		break;
836 
837 	case INIT_DS:
838 	case STATIC_DS:
839 		if (rdata1 > 0xffff) {
840 			CHECKM(ISC_R_RANGE, "key tag");
841 		}
842 		if (rdata2 > 0xff) {
843 			CHECKM(ISC_R_RANGE, "key algorithm");
844 		}
845 		if (rdata3 > 0xff) {
846 			CHECKM(ISC_R_RANGE, "digest type");
847 		}
848 
849 		ds->key_tag = (uint16_t)rdata1;
850 		ds->algorithm = (uint8_t)rdata2;
851 		ds->digest_type = (uint8_t)rdata3;
852 
853 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
854 		CHECK(isc_hex_decodestring(datastr, &databuf));
855 		isc_buffer_usedregion(&databuf, &r);
856 
857 		switch (ds->digest_type) {
858 		case DNS_DSDIGEST_SHA1:
859 			if (r.length != ISC_SHA1_DIGESTLENGTH) {
860 				CHECK(ISC_R_UNEXPECTEDEND);
861 			}
862 			break;
863 		case DNS_DSDIGEST_SHA256:
864 			if (r.length != ISC_SHA256_DIGESTLENGTH) {
865 				CHECK(ISC_R_UNEXPECTEDEND);
866 			}
867 			break;
868 		case DNS_DSDIGEST_SHA384:
869 			if (r.length != ISC_SHA384_DIGESTLENGTH) {
870 				CHECK(ISC_R_UNEXPECTEDEND);
871 			}
872 			break;
873 		default:
874 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
875 				    "key '%s': "
876 				    "unknown ds digest type %u",
877 				    namestr, ds->digest_type);
878 			result = ISC_R_FAILURE;
879 			goto cleanup;
880 			break;
881 		}
882 
883 		ds->length = r.length;
884 		ds->digest = digest;
885 		memmove(ds->digest, r.base, r.length);
886 
887 		break;
888 
889 	default:
890 		UNREACHABLE();
891 	}
892 
893 	return ISC_R_SUCCESS;
894 
895 cleanup:
896 	return result;
897 }
898 
899 static void
900 sfd_add(const dns_name_t *name, void *arg) {
901 	if (arg != NULL) {
902 		dns_view_sfd_add(arg, name);
903 	}
904 }
905 
906 /*%
907  * Parse 'key' in the context of view configuration 'vconfig'.  If successful,
908  * add the key to 'secroots' if both of the following conditions are true:
909  *
910  *   - 'keyname_match' is NULL or it matches the owner name of 'key',
911  *   - support for the algorithm used by 'key' is not disabled by 'resolver'
912  *     for the owner name of 'key'.
913  *
914  * 'managed' is true for managed keys and false for trusted keys.  'mctx' is
915  * the memory context to use for allocating memory.
916  */
917 static isc_result_t
918 process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
919 	    const dns_name_t *keyname_match, dns_view_t *view, bool managed) {
920 	dns_fixedname_t fkeyname;
921 	dns_name_t *keyname = NULL;
922 	const char *namestr = NULL;
923 	dns_rdata_ds_t ds;
924 	isc_result_t result;
925 	bool initializing = managed;
926 	unsigned char digest[ISC_MAX_MD_SIZE];
927 	isc_buffer_t b;
928 
929 	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
930 
931 	switch (result) {
932 	case ISC_R_SUCCESS:
933 		/*
934 		 * Trust anchor was parsed correctly.
935 		 */
936 		isc_buffer_constinit(&b, namestr, strlen(namestr));
937 		isc_buffer_add(&b, strlen(namestr));
938 		keyname = dns_fixedname_initname(&fkeyname);
939 		result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
940 		if (result != ISC_R_SUCCESS) {
941 			return result;
942 		}
943 		break;
944 	case DST_R_UNSUPPORTEDALG:
945 	case DST_R_BADKEYTYPE:
946 		/*
947 		 * Key was parsed correctly, but it cannot be used; this is not
948 		 * a fatal error - log a warning about this key being ignored,
949 		 * but do not prevent any further ones from being processed.
950 		 */
951 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
952 			    "ignoring %s for '%s': %s",
953 			    initializing ? "initial-key" : "static-key",
954 			    namestr, isc_result_totext(result));
955 		return ISC_R_SUCCESS;
956 	case DST_R_NOCRYPTO:
957 		/*
958 		 * Crypto support is not available.
959 		 */
960 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
961 			    "ignoring %s for '%s': no crypto support",
962 			    initializing ? "initial-key" : "static-key",
963 			    namestr);
964 		return result;
965 	default:
966 		/*
967 		 * Something unexpected happened; we have no choice but to
968 		 * indicate an error so that the configuration loading process
969 		 * is interrupted.
970 		 */
971 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
972 			    "configuring %s for '%s': %s",
973 			    initializing ? "initial-key" : "static-key",
974 			    namestr, isc_result_totext(result));
975 		return ISC_R_FAILURE;
976 	}
977 
978 	/*
979 	 * If the caller requested to only load keys for a specific name and
980 	 * the owner name of this key does not match the requested name, do not
981 	 * load it.
982 	 */
983 	if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) {
984 		goto done;
985 	}
986 
987 	/*
988 	 * Ensure that 'resolver' allows using the algorithm of this key for
989 	 * its owner name.  If it does not, do not load the key and log a
990 	 * warning, but do not prevent further keys from being processed.
991 	 */
992 	if (!dns_resolver_algorithm_supported(view->resolver, keyname,
993 					      ds.algorithm))
994 	{
995 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
996 			    "ignoring %s for '%s': algorithm is disabled",
997 			    initializing ? "initial-key" : "static-key",
998 			    namestr);
999 		goto done;
1000 	}
1001 
1002 	/*
1003 	 * Add the key to 'secroots'.  Keys from a "trust-anchors" or
1004 	 * "managed-keys" statement may be either static or initializing
1005 	 * keys. If it's not initializing, we don't want to treat it as
1006 	 * managed, so we use 'initializing' twice here, for both the
1007 	 * 'managed' and 'initializing' arguments to dns_keytable_add().
1008 	 */
1009 	result = dns_keytable_add(secroots, initializing, initializing, keyname,
1010 				  &ds, sfd_add, view);
1011 
1012 done:
1013 	return result;
1014 }
1015 
1016 /*
1017  * Load keys from configuration into key table. If 'keyname' is specified,
1018  * only load keys matching that name. If 'managed' is true, load the key as
1019  * an initializing key.
1020  */
1021 static isc_result_t
1022 load_view_keys(const cfg_obj_t *keys, dns_view_t *view, bool managed,
1023 	       const dns_name_t *keyname) {
1024 	const cfg_listelt_t *elt, *elt2;
1025 	const cfg_obj_t *keylist;
1026 	isc_result_t result;
1027 	dns_keytable_t *secroots = NULL;
1028 
1029 	CHECK(dns_view_getsecroots(view, &secroots));
1030 
1031 	for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt))
1032 	{
1033 		keylist = cfg_listelt_value(elt);
1034 
1035 		for (elt2 = cfg_list_first(keylist); elt2 != NULL;
1036 		     elt2 = cfg_list_next(elt2))
1037 		{
1038 			CHECK(process_key(cfg_listelt_value(elt2), secroots,
1039 					  keyname, view, managed));
1040 		}
1041 	}
1042 
1043 cleanup:
1044 	if (secroots != NULL) {
1045 		dns_keytable_detach(&secroots);
1046 	}
1047 	if (result == DST_R_NOCRYPTO) {
1048 		result = ISC_R_SUCCESS;
1049 	}
1050 	return result;
1051 }
1052 
1053 /*%
1054  * Check whether a key has been successfully loaded.
1055  */
1056 static bool
1057 keyloaded(dns_view_t *view, const dns_name_t *name) {
1058 	isc_result_t result;
1059 	dns_keytable_t *secroots = NULL;
1060 	dns_keynode_t *keynode = NULL;
1061 
1062 	result = dns_view_getsecroots(view, &secroots);
1063 	if (result != ISC_R_SUCCESS) {
1064 		return false;
1065 	}
1066 
1067 	result = dns_keytable_find(secroots, name, &keynode);
1068 
1069 	if (keynode != NULL) {
1070 		dns_keynode_detach(&keynode);
1071 	}
1072 	if (secroots != NULL) {
1073 		dns_keytable_detach(&secroots);
1074 	}
1075 
1076 	return result == ISC_R_SUCCESS;
1077 }
1078 
1079 /*%
1080  * Configure DNSSEC keys for a view.
1081  *
1082  * The per-view configuration values and the server-global defaults are read
1083  * from 'vconfig' and 'config'.
1084  */
1085 static isc_result_t
1086 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
1087 			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
1088 			  bool auto_root) {
1089 	isc_result_t result = ISC_R_SUCCESS;
1090 	const cfg_obj_t *view_keys = NULL;
1091 	const cfg_obj_t *global_keys = NULL;
1092 	const cfg_obj_t *view_managed_keys = NULL;
1093 	const cfg_obj_t *view_trust_anchors = NULL;
1094 	const cfg_obj_t *global_managed_keys = NULL;
1095 	const cfg_obj_t *global_trust_anchors = NULL;
1096 	const cfg_obj_t *maps[4];
1097 	const cfg_obj_t *voptions = NULL;
1098 	const cfg_obj_t *options = NULL;
1099 	const cfg_obj_t *obj = NULL;
1100 	const char *directory;
1101 	int i = 0;
1102 
1103 	/* We don't need trust anchors for the _bind view */
1104 	if (strcmp(view->name, "_bind") == 0 &&
1105 	    view->rdclass == dns_rdataclass_chaos)
1106 	{
1107 		return ISC_R_SUCCESS;
1108 	}
1109 
1110 	if (vconfig != NULL) {
1111 		voptions = cfg_tuple_get(vconfig, "options");
1112 		if (voptions != NULL) {
1113 			(void)cfg_map_get(voptions, "trusted-keys", &view_keys);
1114 
1115 			/* managed-keys and trust-anchors are synonyms. */
1116 			(void)cfg_map_get(voptions, "managed-keys",
1117 					  &view_managed_keys);
1118 			(void)cfg_map_get(voptions, "trust-anchors",
1119 					  &view_trust_anchors);
1120 
1121 			maps[i++] = voptions;
1122 		}
1123 	}
1124 
1125 	if (config != NULL) {
1126 		(void)cfg_map_get(config, "trusted-keys", &global_keys);
1127 
1128 		/* managed-keys and trust-anchors are synonyms. */
1129 		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
1130 		(void)cfg_map_get(config, "trust-anchors",
1131 				  &global_trust_anchors);
1132 
1133 		(void)cfg_map_get(config, "options", &options);
1134 		if (options != NULL) {
1135 			maps[i++] = options;
1136 		}
1137 	}
1138 
1139 	maps[i++] = named_g_defaults;
1140 	maps[i] = NULL;
1141 
1142 	dns_view_initsecroots(view);
1143 	dns_view_initntatable(view, named_g_loopmgr);
1144 
1145 	if (auto_root && view->rdclass == dns_rdataclass_in) {
1146 		const cfg_obj_t *builtin_keys = NULL;
1147 
1148 		/*
1149 		 * If bind.keys exists and is populated, it overrides
1150 		 * the trust-anchors clause hard-coded in named_g_config.
1151 		 */
1152 		if (bindkeys != NULL) {
1153 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1154 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1155 				      "obtaining root key for view %s "
1156 				      "from '%s'",
1157 				      view->name, named_g_server->bindkeysfile);
1158 
1159 			(void)cfg_map_get(bindkeys, "trust-anchors",
1160 					  &builtin_keys);
1161 
1162 			if (builtin_keys == NULL) {
1163 				isc_log_write(
1164 					named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1165 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
1166 					"dnssec-validation auto: "
1167 					"WARNING: root zone key "
1168 					"not found");
1169 			}
1170 		}
1171 
1172 		if (builtin_keys == NULL) {
1173 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1174 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1175 				      "using built-in root key for view %s",
1176 				      view->name);
1177 
1178 			(void)cfg_map_get(named_g_config, "trust-anchors",
1179 					  &builtin_keys);
1180 		}
1181 
1182 		if (builtin_keys != NULL) {
1183 			CHECK(load_view_keys(builtin_keys, view, true,
1184 					     dns_rootname));
1185 		}
1186 
1187 		if (!keyloaded(view, dns_rootname)) {
1188 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1189 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1190 				      "root key not loaded");
1191 			result = ISC_R_FAILURE;
1192 			goto cleanup;
1193 		}
1194 	}
1195 
1196 	if (view->rdclass == dns_rdataclass_in) {
1197 		CHECK(load_view_keys(view_keys, view, false, NULL));
1198 		CHECK(load_view_keys(view_trust_anchors, view, true, NULL));
1199 		CHECK(load_view_keys(view_managed_keys, view, true, NULL));
1200 
1201 		CHECK(load_view_keys(global_keys, view, false, NULL));
1202 		CHECK(load_view_keys(global_trust_anchors, view, true, NULL));
1203 		CHECK(load_view_keys(global_managed_keys, view, true, NULL));
1204 	}
1205 
1206 	/*
1207 	 * Add key zone for managed keys.
1208 	 */
1209 	obj = NULL;
1210 	(void)named_config_get(maps, "managed-keys-directory", &obj);
1211 	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
1212 	if (directory != NULL) {
1213 		result = isc_file_isdirectory(directory);
1214 	}
1215 	if (result != ISC_R_SUCCESS) {
1216 		isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1217 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1218 			      "invalid managed-keys-directory %s: %s",
1219 			      directory, isc_result_totext(result));
1220 		goto cleanup;
1221 	} else if (directory != NULL) {
1222 		if (!isc_file_isdirwritable(directory)) {
1223 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1224 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1225 				      "managed-keys-directory '%s' "
1226 				      "is not writable",
1227 				      directory);
1228 			result = ISC_R_NOPERM;
1229 			goto cleanup;
1230 		}
1231 	}
1232 
1233 	if (auto_root) {
1234 		CHECK(add_keydata_zone(view, directory, named_g_mctx));
1235 	}
1236 
1237 cleanup:
1238 	return result;
1239 }
1240 
1241 static isc_result_t
1242 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
1243 	const cfg_listelt_t *element;
1244 	const cfg_obj_t *obj;
1245 	const char *str;
1246 	dns_fixedname_t fixed;
1247 	dns_name_t *name;
1248 	bool value;
1249 	isc_result_t result;
1250 	isc_buffer_t b;
1251 
1252 	name = dns_fixedname_initname(&fixed);
1253 	for (element = cfg_list_first(mbs); element != NULL;
1254 	     element = cfg_list_next(element))
1255 	{
1256 		obj = cfg_listelt_value(element);
1257 		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
1258 		isc_buffer_constinit(&b, str, strlen(str));
1259 		isc_buffer_add(&b, strlen(str));
1260 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1261 		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
1262 		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
1263 	}
1264 
1265 	result = ISC_R_SUCCESS;
1266 
1267 cleanup:
1268 	return result;
1269 }
1270 
1271 /*%
1272  * Get a dispatch appropriate for the resolver of a given view.
1273  */
1274 static isc_result_t
1275 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
1276 			      dns_dispatch_t **dispatchp, bool is_firstview) {
1277 	isc_result_t result = ISC_R_FAILURE;
1278 	dns_dispatch_t *disp = NULL;
1279 	isc_sockaddr_t sa;
1280 	const cfg_obj_t *obj = NULL;
1281 
1282 	switch (af) {
1283 	case AF_INET:
1284 		result = named_config_get(maps, "query-source", &obj);
1285 		INSIST(result == ISC_R_SUCCESS);
1286 		break;
1287 	case AF_INET6:
1288 		result = named_config_get(maps, "query-source-v6", &obj);
1289 		INSIST(result == ISC_R_SUCCESS);
1290 		break;
1291 	default:
1292 		UNREACHABLE();
1293 	}
1294 
1295 	sa = *(cfg_obj_assockaddr(obj));
1296 	INSIST(isc_sockaddr_pf(&sa) == af);
1297 
1298 	/*
1299 	 * If we don't support this address family, we're done!
1300 	 */
1301 	switch (af) {
1302 	case AF_INET:
1303 		result = isc_net_probeipv4();
1304 		break;
1305 	case AF_INET6:
1306 		result = isc_net_probeipv6();
1307 		break;
1308 	default:
1309 		UNREACHABLE();
1310 	}
1311 	if (result != ISC_R_SUCCESS) {
1312 		return ISC_R_SUCCESS;
1313 	}
1314 
1315 	/*
1316 	 * Try to find a dispatcher that we can share.
1317 	 */
1318 	if (isc_sockaddr_getport(&sa) != 0) {
1319 		INSIST(obj != NULL);
1320 		if (is_firstview) {
1321 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
1322 				    "using specific query-source port "
1323 				    "suppresses port randomization and can be "
1324 				    "insecure.");
1325 		}
1326 	}
1327 
1328 	result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, &disp);
1329 	if (result != ISC_R_SUCCESS) {
1330 		isc_sockaddr_t any;
1331 		char buf[ISC_SOCKADDR_FORMATSIZE];
1332 
1333 		switch (af) {
1334 		case AF_INET:
1335 			isc_sockaddr_any(&any);
1336 			break;
1337 		case AF_INET6:
1338 			isc_sockaddr_any6(&any);
1339 			break;
1340 		}
1341 		if (isc_sockaddr_equal(&sa, &any)) {
1342 			return ISC_R_SUCCESS;
1343 		}
1344 		isc_sockaddr_format(&sa, buf, sizeof(buf));
1345 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1346 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1347 			      "could not get query source dispatcher (%s): %s",
1348 			      buf, isc_result_totext(result));
1349 		return result;
1350 	}
1351 
1352 	*dispatchp = disp;
1353 
1354 	return ISC_R_SUCCESS;
1355 }
1356 
1357 static isc_result_t
1358 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1359 	dns_rdataclass_t rdclass;
1360 	dns_rdatatype_t rdtype;
1361 	const cfg_obj_t *obj;
1362 	dns_fixedname_t fixed;
1363 	unsigned int mode = 0;
1364 	const char *str;
1365 	isc_buffer_t b;
1366 	isc_result_t result;
1367 	bool addroot;
1368 
1369 	result = named_config_getclass(cfg_tuple_get(ent, "class"),
1370 				       dns_rdataclass_any, &rdclass);
1371 	if (result != ISC_R_SUCCESS) {
1372 		return result;
1373 	}
1374 
1375 	result = named_config_gettype(cfg_tuple_get(ent, "type"),
1376 				      dns_rdatatype_any, &rdtype);
1377 	if (result != ISC_R_SUCCESS) {
1378 		return result;
1379 	}
1380 
1381 	obj = cfg_tuple_get(ent, "name");
1382 	if (cfg_obj_isstring(obj)) {
1383 		str = cfg_obj_asstring(obj);
1384 	} else {
1385 		str = "*";
1386 	}
1387 	addroot = (strcmp(str, "*") == 0);
1388 	isc_buffer_constinit(&b, str, strlen(str));
1389 	isc_buffer_add(&b, strlen(str));
1390 	dns_fixedname_init(&fixed);
1391 	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, dns_rootname,
1392 				   0, NULL);
1393 	if (result != ISC_R_SUCCESS) {
1394 		return result;
1395 	}
1396 
1397 	obj = cfg_tuple_get(ent, "ordering");
1398 	INSIST(cfg_obj_isstring(obj));
1399 	str = cfg_obj_asstring(obj);
1400 	if (!strcasecmp(str, "fixed")) {
1401 #if DNS_RDATASET_FIXED
1402 		mode = DNS_RDATASETATTR_FIXEDORDER;
1403 #else  /* if DNS_RDATASET_FIXED */
1404 		mode = DNS_RDATASETATTR_CYCLIC;
1405 #endif /* DNS_RDATASET_FIXED */
1406 	} else if (!strcasecmp(str, "random")) {
1407 		mode = DNS_RDATASETATTR_RANDOMIZE;
1408 	} else if (!strcasecmp(str, "cyclic")) {
1409 		mode = DNS_RDATASETATTR_CYCLIC;
1410 	} else if (!strcasecmp(str, "none")) {
1411 		mode = DNS_RDATASETATTR_NONE;
1412 	} else {
1413 		UNREACHABLE();
1414 	}
1415 
1416 	/*
1417 	 * "*" should match everything including the root (BIND 8 compat).
1418 	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1419 	 * explicit entry for "." when the name is "*".
1420 	 */
1421 	if (addroot) {
1422 		result = dns_order_add(order, dns_rootname, rdtype, rdclass,
1423 				       mode);
1424 		if (result != ISC_R_SUCCESS) {
1425 			return result;
1426 		}
1427 	}
1428 
1429 	return dns_order_add(order, dns_fixedname_name(&fixed), rdtype, rdclass,
1430 			     mode);
1431 }
1432 
1433 static isc_result_t
1434 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1435 	isc_netaddr_t na;
1436 	dns_peer_t *peer;
1437 	const cfg_obj_t *obj;
1438 	const char *str;
1439 	isc_result_t result;
1440 	unsigned int prefixlen;
1441 
1442 	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1443 
1444 	peer = NULL;
1445 	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1446 	if (result != ISC_R_SUCCESS) {
1447 		return result;
1448 	}
1449 
1450 	obj = NULL;
1451 	(void)cfg_map_get(cpeer, "bogus", &obj);
1452 	if (obj != NULL) {
1453 		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1454 	}
1455 
1456 	obj = NULL;
1457 	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1458 	if (obj != NULL) {
1459 		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1460 	}
1461 
1462 	obj = NULL;
1463 	(void)cfg_map_get(cpeer, "request-expire", &obj);
1464 	if (obj != NULL) {
1465 		CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
1466 	}
1467 
1468 	obj = NULL;
1469 	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
1470 	if (obj != NULL) {
1471 		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1472 	}
1473 
1474 	obj = NULL;
1475 	(void)cfg_map_get(cpeer, "request-nsid", &obj);
1476 	if (obj != NULL) {
1477 		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1478 	}
1479 
1480 	obj = NULL;
1481 	(void)cfg_map_get(cpeer, "send-cookie", &obj);
1482 	if (obj != NULL) {
1483 		CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj)));
1484 	}
1485 
1486 	obj = NULL;
1487 	(void)cfg_map_get(cpeer, "require-cookie", &obj);
1488 	if (obj != NULL) {
1489 		CHECK(dns_peer_setrequirecookie(peer, cfg_obj_asboolean(obj)));
1490 	}
1491 
1492 	obj = NULL;
1493 	(void)cfg_map_get(cpeer, "edns", &obj);
1494 	if (obj != NULL) {
1495 		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1496 	}
1497 
1498 	obj = NULL;
1499 	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1500 	if (obj != NULL) {
1501 		uint32_t udpsize = cfg_obj_asuint32(obj);
1502 		if (udpsize < 512U) {
1503 			udpsize = 512U;
1504 		}
1505 		if (udpsize > 4096U) {
1506 			udpsize = 4096U;
1507 		}
1508 		CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize));
1509 	}
1510 
1511 	obj = NULL;
1512 	(void)cfg_map_get(cpeer, "edns-version", &obj);
1513 	if (obj != NULL) {
1514 		uint32_t ednsversion = cfg_obj_asuint32(obj);
1515 		if (ednsversion > 255U) {
1516 			ednsversion = 255U;
1517 		}
1518 		CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion));
1519 	}
1520 
1521 	obj = NULL;
1522 	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
1523 	if (obj != NULL) {
1524 		uint32_t udpsize = cfg_obj_asuint32(obj);
1525 		if (udpsize < 512U) {
1526 			udpsize = 512U;
1527 		}
1528 		if (udpsize > 4096U) {
1529 			udpsize = 4096U;
1530 		}
1531 		CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize));
1532 	}
1533 
1534 	obj = NULL;
1535 	(void)cfg_map_get(cpeer, "padding", &obj);
1536 	if (obj != NULL) {
1537 		uint32_t padding = cfg_obj_asuint32(obj);
1538 		if (padding > 512U) {
1539 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
1540 				    "server padding value cannot "
1541 				    "exceed 512: lowering");
1542 			padding = 512U;
1543 		}
1544 		CHECK(dns_peer_setpadding(peer, (uint16_t)padding));
1545 	}
1546 
1547 	obj = NULL;
1548 	(void)cfg_map_get(cpeer, "tcp-only", &obj);
1549 	if (obj != NULL) {
1550 		CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
1551 	}
1552 
1553 	obj = NULL;
1554 	(void)cfg_map_get(cpeer, "tcp-keepalive", &obj);
1555 	if (obj != NULL) {
1556 		CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj)));
1557 	}
1558 
1559 	obj = NULL;
1560 	(void)cfg_map_get(cpeer, "transfers", &obj);
1561 	if (obj != NULL) {
1562 		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1563 	}
1564 
1565 	obj = NULL;
1566 	(void)cfg_map_get(cpeer, "transfer-format", &obj);
1567 	if (obj != NULL) {
1568 		str = cfg_obj_asstring(obj);
1569 		if (strcasecmp(str, "many-answers") == 0) {
1570 			CHECK(dns_peer_settransferformat(peer,
1571 							 dns_many_answers));
1572 		} else if (strcasecmp(str, "one-answer") == 0) {
1573 			CHECK(dns_peer_settransferformat(peer, dns_one_answer));
1574 		} else {
1575 			UNREACHABLE();
1576 		}
1577 	}
1578 
1579 	obj = NULL;
1580 	(void)cfg_map_get(cpeer, "keys", &obj);
1581 	if (obj != NULL) {
1582 		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1583 		if (result != ISC_R_SUCCESS) {
1584 			goto cleanup;
1585 		}
1586 	}
1587 
1588 	obj = NULL;
1589 	if (na.family == AF_INET) {
1590 		(void)cfg_map_get(cpeer, "transfer-source", &obj);
1591 	} else {
1592 		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1593 	}
1594 	if (obj != NULL) {
1595 		result = dns_peer_settransfersource(peer,
1596 						    cfg_obj_assockaddr(obj));
1597 		if (result != ISC_R_SUCCESS) {
1598 			goto cleanup;
1599 		}
1600 	}
1601 
1602 	obj = NULL;
1603 	if (na.family == AF_INET) {
1604 		(void)cfg_map_get(cpeer, "notify-source", &obj);
1605 	} else {
1606 		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1607 	}
1608 	if (obj != NULL) {
1609 		result = dns_peer_setnotifysource(peer,
1610 						  cfg_obj_assockaddr(obj));
1611 		if (result != ISC_R_SUCCESS) {
1612 			goto cleanup;
1613 		}
1614 	}
1615 
1616 	obj = NULL;
1617 	if (na.family == AF_INET) {
1618 		(void)cfg_map_get(cpeer, "query-source", &obj);
1619 	} else {
1620 		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
1621 	}
1622 	if (obj != NULL) {
1623 		result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj));
1624 		if (result != ISC_R_SUCCESS) {
1625 			goto cleanup;
1626 		}
1627 	}
1628 
1629 	*peerp = peer;
1630 	return ISC_R_SUCCESS;
1631 
1632 cleanup:
1633 	dns_peer_detach(&peer);
1634 	return result;
1635 }
1636 
1637 static isc_result_t
1638 configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
1639 		const dns_dyndbctx_t *dctx) {
1640 	isc_result_t result = ISC_R_SUCCESS;
1641 	const cfg_obj_t *obj;
1642 	const char *name, *library;
1643 
1644 	/* Get the name of the dyndb instance and the library path . */
1645 	name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name"));
1646 	library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library"));
1647 
1648 	obj = cfg_tuple_get(dyndb, "parameters");
1649 	if (obj != NULL) {
1650 		result = dns_dyndb_load(library, name, cfg_obj_asstring(obj),
1651 					cfg_obj_file(obj), cfg_obj_line(obj),
1652 					mctx, dctx);
1653 	}
1654 
1655 	if (result != ISC_R_SUCCESS) {
1656 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1657 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1658 			      "dynamic database '%s' configuration failed: %s",
1659 			      name, isc_result_totext(result));
1660 	}
1661 	return result;
1662 }
1663 
1664 static isc_result_t
1665 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1666 	isc_result_t result;
1667 	const cfg_obj_t *algorithms;
1668 	const cfg_listelt_t *element;
1669 	const char *str;
1670 	dns_fixedname_t fixed;
1671 	dns_name_t *name;
1672 	isc_buffer_t b;
1673 
1674 	name = dns_fixedname_initname(&fixed);
1675 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1676 	isc_buffer_constinit(&b, str, strlen(str));
1677 	isc_buffer_add(&b, strlen(str));
1678 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1679 
1680 	algorithms = cfg_tuple_get(disabled, "algorithms");
1681 	for (element = cfg_list_first(algorithms); element != NULL;
1682 	     element = cfg_list_next(element))
1683 	{
1684 		isc_textregion_t r;
1685 		dns_secalg_t alg;
1686 
1687 		r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element)));
1688 		r.length = strlen(r.base);
1689 
1690 		result = dns_secalg_fromtext(&alg, &r);
1691 		if (result != ISC_R_SUCCESS) {
1692 			uint8_t ui;
1693 			result = isc_parse_uint8(&ui, r.base, 10);
1694 			alg = ui;
1695 		}
1696 		if (result != ISC_R_SUCCESS) {
1697 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1698 				    ISC_LOG_ERROR, "invalid algorithm");
1699 			CHECK(result);
1700 		}
1701 		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1702 	}
1703 cleanup:
1704 	return result;
1705 }
1706 
1707 static isc_result_t
1708 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1709 	isc_result_t result;
1710 	const cfg_obj_t *digests;
1711 	const cfg_listelt_t *element;
1712 	const char *str;
1713 	dns_fixedname_t fixed;
1714 	dns_name_t *name;
1715 	isc_buffer_t b;
1716 
1717 	name = dns_fixedname_initname(&fixed);
1718 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1719 	isc_buffer_constinit(&b, str, strlen(str));
1720 	isc_buffer_add(&b, strlen(str));
1721 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1722 
1723 	digests = cfg_tuple_get(disabled, "digests");
1724 	for (element = cfg_list_first(digests); element != NULL;
1725 	     element = cfg_list_next(element))
1726 	{
1727 		isc_textregion_t r;
1728 		dns_dsdigest_t digest;
1729 
1730 		r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element)));
1731 		r.length = strlen(r.base);
1732 
1733 		/* disable_ds_digests handles numeric values. */
1734 		result = dns_dsdigest_fromtext(&digest, &r);
1735 		if (result != ISC_R_SUCCESS) {
1736 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1737 				    ISC_LOG_ERROR, "invalid algorithm");
1738 			CHECK(result);
1739 		}
1740 		CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
1741 	}
1742 cleanup:
1743 	return result;
1744 }
1745 
1746 static bool
1747 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1748 	const cfg_listelt_t *element;
1749 	dns_fixedname_t fixed;
1750 	dns_name_t *name;
1751 	isc_result_t result;
1752 	const cfg_obj_t *value;
1753 	const char *str;
1754 	isc_buffer_t b;
1755 
1756 	name = dns_fixedname_initname(&fixed);
1757 
1758 	for (element = cfg_list_first(disablelist); element != NULL;
1759 	     element = cfg_list_next(element))
1760 	{
1761 		value = cfg_listelt_value(element);
1762 		str = cfg_obj_asstring(value);
1763 		isc_buffer_constinit(&b, str, strlen(str));
1764 		isc_buffer_add(&b, strlen(str));
1765 		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
1766 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1767 		if (dns_name_equal(name, zonename)) {
1768 			return true;
1769 		}
1770 	}
1771 	return false;
1772 }
1773 
1774 static isc_result_t
1775 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
1776 	     isc_mem_t *mctx) {
1777 	char **argv = NULL;
1778 	unsigned int i;
1779 	isc_result_t result = ISC_R_SUCCESS;
1780 
1781 	CHECK(dns_zone_getdbtype(zone, &argv, mctx));
1782 
1783 	/*
1784 	 * Check that all the arguments match.
1785 	 */
1786 	for (i = 0; i < dbtypec; i++) {
1787 		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
1788 			CHECK(ISC_R_FAILURE);
1789 		}
1790 	}
1791 
1792 	/*
1793 	 * Check that there are not extra arguments.
1794 	 */
1795 	if (i == dbtypec && argv[i] != NULL) {
1796 		result = ISC_R_FAILURE;
1797 	}
1798 
1799 cleanup:
1800 	isc_mem_free(mctx, argv);
1801 	return result;
1802 }
1803 
1804 static void
1805 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
1806 	isc_stats_t *zoneqrystats;
1807 
1808 	dns_zone_setstatlevel(zone, level);
1809 
1810 	zoneqrystats = NULL;
1811 	if (level == dns_zonestat_full) {
1812 		isc_stats_create(mctx, &zoneqrystats, ns_statscounter_max);
1813 	}
1814 	dns_zone_setrequeststats(zone, zoneqrystats);
1815 	if (zoneqrystats != NULL) {
1816 		isc_stats_detach(&zoneqrystats);
1817 	}
1818 }
1819 
1820 static named_cache_t *
1821 cachelist_find(named_cachelist_t *cachelist, const char *cachename,
1822 	       dns_rdataclass_t rdclass) {
1823 	named_cache_t *nsc;
1824 
1825 	for (nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
1826 	     nsc = ISC_LIST_NEXT(nsc, link))
1827 	{
1828 		if (nsc->rdclass == rdclass &&
1829 		    strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1830 		{
1831 			return nsc;
1832 		}
1833 	}
1834 
1835 	return NULL;
1836 }
1837 
1838 static bool
1839 cache_reusable(dns_view_t *originview, dns_view_t *view,
1840 	       bool new_zero_no_soattl) {
1841 	if (originview->rdclass != view->rdclass ||
1842 	    originview->checknames != view->checknames ||
1843 	    dns_resolver_getzeronosoattl(originview->resolver) !=
1844 		    new_zero_no_soattl ||
1845 	    originview->acceptexpired != view->acceptexpired ||
1846 	    originview->enablevalidation != view->enablevalidation ||
1847 	    originview->maxcachettl != view->maxcachettl ||
1848 	    originview->maxncachettl != view->maxncachettl)
1849 	{
1850 		return false;
1851 	}
1852 
1853 	return true;
1854 }
1855 
1856 static bool
1857 cache_sharable(dns_view_t *originview, dns_view_t *view,
1858 	       bool new_zero_no_soattl, uint64_t new_max_cache_size,
1859 	       uint32_t new_stale_ttl, uint32_t new_stale_refresh_time) {
1860 	/*
1861 	 * If the cache cannot even reused for the same view, it cannot be
1862 	 * shared with other views.
1863 	 */
1864 	if (!cache_reusable(originview, view, new_zero_no_soattl)) {
1865 		return false;
1866 	}
1867 
1868 	/*
1869 	 * Check other cache related parameters that must be consistent among
1870 	 * the sharing views.
1871 	 */
1872 	if (dns_cache_getservestalettl(originview->cache) != new_stale_ttl ||
1873 	    dns_cache_getservestalerefresh(originview->cache) !=
1874 		    new_stale_refresh_time ||
1875 	    dns_cache_getcachesize(originview->cache) != new_max_cache_size)
1876 	{
1877 		return false;
1878 	}
1879 
1880 	return true;
1881 }
1882 
1883 /*
1884  * Callback from DLZ configure when the driver sets up a writeable zone
1885  */
1886 static isc_result_t
1887 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
1888 	dns_name_t *origin = dns_zone_getorigin(zone);
1889 	dns_rdataclass_t zclass = view->rdclass;
1890 	isc_result_t result;
1891 
1892 	result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
1893 	if (result != ISC_R_SUCCESS) {
1894 		return result;
1895 	}
1896 	dns_zone_setstats(zone, named_g_server->zonestats);
1897 
1898 	return named_zone_configure_writeable_dlz(dlzdb, zone, zclass, origin);
1899 }
1900 
1901 static isc_result_t
1902 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1903 	      unsigned int prefixlen, const char *server, const char *contact) {
1904 	char reverse[48 + sizeof("ip6.arpa.")] = { 0 };
1905 	char buf[sizeof("x.x.")];
1906 	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1907 	const char *sep = ": view ";
1908 	const char *viewname = view->name;
1909 	const unsigned char *s6;
1910 	dns_fixedname_t fixed;
1911 	dns_name_t *name;
1912 	dns_zone_t *zone = NULL;
1913 	int dns64_dbtypec = 4;
1914 	isc_buffer_t b;
1915 	isc_result_t result;
1916 
1917 	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1918 		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1919 
1920 	if (!strcmp(viewname, "_default")) {
1921 		sep = "";
1922 		viewname = "";
1923 	}
1924 
1925 	/*
1926 	 * Construct the reverse name of the zone.
1927 	 */
1928 	s6 = na->type.in6.s6_addr;
1929 	while (prefixlen > 0) {
1930 		prefixlen -= 8;
1931 		snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen / 8] & 0xf,
1932 			 (s6[prefixlen / 8] >> 4) & 0xf);
1933 		strlcat(reverse, buf, sizeof(reverse));
1934 	}
1935 	strlcat(reverse, "ip6.arpa.", sizeof(reverse));
1936 
1937 	/*
1938 	 * Create the actual zone.
1939 	 */
1940 	if (server != NULL) {
1941 		dns64_dbtype[2] = server;
1942 	}
1943 	if (contact != NULL) {
1944 		dns64_dbtype[3] = contact;
1945 	}
1946 	name = dns_fixedname_initname(&fixed);
1947 	isc_buffer_constinit(&b, reverse, strlen(reverse));
1948 	isc_buffer_add(&b, strlen(reverse));
1949 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1950 	dns_zone_create(&zone, mctx, 0);
1951 	CHECK(dns_zone_setorigin(zone, name));
1952 	dns_zone_setview(zone, view);
1953 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
1954 	dns_zone_setclass(zone, view->rdclass);
1955 	dns_zone_settype(zone, dns_zone_primary);
1956 	dns_zone_setstats(zone, named_g_server->zonestats);
1957 	dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype);
1958 	if (view->queryacl != NULL) {
1959 		dns_zone_setqueryacl(zone, view->queryacl);
1960 	}
1961 	if (view->queryonacl != NULL) {
1962 		dns_zone_setqueryonacl(zone, view->queryonacl);
1963 	}
1964 	dns_zone_setdialup(zone, dns_dialuptype_no);
1965 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
1966 	dns_zone_setnotifytype(zone, dns_notifytype_no);
1967 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
1968 	setquerystats(zone, mctx, dns_zonestat_none);
1969 	CHECK(dns_view_addzone(view, zone));
1970 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1971 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1972 		      "dns64 reverse zone%s%s: %s", sep, viewname, reverse);
1973 
1974 cleanup:
1975 	if (zone != NULL) {
1976 		dns_zone_detach(&zone);
1977 	}
1978 	return result;
1979 }
1980 
1981 #ifdef USE_DNSRPS
1982 typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
1983 struct conf_dnsrps_ctx {
1984 	isc_result_t result;
1985 	char *cstr;
1986 	size_t cstr_size;
1987 	isc_mem_t *mctx;
1988 };
1989 
1990 /*
1991  * Add to the DNSRPS configuration string.
1992  */
1993 static bool
1994 conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
1995 	size_t new_len, cur_len, new_cstr_size;
1996 	char *new_cstr;
1997 	va_list args;
1998 
1999 	if (ctx->cstr == NULL) {
2000 		ctx->cstr = isc_mem_get(ctx->mctx, 256);
2001 		ctx->cstr[0] = '\0';
2002 		ctx->cstr_size = 256;
2003 	}
2004 
2005 	cur_len = strlen(ctx->cstr);
2006 	va_start(args, p);
2007 	new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p,
2008 			    args) +
2009 		  1;
2010 	va_end(args);
2011 
2012 	if (cur_len + new_len <= ctx->cstr_size) {
2013 		return true;
2014 	}
2015 
2016 	new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256;
2017 	new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
2018 
2019 	memmove(new_cstr, ctx->cstr, cur_len);
2020 	isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
2021 	ctx->cstr_size = new_cstr_size;
2022 	ctx->cstr = new_cstr;
2023 
2024 	/* cannot use args twice after a single va_start()on some systems */
2025 	va_start(args, p);
2026 	vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
2027 	va_end(args);
2028 	return true;
2029 }
2030 
2031 /*
2032  * Get a DNSRPS configuration value using the global and view options
2033  * for the default.  Return false upon failure.
2034  */
2035 static bool
2036 conf_dnsrps_get(const cfg_obj_t **sub_obj, const cfg_obj_t **maps,
2037 		const cfg_obj_t *obj, const char *name,
2038 		conf_dnsrps_ctx_t *ctx) {
2039 	if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
2040 		*sub_obj = NULL;
2041 		return false;
2042 	}
2043 
2044 	*sub_obj = cfg_tuple_get(obj, name);
2045 	if (cfg_obj_isvoid(*sub_obj)) {
2046 		*sub_obj = NULL;
2047 		if (maps != NULL &&
2048 		    ISC_R_SUCCESS != named_config_get(maps, name, sub_obj))
2049 		{
2050 			*sub_obj = NULL;
2051 		}
2052 	}
2053 	return true;
2054 }
2055 
2056 /*
2057  * Handle a DNSRPS boolean configuration value with the global and view
2058  * options providing the default.
2059  */
2060 static void
2061 conf_dnsrps_yes_no(const cfg_obj_t *obj, const char *name,
2062 		   conf_dnsrps_ctx_t *ctx) {
2063 	const cfg_obj_t *sub_obj;
2064 
2065 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2066 		return;
2067 	}
2068 	if (sub_obj == NULL) {
2069 		return;
2070 	}
2071 	if (ctx == NULL) {
2072 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2073 			    "\"%s\" without \"dnsrps-enable yes\"", name);
2074 		return;
2075 	}
2076 
2077 	conf_dnsrps_sadd(ctx, " %s %s", name,
2078 			 cfg_obj_asboolean(sub_obj) ? "yes" : "no");
2079 }
2080 
2081 static void
2082 conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
2083 		conf_dnsrps_ctx_t *ctx) {
2084 	const cfg_obj_t *sub_obj;
2085 
2086 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2087 		return;
2088 	}
2089 	if (sub_obj == NULL) {
2090 		return;
2091 	}
2092 	if (ctx == NULL) {
2093 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2094 			    "\"%s\" without \"dnsrps-enable yes\"", name);
2095 		return;
2096 	}
2097 
2098 	if (cfg_obj_isduration(sub_obj)) {
2099 		conf_dnsrps_sadd(ctx, " %s %d", name,
2100 				 cfg_obj_asduration(sub_obj));
2101 	} else {
2102 		conf_dnsrps_sadd(ctx, " %s %d", name,
2103 				 cfg_obj_asuint32(sub_obj));
2104 	}
2105 }
2106 
2107 /*
2108  * Convert the parsed RPZ configuration statement to a string for
2109  * dns_rpz_new_zones().
2110  */
2111 static isc_result_t
2112 conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps, bool nsip_enabled,
2113 	    bool nsdname_enabled, dns_rpz_zbits_t *nsip_on,
2114 	    dns_rpz_zbits_t *nsdname_on, char **rps_cstr, size_t *rps_cstr_size,
2115 	    const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element) {
2116 	conf_dnsrps_ctx_t ctx;
2117 	const cfg_obj_t *zone_obj, *obj;
2118 	dns_rpz_num_t rpz_num;
2119 	bool on;
2120 	const char *s;
2121 
2122 	memset(&ctx, 0, sizeof(ctx));
2123 	ctx.result = ISC_R_SUCCESS;
2124 	ctx.mctx = view->mctx;
2125 
2126 	for (rpz_num = 0; zone_element != NULL && ctx.result == ISC_R_SUCCESS;
2127 	     ++rpz_num)
2128 	{
2129 		zone_obj = cfg_listelt_value(zone_element);
2130 
2131 		s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
2132 		conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
2133 
2134 		obj = cfg_tuple_get(zone_obj, "policy");
2135 		if (!cfg_obj_isvoid(obj)) {
2136 			s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2137 			conf_dnsrps_sadd(&ctx, " policy %s", s);
2138 			if (strcasecmp(s, "cname") == 0) {
2139 				s = cfg_obj_asstring(
2140 					cfg_tuple_get(obj, "cname"));
2141 				conf_dnsrps_sadd(&ctx, " %s", s);
2142 			}
2143 		}
2144 
2145 		conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
2146 		conf_dnsrps_yes_no(zone_obj, "log", &ctx);
2147 		conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
2148 		obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2149 		if (!cfg_obj_isvoid(obj)) {
2150 			if (cfg_obj_asboolean(obj)) {
2151 				*nsip_on |= DNS_RPZ_ZBIT(rpz_num);
2152 			} else {
2153 				*nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
2154 			}
2155 		}
2156 		on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2157 		if (nsip_enabled != on) {
2158 			conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes "
2159 						  : " nsip-enable no ");
2160 		}
2161 		obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2162 		if (!cfg_obj_isvoid(obj)) {
2163 			if (cfg_obj_asboolean(obj)) {
2164 				*nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
2165 			} else {
2166 				*nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
2167 			}
2168 		}
2169 		on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2170 		if (nsdname_enabled != on) {
2171 			conf_dnsrps_sadd(&ctx, on ? " nsdname-enable yes "
2172 						  : " nsdname-enable no ");
2173 		}
2174 		conf_dnsrps_sadd(&ctx, ";\n");
2175 		zone_element = cfg_list_next(zone_element);
2176 	}
2177 
2178 	conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
2179 	conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
2180 	conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
2181 	conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
2182 	conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
2183 	if (!nsip_enabled) {
2184 		conf_dnsrps_sadd(&ctx, " nsip-enable no ");
2185 	}
2186 	if (!nsdname_enabled) {
2187 		conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
2188 	}
2189 
2190 	/*
2191 	 * Get the general dnsrpzd parameters from the response-policy
2192 	 * statement in the view and the general options.
2193 	 */
2194 	if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
2195 	    obj != NULL)
2196 	{
2197 		conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
2198 	}
2199 
2200 	if (ctx.result == ISC_R_SUCCESS) {
2201 		*rps_cstr = ctx.cstr;
2202 		*rps_cstr_size = ctx.cstr_size;
2203 	} else {
2204 		if (ctx.cstr != NULL) {
2205 			isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
2206 		}
2207 		*rps_cstr = NULL;
2208 		*rps_cstr_size = 0;
2209 	}
2210 	return ctx.result;
2211 }
2212 #endif /* ifdef USE_DNSRPS */
2213 
2214 static isc_result_t
2215 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2216 		   const char *str, const char *msg) {
2217 	isc_result_t result;
2218 
2219 	result = dns_name_fromstring(name, str, dns_rootname, DNS_NAME_DOWNCASE,
2220 				     view->mctx);
2221 	if (result != ISC_R_SUCCESS) {
2222 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2223 			    "invalid %s '%s'", msg, str);
2224 	}
2225 	return result;
2226 }
2227 
2228 static isc_result_t
2229 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2230 		    const char *str, const dns_name_t *origin) {
2231 	isc_result_t result;
2232 
2233 	result = dns_name_fromstring(name, str, origin, DNS_NAME_DOWNCASE,
2234 				     view->mctx);
2235 	if (result != ISC_R_SUCCESS) {
2236 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2237 			    "invalid zone '%s'", str);
2238 	}
2239 	return result;
2240 }
2241 
2242 static isc_result_t
2243 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
2244 		   bool recursive_only_default, bool add_soa_default,
2245 		   dns_ttl_t ttl_default, uint32_t minupdateinterval_default,
2246 		   const dns_rpz_zone_t *old, bool *old_rpz_okp) {
2247 	const cfg_obj_t *rpz_obj, *obj;
2248 	const char *str;
2249 	dns_rpz_zone_t *zone = NULL;
2250 	isc_result_t result;
2251 	dns_rpz_num_t rpz_num;
2252 
2253 	REQUIRE(old != NULL || !*old_rpz_okp);
2254 
2255 	rpz_obj = cfg_listelt_value(element);
2256 
2257 	if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
2258 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2259 			    "limit of %d response policy zones exceeded",
2260 			    DNS_RPZ_MAX_ZONES);
2261 		return ISC_R_FAILURE;
2262 	}
2263 
2264 	result = dns_rpz_new_zone(view->rpzs, &zone);
2265 	if (result != ISC_R_SUCCESS) {
2266 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2267 			    "Error creating new RPZ zone : %s",
2268 			    isc_result_totext(result));
2269 		return result;
2270 	}
2271 
2272 	obj = cfg_tuple_get(rpz_obj, "recursive-only");
2273 	if (cfg_obj_isvoid(obj) ? recursive_only_default
2274 				: cfg_obj_asboolean(obj))
2275 	{
2276 		view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num);
2277 	} else {
2278 		view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num);
2279 	}
2280 
2281 	obj = cfg_tuple_get(rpz_obj, "log");
2282 	if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) {
2283 		view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num);
2284 	} else {
2285 		view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num);
2286 	}
2287 
2288 	obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2289 	if (cfg_obj_isduration(obj)) {
2290 		zone->max_policy_ttl = cfg_obj_asduration(obj);
2291 	} else {
2292 		zone->max_policy_ttl = ttl_default;
2293 	}
2294 	if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl) {
2295 		*old_rpz_okp = false;
2296 	}
2297 
2298 	obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2299 	if (cfg_obj_isduration(obj)) {
2300 		zone->min_update_interval = cfg_obj_asduration(obj);
2301 	} else {
2302 		zone->min_update_interval = minupdateinterval_default;
2303 	}
2304 	if (*old_rpz_okp &&
2305 	    zone->min_update_interval != old->min_update_interval)
2306 	{
2307 		*old_rpz_okp = false;
2308 	}
2309 
2310 	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
2311 	result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone");
2312 	if (result != ISC_R_SUCCESS) {
2313 		return result;
2314 	}
2315 	if (dns_name_equal(&zone->origin, dns_rootname)) {
2316 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2317 			    "invalid zone name '%s'", str);
2318 		return DNS_R_EMPTYLABEL;
2319 	}
2320 	if (!view->rpzs->p.dnsrps_enabled) {
2321 		for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1;
2322 		     ++rpz_num)
2323 		{
2324 			if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
2325 					   &zone->origin))
2326 			{
2327 				cfg_obj_log(rpz_obj, named_g_lctx,
2328 					    DNS_RPZ_ERROR_LEVEL,
2329 					    "duplicate '%s'", str);
2330 				result = DNS_R_DUPLICATE;
2331 				return result;
2332 			}
2333 		}
2334 	}
2335 	if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) {
2336 		*old_rpz_okp = false;
2337 	}
2338 
2339 	result = configure_rpz_name2(view, rpz_obj, &zone->client_ip,
2340 				     DNS_RPZ_CLIENT_IP_ZONE, &zone->origin);
2341 	if (result != ISC_R_SUCCESS) {
2342 		return result;
2343 	}
2344 
2345 	result = configure_rpz_name2(view, rpz_obj, &zone->ip, DNS_RPZ_IP_ZONE,
2346 				     &zone->origin);
2347 	if (result != ISC_R_SUCCESS) {
2348 		return result;
2349 	}
2350 
2351 	result = configure_rpz_name2(view, rpz_obj, &zone->nsdname,
2352 				     DNS_RPZ_NSDNAME_ZONE, &zone->origin);
2353 	if (result != ISC_R_SUCCESS) {
2354 		return result;
2355 	}
2356 
2357 	result = configure_rpz_name2(view, rpz_obj, &zone->nsip,
2358 				     DNS_RPZ_NSIP_ZONE, &zone->origin);
2359 	if (result != ISC_R_SUCCESS) {
2360 		return result;
2361 	}
2362 
2363 	result = configure_rpz_name(view, rpz_obj, &zone->passthru,
2364 				    DNS_RPZ_PASSTHRU_NAME, "name");
2365 	if (result != ISC_R_SUCCESS) {
2366 		return result;
2367 	}
2368 
2369 	result = configure_rpz_name(view, rpz_obj, &zone->drop,
2370 				    DNS_RPZ_DROP_NAME, "name");
2371 	if (result != ISC_R_SUCCESS) {
2372 		return result;
2373 	}
2374 
2375 	result = configure_rpz_name(view, rpz_obj, &zone->tcp_only,
2376 				    DNS_RPZ_TCP_ONLY_NAME, "name");
2377 	if (result != ISC_R_SUCCESS) {
2378 		return result;
2379 	}
2380 
2381 	obj = cfg_tuple_get(rpz_obj, "policy");
2382 	if (cfg_obj_isvoid(obj)) {
2383 		zone->policy = DNS_RPZ_POLICY_GIVEN;
2384 	} else {
2385 		str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2386 		zone->policy = dns_rpz_str2policy(str);
2387 		INSIST(zone->policy != DNS_RPZ_POLICY_ERROR);
2388 		if (zone->policy == DNS_RPZ_POLICY_CNAME) {
2389 			str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
2390 			result = configure_rpz_name(view, rpz_obj, &zone->cname,
2391 						    str, "cname");
2392 			if (result != ISC_R_SUCCESS) {
2393 				return result;
2394 			}
2395 		}
2396 	}
2397 	if (*old_rpz_okp && (zone->policy != old->policy ||
2398 			     !dns_name_equal(&old->cname, &zone->cname)))
2399 	{
2400 		*old_rpz_okp = false;
2401 	}
2402 
2403 	obj = cfg_tuple_get(rpz_obj, "ede");
2404 	if (!cfg_obj_isstring(obj)) {
2405 		zone->ede = 0;
2406 	} else {
2407 		str = cfg_obj_asstring(obj);
2408 		zone->ede = dns_rpz_str2ede(str);
2409 		INSIST(zone->ede != UINT16_MAX);
2410 	}
2411 	if (*old_rpz_okp && zone->ede != old->ede) {
2412 		*old_rpz_okp = false;
2413 	}
2414 
2415 	obj = cfg_tuple_get(rpz_obj, "add-soa");
2416 	if (cfg_obj_isvoid(obj)) {
2417 		zone->addsoa = add_soa_default;
2418 	} else {
2419 		zone->addsoa = cfg_obj_asboolean(obj);
2420 	}
2421 	if (*old_rpz_okp && zone->addsoa != old->addsoa) {
2422 		*old_rpz_okp = false;
2423 	}
2424 
2425 	return ISC_R_SUCCESS;
2426 }
2427 
2428 static isc_result_t
2429 configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
2430 	      const cfg_obj_t *rpz_obj, bool *old_rpz_okp) {
2431 	bool dnsrps_enabled;
2432 	const cfg_listelt_t *zone_element;
2433 	char *rps_cstr;
2434 	size_t rps_cstr_size;
2435 	const cfg_obj_t *sub_obj;
2436 	bool recursive_only_default, add_soa_default;
2437 	bool nsip_enabled, nsdname_enabled;
2438 	dns_rpz_zbits_t nsip_on, nsdname_on;
2439 	dns_ttl_t ttl_default;
2440 	uint32_t minupdateinterval_default;
2441 	dns_rpz_zones_t *zones;
2442 	const dns_rpz_zones_t *old;
2443 	bool pview_must_detach = false;
2444 	const dns_rpz_zone_t *old_zone;
2445 	isc_result_t result;
2446 	int i;
2447 
2448 	*old_rpz_okp = false;
2449 
2450 	zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
2451 	if (zone_element == NULL) {
2452 		return ISC_R_SUCCESS;
2453 	}
2454 
2455 	nsip_enabled = true;
2456 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2457 	if (!cfg_obj_isvoid(sub_obj)) {
2458 		nsip_enabled = cfg_obj_asboolean(sub_obj);
2459 	}
2460 	nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2461 
2462 	nsdname_enabled = true;
2463 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2464 	if (!cfg_obj_isvoid(sub_obj)) {
2465 		nsdname_enabled = cfg_obj_asboolean(sub_obj);
2466 	}
2467 	nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2468 
2469 	/*
2470 	 * "dnsrps-enable yes|no" can be either a global or response-policy
2471 	 * clause.
2472 	 */
2473 	dnsrps_enabled = false;
2474 	rps_cstr = NULL;
2475 	rps_cstr_size = 0;
2476 	sub_obj = NULL;
2477 	(void)named_config_get(maps, "dnsrps-enable", &sub_obj);
2478 	if (sub_obj != NULL) {
2479 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2480 	}
2481 	sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
2482 	if (!cfg_obj_isvoid(sub_obj)) {
2483 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2484 	}
2485 #ifndef USE_DNSRPS
2486 	if (dnsrps_enabled) {
2487 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2488 			    "\"dnsrps-enable yes\" but"
2489 			    " without `./configure --enable-dnsrps`");
2490 		return ISC_R_FAILURE;
2491 	}
2492 #else  /* ifndef USE_DNSRPS */
2493 	if (dnsrps_enabled) {
2494 		if (librpz == NULL) {
2495 			cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2496 				    "\"dnsrps-enable yes\" but %s",
2497 				    librpz_lib_open_emsg.c);
2498 			return ISC_R_FAILURE;
2499 		}
2500 
2501 		/*
2502 		 * Generate the DNS Response Policy Service
2503 		 * configuration string.
2504 		 */
2505 		result = conf_dnsrps(view, maps, nsip_enabled, nsdname_enabled,
2506 				     &nsip_on, &nsdname_on, &rps_cstr,
2507 				     &rps_cstr_size, rpz_obj, zone_element);
2508 		if (result != ISC_R_SUCCESS) {
2509 			return result;
2510 		}
2511 	}
2512 #endif /* ifndef USE_DNSRPS */
2513 
2514 	result = dns_rpz_new_zones(view, named_g_loopmgr, rps_cstr,
2515 				   rps_cstr_size, &view->rpzs);
2516 	if (result != ISC_R_SUCCESS) {
2517 		return result;
2518 	}
2519 
2520 	zones = view->rpzs;
2521 
2522 	zones->p.nsip_on = nsip_on;
2523 	zones->p.nsdname_on = nsdname_on;
2524 
2525 	sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
2526 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2527 		recursive_only_default = false;
2528 	} else {
2529 		recursive_only_default = true;
2530 	}
2531 
2532 	sub_obj = cfg_tuple_get(rpz_obj, "add-soa");
2533 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2534 		add_soa_default = false;
2535 	} else {
2536 		add_soa_default = true;
2537 	}
2538 
2539 	sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
2540 	if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
2541 		zones->p.break_dnssec = true;
2542 	} else {
2543 		zones->p.break_dnssec = false;
2544 	}
2545 
2546 	sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2547 	if (cfg_obj_isduration(sub_obj)) {
2548 		ttl_default = cfg_obj_asduration(sub_obj);
2549 	} else {
2550 		ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
2551 	}
2552 
2553 	sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2554 	if (cfg_obj_isduration(sub_obj)) {
2555 		minupdateinterval_default = cfg_obj_asduration(sub_obj);
2556 	} else {
2557 		minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
2558 	}
2559 
2560 	sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
2561 	if (cfg_obj_isuint32(sub_obj)) {
2562 		zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
2563 	} else {
2564 		zones->p.min_ns_labels = 2;
2565 	}
2566 
2567 	sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
2568 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2569 		zones->p.qname_wait_recurse = true;
2570 	} else {
2571 		zones->p.qname_wait_recurse = false;
2572 	}
2573 
2574 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-wait-recurse");
2575 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2576 		zones->p.nsdname_wait_recurse = true;
2577 	} else {
2578 		zones->p.nsdname_wait_recurse = false;
2579 	}
2580 
2581 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse");
2582 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2583 		zones->p.nsip_wait_recurse = true;
2584 	} else {
2585 		zones->p.nsip_wait_recurse = false;
2586 	}
2587 
2588 	if (pview != NULL) {
2589 		old = pview->rpzs;
2590 	} else {
2591 		result = dns_viewlist_find(&named_g_server->viewlist,
2592 					   view->name, view->rdclass, &pview);
2593 		if (result == ISC_R_SUCCESS) {
2594 			pview_must_detach = true;
2595 			old = pview->rpzs;
2596 		} else {
2597 			old = NULL;
2598 		}
2599 	}
2600 
2601 	if (old == NULL) {
2602 		*old_rpz_okp = false;
2603 	} else {
2604 		*old_rpz_okp = true;
2605 	}
2606 
2607 	for (i = 0; zone_element != NULL;
2608 	     ++i, zone_element = cfg_list_next(zone_element))
2609 	{
2610 		INSIST(!*old_rpz_okp || old != NULL);
2611 		if (*old_rpz_okp && i < old->p.num_zones) {
2612 			old_zone = old->zones[i];
2613 		} else {
2614 			*old_rpz_okp = false;
2615 			old_zone = NULL;
2616 		}
2617 		result = configure_rpz_zone(
2618 			view, zone_element, recursive_only_default,
2619 			add_soa_default, ttl_default, minupdateinterval_default,
2620 			old_zone, old_rpz_okp);
2621 		if (result != ISC_R_SUCCESS) {
2622 			if (pview_must_detach) {
2623 				dns_view_detach(&pview);
2624 			}
2625 			return result;
2626 		}
2627 	}
2628 
2629 	/*
2630 	 * If this is a reloading and the parameters and list of policy
2631 	 * zones are unchanged, then use the same policy data.
2632 	 * Data for individual zones that must be reloaded will be merged.
2633 	 */
2634 	if (*old_rpz_okp) {
2635 		if (old != NULL &&
2636 		    memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
2637 		{
2638 			*old_rpz_okp = false;
2639 		} else if ((old == NULL || old->rps_cstr == NULL) !=
2640 			   (zones->rps_cstr == NULL))
2641 		{
2642 			*old_rpz_okp = false;
2643 		} else if (old != NULL && zones->rps_cstr != NULL &&
2644 			   strcmp(old->rps_cstr, zones->rps_cstr) != 0)
2645 		{
2646 			*old_rpz_okp = false;
2647 		}
2648 	}
2649 
2650 	if (*old_rpz_okp) {
2651 		dns_rpz_zones_shutdown(view->rpzs);
2652 		dns_rpz_zones_detach(&view->rpzs);
2653 		dns_rpz_zones_attach(pview->rpzs, &view->rpzs);
2654 		dns_rpz_zones_detach(&pview->rpzs);
2655 	} else if (old != NULL && pview != NULL) {
2656 		++pview->rpzs->rpz_ver;
2657 		view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
2658 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
2659 			    "updated RPZ policy: version %d",
2660 			    view->rpzs->rpz_ver);
2661 	}
2662 
2663 	if (pview_must_detach) {
2664 		dns_view_detach(&pview);
2665 	}
2666 
2667 	return ISC_R_SUCCESS;
2668 }
2669 
2670 static void
2671 catz_addmodzone_cb(void *arg) {
2672 	catz_chgzone_t *cz = (catz_chgzone_t *)arg;
2673 	isc_result_t result;
2674 	dns_forwarders_t *dnsforwarders = NULL;
2675 	dns_name_t *name = NULL;
2676 	isc_buffer_t namebuf;
2677 	isc_buffer_t *confbuf = NULL;
2678 	char nameb[DNS_NAME_FORMATSIZE];
2679 	const cfg_obj_t *zlist = NULL;
2680 	cfg_obj_t *zoneconf = NULL;
2681 	cfg_obj_t *zoneobj = NULL;
2682 	ns_cfgctx_t *cfg = NULL;
2683 	dns_zone_t *zone = NULL;
2684 
2685 	if (isc_loop_shuttingdown(isc_loop_get(named_g_loopmgr, isc_tid()))) {
2686 		goto cleanup;
2687 	}
2688 
2689 	/*
2690 	 * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
2691 	 * is true, so this is expected to be non-NULL.
2692 	 */
2693 	cfg = (ns_cfgctx_t *)cz->view->new_zone_config;
2694 	if (cfg == NULL) {
2695 		CHECK(ISC_R_FAILURE);
2696 	}
2697 
2698 	name = dns_catz_entry_getname(cz->entry);
2699 
2700 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
2701 	dns_name_totext(name, DNS_NAME_OMITFINALDOT, &namebuf);
2702 	isc_buffer_putuint8(&namebuf, 0);
2703 
2704 	result = dns_fwdtable_find(cz->view->fwdtable, name, &dnsforwarders);
2705 	if (result == ISC_R_SUCCESS &&
2706 	    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
2707 	{
2708 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2709 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2710 			      "catz: catz_addmodzone_cb: "
2711 			      "zone '%s' will not be processed because of the "
2712 			      "explicitly configured forwarding for that zone",
2713 			      nameb);
2714 		goto cleanup;
2715 	}
2716 
2717 	result = dns_view_findzone(cz->view, name, DNS_ZTFIND_EXACT, &zone);
2718 
2719 	if (cz->mod) {
2720 		dns_catz_zone_t *parentcatz;
2721 
2722 		if (result != ISC_R_SUCCESS) {
2723 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2724 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2725 				      "catz: error \"%s\" while trying to "
2726 				      "modify zone '%s'",
2727 				      isc_result_totext(result), nameb);
2728 			goto cleanup;
2729 		}
2730 
2731 		if (!dns_zone_getadded(zone)) {
2732 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2733 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2734 				      "catz: catz_addmodzone_cb: "
2735 				      "zone '%s' is not a dynamically "
2736 				      "added zone",
2737 				      nameb);
2738 			goto cleanup;
2739 		}
2740 
2741 		parentcatz = dns_zone_get_parentcatz(zone);
2742 
2743 		if (parentcatz == NULL) {
2744 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2745 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2746 				      "catz: catz_addmodzone_cb: "
2747 				      "zone '%s' exists and is not added by "
2748 				      "a catalog zone, so won't be modified",
2749 				      nameb);
2750 			goto cleanup;
2751 		}
2752 		if (parentcatz != cz->origin) {
2753 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2754 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2755 				      "catz: catz_addmodzone_cb: "
2756 				      "zone '%s' exists in multiple "
2757 				      "catalog zones",
2758 				      nameb);
2759 			goto cleanup;
2760 		}
2761 
2762 		dns_zone_detach(&zone);
2763 	} else {
2764 		/* Zone shouldn't already exist when adding */
2765 		if (result == ISC_R_SUCCESS) {
2766 			if (dns_zone_get_parentcatz(zone) == NULL) {
2767 				isc_log_write(
2768 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2769 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2770 					"catz: "
2771 					"catz_addmodzone_cb: "
2772 					"zone '%s' will not be added "
2773 					"because it is an explicitly "
2774 					"configured zone",
2775 					nameb);
2776 			} else {
2777 				isc_log_write(
2778 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2779 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2780 					"catz: "
2781 					"catz_addmodzone_cb: "
2782 					"zone '%s' will not be added "
2783 					"because another catalog zone "
2784 					"already contains an entry with "
2785 					"that zone",
2786 					nameb);
2787 			}
2788 			goto cleanup;
2789 		} else {
2790 			RUNTIME_CHECK(result == ISC_R_NOTFOUND);
2791 		}
2792 	}
2793 	RUNTIME_CHECK(zone == NULL);
2794 	/* Create a config for new zone */
2795 	confbuf = NULL;
2796 	result = dns_catz_generate_zonecfg(cz->origin, cz->entry, &confbuf);
2797 	if (result == ISC_R_SUCCESS) {
2798 		cfg_parser_reset(cfg->add_parser);
2799 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
2800 					  &cfg_type_addzoneconf, 0, &zoneconf);
2801 		isc_buffer_free(&confbuf);
2802 	}
2803 	/*
2804 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer()
2805 	 * failed.
2806 	 */
2807 	if (result != ISC_R_SUCCESS) {
2808 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2809 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2810 			      "catz: error \"%s\" while trying to generate "
2811 			      "config for zone '%s'",
2812 			      isc_result_totext(result), nameb);
2813 		goto cleanup;
2814 	}
2815 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
2816 	if (!cfg_obj_islist(zlist)) {
2817 		CHECK(ISC_R_FAILURE);
2818 	}
2819 
2820 	/* For now we only support adding one zone at a time */
2821 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
2822 
2823 	/* Mark view unfrozen so that zone can be added */
2824 	isc_loopmgr_pause(named_g_loopmgr);
2825 	dns_view_thaw(cz->view);
2826 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig, cz->view,
2827 				&cz->cbd->server->viewlist,
2828 				&cz->cbd->server->kasplist,
2829 				&cz->cbd->server->keystorelist, cfg->actx, true,
2830 				false, true, cz->mod);
2831 	dns_view_freeze(cz->view);
2832 	isc_loopmgr_resume(named_g_loopmgr);
2833 
2834 	if (result != ISC_R_SUCCESS) {
2835 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2836 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2837 			      "catz: failed to configure zone '%s' - %d", nameb,
2838 			      result);
2839 		goto cleanup;
2840 	}
2841 
2842 	/* Is it there yet? */
2843 	CHECK(dns_view_findzone(cz->view, name, DNS_ZTFIND_EXACT, &zone));
2844 
2845 	/*
2846 	 * Load the zone from the master file.	If this fails, we'll
2847 	 * need to undo the configuration we've done already.
2848 	 */
2849 	result = dns_zone_load(zone, true);
2850 	if (result != ISC_R_SUCCESS) {
2851 		dns_db_t *dbp = NULL;
2852 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2853 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2854 			      "catz: dns_zone_load() failed "
2855 			      "with %s; reverting.",
2856 			      isc_result_totext(result));
2857 
2858 		/* If the zone loaded partially, unload it */
2859 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2860 			dns_db_detach(&dbp);
2861 			dns_zone_unload(zone);
2862 		}
2863 
2864 		/* Remove the zone from the zone table */
2865 		dns_view_delzone(cz->view, zone);
2866 		goto cleanup;
2867 	}
2868 
2869 	/* Flag the zone as having been added at runtime */
2870 	dns_zone_setadded(zone, true);
2871 	dns_zone_set_parentcatz(zone, cz->origin);
2872 
2873 cleanup:
2874 	if (zone != NULL) {
2875 		dns_zone_detach(&zone);
2876 	}
2877 	if (zoneconf != NULL) {
2878 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
2879 	}
2880 	if (dnsforwarders != NULL) {
2881 		dns_forwarders_detach(&dnsforwarders);
2882 	}
2883 	dns_catz_entry_detach(cz->origin, &cz->entry);
2884 	dns_catz_zone_detach(&cz->origin);
2885 	dns_view_weakdetach(&cz->view);
2886 	isc_mem_putanddetach(&cz->mctx, cz, sizeof(*cz));
2887 }
2888 
2889 static void
2890 catz_delzone_cb(void *arg) {
2891 	catz_chgzone_t *cz = (catz_chgzone_t *)arg;
2892 	isc_result_t result;
2893 	dns_zone_t *zone = NULL;
2894 	dns_db_t *dbp = NULL;
2895 	char cname[DNS_NAME_FORMATSIZE];
2896 	const char *file = NULL;
2897 
2898 	if (isc_loop_shuttingdown(isc_loop_get(named_g_loopmgr, isc_tid()))) {
2899 		goto cleanup;
2900 	}
2901 
2902 	isc_loopmgr_pause(named_g_loopmgr);
2903 
2904 	dns_name_format(dns_catz_entry_getname(cz->entry), cname,
2905 			DNS_NAME_FORMATSIZE);
2906 	result = dns_view_findzone(cz->view, dns_catz_entry_getname(cz->entry),
2907 				   DNS_ZTFIND_EXACT, &zone);
2908 	if (result != ISC_R_SUCCESS) {
2909 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2910 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2911 			      "catz: catz_delzone_cb: "
2912 			      "zone '%s' not found",
2913 			      cname);
2914 		goto resume;
2915 	}
2916 
2917 	if (!dns_zone_getadded(zone)) {
2918 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2919 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2920 			      "catz: catz_delzone_cb: "
2921 			      "zone '%s' is not a dynamically added zone",
2922 			      cname);
2923 		goto resume;
2924 	}
2925 
2926 	if (dns_zone_get_parentcatz(zone) != cz->origin) {
2927 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2928 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2929 			      "catz: catz_delzone_cb: zone "
2930 			      "'%s' exists in multiple catalog zones",
2931 			      cname);
2932 		goto resume;
2933 	}
2934 
2935 	/* Stop answering for this zone */
2936 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2937 		dns_db_detach(&dbp);
2938 		dns_zone_unload(zone);
2939 	}
2940 
2941 	if (dns_view_delzone(cz->view, zone) != ISC_R_SUCCESS) {
2942 		goto resume;
2943 	}
2944 	file = dns_zone_getfile(zone);
2945 	if (file != NULL) {
2946 		isc_file_remove(file);
2947 		file = dns_zone_getjournal(zone);
2948 		if (file != NULL) {
2949 			isc_file_remove(file);
2950 		}
2951 	}
2952 
2953 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2954 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2955 		      "catz: catz_delzone_cb: "
2956 		      "zone '%s' deleted",
2957 		      cname);
2958 resume:
2959 	isc_loopmgr_resume(named_g_loopmgr);
2960 cleanup:
2961 	if (zone != NULL) {
2962 		dns_zone_detach(&zone);
2963 	}
2964 	dns_catz_entry_detach(cz->origin, &cz->entry);
2965 	dns_catz_zone_detach(&cz->origin);
2966 	dns_view_weakdetach(&cz->view);
2967 	isc_mem_putanddetach(&cz->mctx, cz, sizeof(*cz));
2968 }
2969 
2970 static isc_result_t
2971 catz_run(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
2972 	 void *udata, catz_type_t type) {
2973 	catz_chgzone_t *cz = NULL;
2974 	isc_job_cb action = NULL;
2975 
2976 	switch (type) {
2977 	case CATZ_ADDZONE:
2978 	case CATZ_MODZONE:
2979 		action = catz_addmodzone_cb;
2980 		break;
2981 	case CATZ_DELZONE:
2982 		action = catz_delzone_cb;
2983 		break;
2984 	default:
2985 		REQUIRE(0);
2986 		UNREACHABLE();
2987 	}
2988 
2989 	cz = isc_mem_get(view->mctx, sizeof(*cz));
2990 	*cz = (catz_chgzone_t){
2991 		.cbd = (catz_cb_data_t *)udata,
2992 		.mod = (type == CATZ_MODZONE),
2993 	};
2994 	isc_mem_attach(view->mctx, &cz->mctx);
2995 
2996 	dns_catz_entry_attach(entry, &cz->entry);
2997 	dns_catz_zone_attach(origin, &cz->origin);
2998 	dns_view_weakattach(view, &cz->view);
2999 
3000 	isc_async_run(named_g_mainloop, action, cz);
3001 
3002 	return ISC_R_SUCCESS;
3003 }
3004 
3005 static isc_result_t
3006 catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3007 	     void *udata) {
3008 	return catz_run(entry, origin, view, udata, CATZ_ADDZONE);
3009 }
3010 
3011 static isc_result_t
3012 catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3013 	     void *udata) {
3014 	return catz_run(entry, origin, view, udata, CATZ_DELZONE);
3015 }
3016 
3017 static isc_result_t
3018 catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3019 	     void *udata) {
3020 	return catz_run(entry, origin, view, udata, CATZ_MODZONE);
3021 }
3022 
3023 static void
3024 catz_changeview(dns_catz_entry_t *entry, void *arg1, void *arg2) {
3025 	dns_view_t *pview = arg1;
3026 	dns_view_t *view = arg2;
3027 
3028 	dns_zone_t *zone = NULL;
3029 	isc_result_t result = dns_view_findzone(
3030 		pview, dns_catz_entry_getname(entry), DNS_ZTFIND_EXACT, &zone);
3031 
3032 	if (result != ISC_R_SUCCESS) {
3033 		return;
3034 	}
3035 
3036 	dns_zone_setview(zone, view);
3037 	dns_view_addzone(view, zone);
3038 
3039 	dns_zone_detach(&zone);
3040 }
3041 
3042 static void
3043 catz_reconfigure(dns_catz_entry_t *entry, void *arg1, void *arg2) {
3044 	dns_view_t *view = arg1;
3045 	catz_reconfig_data_t *data = arg2;
3046 	isc_buffer_t namebuf;
3047 	isc_buffer_t *confbuf = NULL;
3048 	const cfg_obj_t *zlist = NULL;
3049 	char nameb[DNS_NAME_FORMATSIZE];
3050 	cfg_obj_t *zoneconf = NULL;
3051 	cfg_obj_t *zoneobj = NULL;
3052 	ns_cfgctx_t *cfg = NULL;
3053 	dns_zone_t *zone = NULL;
3054 	isc_result_t result;
3055 
3056 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
3057 	dns_name_totext(dns_catz_entry_getname(entry), DNS_NAME_OMITFINALDOT,
3058 			&namebuf);
3059 	isc_buffer_putuint8(&namebuf, 0);
3060 
3061 	result = dns_view_findzone(view, dns_catz_entry_getname(entry),
3062 				   DNS_ZTFIND_EXACT, &zone);
3063 	if (result != ISC_R_SUCCESS) {
3064 		return;
3065 	}
3066 
3067 	/*
3068 	 * A non-empty 'catalog-zones' statement implies that 'allow-new-zones'
3069 	 * is true, so this is expected to be non-NULL.
3070 	 */
3071 	cfg = (ns_cfgctx_t *)view->new_zone_config;
3072 	if (cfg == NULL) {
3073 		CHECK(ISC_R_FAILURE);
3074 	}
3075 
3076 	result = dns_catz_generate_zonecfg(data->catz, entry, &confbuf);
3077 	if (result == ISC_R_SUCCESS) {
3078 		cfg_parser_reset(cfg->add_parser);
3079 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
3080 					  &cfg_type_addzoneconf, 0, &zoneconf);
3081 		isc_buffer_free(&confbuf);
3082 	}
3083 	/*
3084 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer()
3085 	 * failed.
3086 	 */
3087 	if (result != ISC_R_SUCCESS) {
3088 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3089 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3090 			      "catz_reconfigure: error \"%s\" while trying to "
3091 			      "generate config for member zone '%s'",
3092 			      isc_result_totext(result), nameb);
3093 		goto cleanup;
3094 	}
3095 
3096 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
3097 	if (!cfg_obj_islist(zlist)) {
3098 		CHECK(ISC_R_FAILURE);
3099 	}
3100 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
3101 
3102 	result = configure_zone(data->config, zoneobj, cfg->vconfig, view,
3103 				&data->cbd->server->viewlist,
3104 				&data->cbd->server->kasplist,
3105 				&data->cbd->server->keystorelist, cfg->actx,
3106 				true, false, true, true);
3107 	if (result != ISC_R_SUCCESS) {
3108 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3109 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3110 			      "catz_reconfigure : error \"%s\" while trying to "
3111 			      "reconfigure member zone '%s'",
3112 			      isc_result_totext(result), nameb);
3113 		goto cleanup;
3114 	}
3115 
3116 cleanup:
3117 	if (zoneconf != NULL) {
3118 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
3119 	}
3120 
3121 	dns_zone_detach(&zone);
3122 }
3123 
3124 static isc_result_t
3125 configure_catz_zone(dns_view_t *view, dns_view_t *pview,
3126 		    const cfg_obj_t *config, const cfg_listelt_t *element) {
3127 	const cfg_obj_t *catz_obj, *obj;
3128 	dns_catz_zone_t *zone = NULL;
3129 	const char *str;
3130 	isc_result_t result;
3131 	dns_name_t origin;
3132 	dns_catz_options_t *opts;
3133 
3134 	dns_name_init(&origin, NULL);
3135 	catz_obj = cfg_listelt_value(element);
3136 
3137 	str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
3138 
3139 	result = dns_name_fromstring(&origin, str, dns_rootname,
3140 				     DNS_NAME_DOWNCASE, view->mctx);
3141 	if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname)) {
3142 		result = DNS_R_EMPTYLABEL;
3143 	}
3144 
3145 	if (result != ISC_R_SUCCESS) {
3146 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3147 			    "catz: invalid zone name '%s'", str);
3148 		goto cleanup;
3149 	}
3150 
3151 	result = dns_catz_zone_add(view->catzs, &origin, &zone);
3152 	if (result == ISC_R_EXISTS) {
3153 		catz_reconfig_data_t data = {
3154 			.catz = zone,
3155 			.config = config,
3156 			.cbd = (catz_cb_data_t *)dns_catz_zones_get_udata(
3157 				view->catzs),
3158 		};
3159 
3160 		/*
3161 		 * We have to walk through all the member zones, re-attach
3162 		 * them to the current view and reconfigure
3163 		 */
3164 		dns_catz_zone_for_each_entry2(zone, catz_changeview, pview,
3165 					      view);
3166 		dns_catz_zone_for_each_entry2(zone, catz_reconfigure, view,
3167 					      &data);
3168 	}
3169 
3170 	dns_catz_zone_resetdefoptions(zone);
3171 	opts = dns_catz_zone_getdefoptions(zone);
3172 
3173 	obj = cfg_tuple_get(catz_obj, "default-masters");
3174 	if (obj == NULL || !cfg_obj_istuple(obj)) {
3175 		obj = cfg_tuple_get(catz_obj, "default-primaries");
3176 	}
3177 	if (obj != NULL && cfg_obj_istuple(obj)) {
3178 		result = named_config_getipandkeylist(
3179 			config, "primaries", obj, view->mctx, &opts->masters);
3180 	}
3181 
3182 	obj = cfg_tuple_get(catz_obj, "in-memory");
3183 	if (obj != NULL && cfg_obj_isboolean(obj)) {
3184 		opts->in_memory = cfg_obj_asboolean(obj);
3185 	}
3186 
3187 	obj = cfg_tuple_get(catz_obj, "zone-directory");
3188 	if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) {
3189 		opts->zonedir = isc_mem_strdup(view->mctx,
3190 					       cfg_obj_asstring(obj));
3191 		if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) {
3192 			cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3193 				    "catz: zone-directory '%s' "
3194 				    "not found; zone files will not be "
3195 				    "saved",
3196 				    opts->zonedir);
3197 			opts->in_memory = true;
3198 		}
3199 	}
3200 
3201 	obj = cfg_tuple_get(catz_obj, "min-update-interval");
3202 	if (obj != NULL && cfg_obj_isduration(obj)) {
3203 		opts->min_update_interval = cfg_obj_asduration(obj);
3204 	}
3205 
3206 cleanup:
3207 	dns_name_free(&origin, view->mctx);
3208 
3209 	return result;
3210 }
3211 
3212 static catz_cb_data_t ns_catz_cbdata;
3213 static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
3214 	catz_addzone, catz_modzone, catz_delzone, &ns_catz_cbdata
3215 };
3216 
3217 static isc_result_t
3218 configure_catz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t *config,
3219 	       const cfg_obj_t *catz_obj) {
3220 	const cfg_listelt_t *zone_element = NULL;
3221 	const dns_catz_zones_t *old = NULL;
3222 	bool pview_must_detach = false;
3223 	isc_result_t result;
3224 
3225 	/* xxxwpk TODO do it cleaner, once, somewhere */
3226 	ns_catz_cbdata.server = named_g_server;
3227 
3228 	zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
3229 	if (zone_element == NULL) {
3230 		return ISC_R_SUCCESS;
3231 	}
3232 
3233 	if (pview != NULL) {
3234 		old = pview->catzs;
3235 	} else {
3236 		result = dns_viewlist_find(&named_g_server->viewlist,
3237 					   view->name, view->rdclass, &pview);
3238 		if (result == ISC_R_SUCCESS) {
3239 			pview_must_detach = true;
3240 			old = pview->catzs;
3241 		}
3242 	}
3243 
3244 	if (old != NULL) {
3245 		dns_catz_zones_attach(pview->catzs, &view->catzs);
3246 		dns_catz_zones_detach(&pview->catzs);
3247 		dns_catz_prereconfig(view->catzs);
3248 	} else {
3249 		view->catzs = dns_catz_zones_new(view->mctx, named_g_loopmgr,
3250 						 &ns_catz_zonemodmethods);
3251 	}
3252 
3253 	while (zone_element != NULL) {
3254 		CHECK(configure_catz_zone(view, pview, config, zone_element));
3255 		zone_element = cfg_list_next(zone_element);
3256 	}
3257 
3258 	if (old != NULL) {
3259 		dns_catz_postreconfig(view->catzs);
3260 	}
3261 
3262 	result = ISC_R_SUCCESS;
3263 
3264 cleanup:
3265 	if (pview_must_detach) {
3266 		dns_view_detach(&pview);
3267 	}
3268 
3269 	return result;
3270 }
3271 
3272 #define CHECK_RRL(cond, pat, val1, val2)                                   \
3273 	do {                                                               \
3274 		if (!(cond)) {                                             \
3275 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, pat, \
3276 				    val1, val2);                           \
3277 			result = ISC_R_RANGE;                              \
3278 			goto cleanup;                                      \
3279 		}                                                          \
3280 	} while (0)
3281 
3282 #define CHECK_RRL_RATE(rate, def, max_rate, name)                           \
3283 	do {                                                                \
3284 		obj = NULL;                                                 \
3285 		rrl->rate.str = name;                                       \
3286 		result = cfg_map_get(map, name, &obj);                      \
3287 		if (result == ISC_R_SUCCESS) {                              \
3288 			rrl->rate.r = cfg_obj_asuint32(obj);                \
3289 			CHECK_RRL(rrl->rate.r <= max_rate, name " %d > %d", \
3290 				  rrl->rate.r, max_rate);                   \
3291 		} else {                                                    \
3292 			rrl->rate.r = def;                                  \
3293 		}                                                           \
3294 		rrl->rate.scaled = rrl->rate.r;                             \
3295 	} while (0)
3296 
3297 static isc_result_t
3298 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
3299 	const cfg_obj_t *obj;
3300 	dns_rrl_t *rrl;
3301 	isc_result_t result;
3302 	int min_entries, i, j;
3303 
3304 	/*
3305 	 * Most DNS servers have few clients, but intentinally open
3306 	 * recursive and authoritative servers often have many.
3307 	 * So start with a small number of entries unless told otherwise
3308 	 * to reduce cold-start costs.
3309 	 */
3310 	min_entries = 500;
3311 	obj = NULL;
3312 	result = cfg_map_get(map, "min-table-size", &obj);
3313 	if (result == ISC_R_SUCCESS) {
3314 		min_entries = cfg_obj_asuint32(obj);
3315 		if (min_entries < 1) {
3316 			min_entries = 1;
3317 		}
3318 	}
3319 	result = dns_rrl_init(&rrl, view, min_entries);
3320 	if (result != ISC_R_SUCCESS) {
3321 		return result;
3322 	}
3323 
3324 	i = ISC_MAX(20000, min_entries);
3325 	obj = NULL;
3326 	result = cfg_map_get(map, "max-table-size", &obj);
3327 	if (result == ISC_R_SUCCESS) {
3328 		i = cfg_obj_asuint32(obj);
3329 		CHECK_RRL(i >= min_entries,
3330 			  "max-table-size %d < min-table-size %d", i,
3331 			  min_entries);
3332 	}
3333 	rrl->max_entries = i;
3334 
3335 	CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
3336 		       "responses-per-second");
3337 	CHECK_RRL_RATE(referrals_per_second, rrl->responses_per_second.r,
3338 		       DNS_RRL_MAX_RATE, "referrals-per-second");
3339 	CHECK_RRL_RATE(nodata_per_second, rrl->responses_per_second.r,
3340 		       DNS_RRL_MAX_RATE, "nodata-per-second");
3341 	CHECK_RRL_RATE(nxdomains_per_second, rrl->responses_per_second.r,
3342 		       DNS_RRL_MAX_RATE, "nxdomains-per-second");
3343 	CHECK_RRL_RATE(errors_per_second, rrl->responses_per_second.r,
3344 		       DNS_RRL_MAX_RATE, "errors-per-second");
3345 
3346 	CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
3347 
3348 	CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
3349 
3350 	i = 15;
3351 	obj = NULL;
3352 	result = cfg_map_get(map, "window", &obj);
3353 	if (result == ISC_R_SUCCESS) {
3354 		i = cfg_obj_asuint32(obj);
3355 		CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
3356 			  "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
3357 	}
3358 	rrl->window = i;
3359 
3360 	i = 0;
3361 	obj = NULL;
3362 	result = cfg_map_get(map, "qps-scale", &obj);
3363 	if (result == ISC_R_SUCCESS) {
3364 		i = cfg_obj_asuint32(obj);
3365 		CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
3366 	}
3367 	rrl->qps_scale = i;
3368 	rrl->qps = 1.0;
3369 
3370 	i = 24;
3371 	obj = NULL;
3372 	result = cfg_map_get(map, "ipv4-prefix-length", &obj);
3373 	if (result == ISC_R_SUCCESS) {
3374 		i = cfg_obj_asuint32(obj);
3375 		CHECK_RRL(i >= 8 && i <= 32,
3376 			  "invalid 'ipv4-prefix-length %d'%s", i, "");
3377 	}
3378 	rrl->ipv4_prefixlen = i;
3379 	if (i == 32) {
3380 		rrl->ipv4_mask = 0xffffffff;
3381 	} else {
3382 		rrl->ipv4_mask = htonl(0xffffffff << (32 - i));
3383 	}
3384 
3385 	i = 56;
3386 	obj = NULL;
3387 	result = cfg_map_get(map, "ipv6-prefix-length", &obj);
3388 	if (result == ISC_R_SUCCESS) {
3389 		i = cfg_obj_asuint32(obj);
3390 		CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
3391 			  "ipv6-prefix-length %d < 16 or > %d", i,
3392 			  DNS_RRL_MAX_PREFIX);
3393 	}
3394 	rrl->ipv6_prefixlen = i;
3395 	for (j = 0; j < 4; ++j) {
3396 		if (i <= 0) {
3397 			rrl->ipv6_mask[j] = 0;
3398 		} else if (i < 32) {
3399 			rrl->ipv6_mask[j] = htonl(0xffffffff << (32 - i));
3400 		} else {
3401 			rrl->ipv6_mask[j] = 0xffffffff;
3402 		}
3403 		i -= 32;
3404 	}
3405 
3406 	obj = NULL;
3407 	result = cfg_map_get(map, "exempt-clients", &obj);
3408 	if (result == ISC_R_SUCCESS) {
3409 		result = cfg_acl_fromconfig(obj, config, named_g_lctx,
3410 					    named_g_aclconfctx, named_g_mctx, 0,
3411 					    &rrl->exempt);
3412 		CHECK_RRL(result == ISC_R_SUCCESS, "invalid %s%s",
3413 			  "address match list", "");
3414 	}
3415 
3416 	obj = NULL;
3417 	result = cfg_map_get(map, "log-only", &obj);
3418 	if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) {
3419 		rrl->log_only = true;
3420 	} else {
3421 		rrl->log_only = false;
3422 	}
3423 
3424 	return ISC_R_SUCCESS;
3425 
3426 cleanup:
3427 	dns_rrl_view_destroy(view);
3428 	return result;
3429 }
3430 
3431 static isc_result_t
3432 add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3433 	const dns_name_t *origin, const dns_name_t *contact) {
3434 	dns_dbnode_t *node = NULL;
3435 	dns_rdata_t rdata = DNS_RDATA_INIT;
3436 	dns_rdatalist_t rdatalist;
3437 	dns_rdataset_t rdataset;
3438 	isc_result_t result;
3439 	unsigned char buf[DNS_SOA_BUFFERSIZE];
3440 
3441 	CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 0, 28800,
3442 				 7200, 604800, 86400, buf, &rdata));
3443 
3444 	dns_rdatalist_init(&rdatalist);
3445 	rdatalist.type = rdata.type;
3446 	rdatalist.rdclass = rdata.rdclass;
3447 	rdatalist.ttl = 86400;
3448 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3449 
3450 	dns_rdataset_init(&rdataset);
3451 	dns_rdatalist_tordataset(&rdatalist, &rdataset);
3452 	CHECK(dns_db_findnode(db, name, true, &node));
3453 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3454 
3455 cleanup:
3456 	if (node != NULL) {
3457 		dns_db_detachnode(db, &node);
3458 	}
3459 	return result;
3460 }
3461 
3462 static isc_result_t
3463 add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3464        const dns_name_t *nsname) {
3465 	dns_dbnode_t *node = NULL;
3466 	dns_rdata_ns_t ns;
3467 	dns_rdata_t rdata = DNS_RDATA_INIT;
3468 	dns_rdatalist_t rdatalist;
3469 	dns_rdataset_t rdataset;
3470 	isc_result_t result;
3471 	isc_buffer_t b;
3472 	unsigned char buf[DNS_NAME_MAXWIRE];
3473 
3474 	isc_buffer_init(&b, buf, sizeof(buf));
3475 
3476 	ns.common.rdtype = dns_rdatatype_ns;
3477 	ns.common.rdclass = dns_db_class(db);
3478 	ns.mctx = NULL;
3479 	dns_name_init(&ns.name, NULL);
3480 	dns_name_clone(nsname, &ns.name);
3481 	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
3482 				   &ns, &b));
3483 
3484 	dns_rdatalist_init(&rdatalist);
3485 	rdatalist.type = rdata.type;
3486 	rdatalist.rdclass = rdata.rdclass;
3487 	rdatalist.ttl = 86400;
3488 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3489 
3490 	dns_rdataset_init(&rdataset);
3491 	dns_rdatalist_tordataset(&rdatalist, &rdataset);
3492 	CHECK(dns_db_findnode(db, name, true, &node));
3493 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3494 
3495 cleanup:
3496 	if (node != NULL) {
3497 		dns_db_detachnode(db, &node);
3498 	}
3499 	return result;
3500 }
3501 
3502 static isc_result_t
3503 create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
3504 		  const cfg_obj_t *zonelist, const char **empty_dbtype,
3505 		  int empty_dbtypec, dns_zonestat_level_t statlevel) {
3506 	char namebuf[DNS_NAME_FORMATSIZE];
3507 	const cfg_listelt_t *element;
3508 	const cfg_obj_t *obj;
3509 	const cfg_obj_t *zconfig;
3510 	const cfg_obj_t *zoptions;
3511 	const char *default_dbtype[4] = { ZONEDB_DEFAULT };
3512 	const char *sep = ": view ";
3513 	const char *str;
3514 	const char *viewname = view->name;
3515 	dns_db_t *db = NULL;
3516 	dns_dbversion_t *version = NULL;
3517 	dns_fixedname_t cfixed;
3518 	dns_fixedname_t fixed;
3519 	dns_fixedname_t nsfixed;
3520 	dns_name_t *contact;
3521 	dns_name_t *ns;
3522 	dns_name_t *zname;
3523 	dns_zone_t *zone = NULL;
3524 	int default_dbtypec = 1;
3525 	isc_result_t result;
3526 	dns_namereln_t namereln;
3527 	int order;
3528 	unsigned int nlabels;
3529 
3530 	zname = dns_fixedname_initname(&fixed);
3531 	ns = dns_fixedname_initname(&nsfixed);
3532 	contact = dns_fixedname_initname(&cfixed);
3533 
3534 	/*
3535 	 * Look for forward "zones" beneath this empty zone and if so
3536 	 * create a custom db for the empty zone.
3537 	 */
3538 	for (element = cfg_list_first(zonelist); element != NULL;
3539 	     element = cfg_list_next(element))
3540 	{
3541 		zconfig = cfg_listelt_value(element);
3542 		str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3543 		CHECK(dns_name_fromstring(zname, str, dns_rootname, 0, NULL));
3544 		namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
3545 		if (namereln != dns_namereln_subdomain) {
3546 			continue;
3547 		}
3548 
3549 		zoptions = cfg_tuple_get(zconfig, "options");
3550 
3551 		obj = NULL;
3552 		(void)cfg_map_get(zoptions, "type", &obj);
3553 		if (obj != NULL &&
3554 		    strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
3555 		{
3556 			obj = NULL;
3557 			(void)cfg_map_get(zoptions, "forward", &obj);
3558 			if (obj == NULL) {
3559 				continue;
3560 			}
3561 			if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) {
3562 				continue;
3563 			}
3564 		}
3565 		if (db == NULL) {
3566 			CHECK(dns_db_create(view->mctx, ZONEDB_DEFAULT, name,
3567 					    dns_dbtype_zone, view->rdclass, 0,
3568 					    NULL, &db));
3569 			CHECK(dns_db_newversion(db, &version));
3570 			if (strcmp(empty_dbtype[2], "@") == 0) {
3571 				dns_name_clone(name, ns);
3572 			} else {
3573 				CHECK(dns_name_fromstring(ns, empty_dbtype[2],
3574 							  dns_rootname, 0,
3575 							  NULL));
3576 			}
3577 			CHECK(dns_name_fromstring(contact, empty_dbtype[3],
3578 						  dns_rootname, 0, NULL));
3579 			CHECK(add_soa(db, version, name, ns, contact));
3580 			CHECK(add_ns(db, version, name, ns));
3581 		}
3582 		CHECK(add_ns(db, version, zname, dns_rootname));
3583 	}
3584 
3585 	/*
3586 	 * Is the existing zone ok to use?
3587 	 */
3588 	if (pzone != NULL) {
3589 		unsigned int typec;
3590 		const char **dbargv = NULL;
3591 
3592 		if (db != NULL) {
3593 			typec = default_dbtypec;
3594 			dbargv = default_dbtype;
3595 		} else {
3596 			typec = empty_dbtypec;
3597 			dbargv = empty_dbtype;
3598 		}
3599 
3600 		result = check_dbtype(pzone, typec, dbargv, view->mctx);
3601 		if (result != ISC_R_SUCCESS) {
3602 			pzone = NULL;
3603 		}
3604 
3605 		if (pzone != NULL &&
3606 		    dns_zone_gettype(pzone) != dns_zone_primary)
3607 		{
3608 			pzone = NULL;
3609 		}
3610 		if (pzone != NULL && dns_zone_getfile(pzone) != NULL) {
3611 			pzone = NULL;
3612 		}
3613 		if (pzone != NULL) {
3614 			dns_zone_getraw(pzone, &zone);
3615 			if (zone != NULL) {
3616 				dns_zone_detach(&zone);
3617 				pzone = NULL;
3618 			}
3619 		}
3620 	}
3621 
3622 	if (pzone == NULL) {
3623 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
3624 		CHECK(dns_zone_setorigin(zone, name));
3625 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3626 		if (db == NULL) {
3627 			dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype);
3628 		}
3629 		dns_zone_setclass(zone, view->rdclass);
3630 		dns_zone_settype(zone, dns_zone_primary);
3631 		dns_zone_setstats(zone, named_g_server->zonestats);
3632 	} else {
3633 		dns_zone_attach(pzone, &zone);
3634 	}
3635 
3636 	dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
3637 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3638 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
3639 	dns_zone_setnotifytype(zone, dns_notifytype_no);
3640 	dns_zone_setdialup(zone, dns_dialuptype_no);
3641 	dns_zone_setautomatic(zone, true);
3642 	if (view->queryacl != NULL) {
3643 		dns_zone_setqueryacl(zone, view->queryacl);
3644 	} else {
3645 		dns_zone_clearqueryacl(zone);
3646 	}
3647 	if (view->queryonacl != NULL) {
3648 		dns_zone_setqueryonacl(zone, view->queryonacl);
3649 	} else {
3650 		dns_zone_clearqueryonacl(zone);
3651 	}
3652 	dns_zone_clearupdateacl(zone);
3653 	if (view->transferacl != NULL) {
3654 		dns_zone_setxfracl(zone, view->transferacl);
3655 	} else {
3656 		dns_zone_clearxfracl(zone);
3657 	}
3658 
3659 	setquerystats(zone, view->mctx, statlevel);
3660 	if (db != NULL) {
3661 		dns_db_closeversion(db, &version, true);
3662 		CHECK(dns_zone_replacedb(zone, db, false));
3663 	}
3664 	dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true);
3665 	dns_zone_setview(zone, view);
3666 	CHECK(dns_view_addzone(view, zone));
3667 
3668 	if (!strcmp(viewname, "_default")) {
3669 		sep = "";
3670 		viewname = "";
3671 	}
3672 	dns_name_format(name, namebuf, sizeof(namebuf));
3673 	isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD,
3674 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3675 		      "automatic empty zone%s%s: %s", sep, viewname, namebuf);
3676 
3677 cleanup:
3678 	if (zone != NULL) {
3679 		dns_zone_detach(&zone);
3680 	}
3681 	if (version != NULL) {
3682 		dns_db_closeversion(db, &version, false);
3683 	}
3684 	if (db != NULL) {
3685 		dns_db_detach(&db);
3686 	}
3687 
3688 	INSIST(version == NULL);
3689 
3690 	return result;
3691 }
3692 
3693 static isc_result_t
3694 create_ipv4only_zone(dns_zone_t *pzone, dns_view_t *view,
3695 		     const dns_name_t *name, const char *type, isc_mem_t *mctx,
3696 		     const char *server, const char *contact) {
3697 	char namebuf[DNS_NAME_FORMATSIZE];
3698 	const char *dbtype[4] = { "_builtin", NULL, "@", "." };
3699 	const char *sep = ": view ";
3700 	const char *viewname = view->name;
3701 	dns_zone_t *zone = NULL;
3702 	int dbtypec = 4;
3703 	isc_result_t result;
3704 
3705 	REQUIRE(type != NULL);
3706 
3707 	if (!strcmp(viewname, "_default")) {
3708 		sep = "";
3709 		viewname = "";
3710 	}
3711 
3712 	dbtype[1] = type;
3713 	if (server != NULL) {
3714 		dbtype[2] = server;
3715 	}
3716 	if (contact != NULL) {
3717 		dbtype[3] = contact;
3718 	}
3719 
3720 	if (pzone != NULL) {
3721 		result = check_dbtype(pzone, dbtypec, dbtype, view->mctx);
3722 		if (result != ISC_R_SUCCESS) {
3723 			pzone = NULL;
3724 		}
3725 	}
3726 
3727 	if (pzone == NULL) {
3728 		/*
3729 		 * Create the actual zone.
3730 		 */
3731 		dns_zone_create(&zone, mctx, 0);
3732 		CHECK(dns_zone_setorigin(zone, name));
3733 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3734 		dns_zone_setclass(zone, view->rdclass);
3735 		dns_zone_settype(zone, dns_zone_primary);
3736 		dns_zone_setstats(zone, named_g_server->zonestats);
3737 		dns_zone_setdbtype(zone, dbtypec, dbtype);
3738 		dns_zone_setdialup(zone, dns_dialuptype_no);
3739 		dns_zone_setcheckdstype(zone, dns_checkdstype_no);
3740 		dns_zone_setnotifytype(zone, dns_notifytype_no);
3741 		dns_zone_setautomatic(zone, true);
3742 		dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3743 	} else {
3744 		dns_zone_attach(pzone, &zone);
3745 	}
3746 	if (view->queryacl != NULL) {
3747 		dns_zone_setqueryacl(zone, view->queryacl);
3748 	} else {
3749 		dns_zone_clearqueryacl(zone);
3750 	}
3751 	if (view->queryonacl != NULL) {
3752 		dns_zone_setqueryonacl(zone, view->queryonacl);
3753 	} else {
3754 		dns_zone_clearqueryonacl(zone);
3755 	}
3756 	dns_zone_setview(zone, view);
3757 	CHECK(dns_view_addzone(view, zone));
3758 
3759 	dns_name_format(name, namebuf, sizeof(namebuf));
3760 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3761 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3762 		      "automatic ipv4only zone%s%s: %s", sep, viewname,
3763 		      namebuf);
3764 
3765 cleanup:
3766 	if (zone != NULL) {
3767 		dns_zone_detach(&zone);
3768 	}
3769 	return result;
3770 }
3771 
3772 #ifdef HAVE_DNSTAP
3773 static isc_result_t
3774 configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
3775 	isc_result_t result;
3776 	const cfg_obj_t *obj, *obj2;
3777 	const cfg_listelt_t *element;
3778 	const char *dpath;
3779 	const cfg_obj_t *dlist = NULL;
3780 	dns_dtmsgtype_t dttypes = 0;
3781 	unsigned int i;
3782 	struct fstrm_iothr_options *fopt = NULL;
3783 
3784 	result = named_config_get(maps, "dnstap", &dlist);
3785 	if (result != ISC_R_SUCCESS) {
3786 		return ISC_R_SUCCESS;
3787 	}
3788 
3789 	for (element = cfg_list_first(dlist); element != NULL;
3790 	     element = cfg_list_next(element))
3791 	{
3792 		const char *str;
3793 		dns_dtmsgtype_t dt = 0;
3794 
3795 		obj = cfg_listelt_value(element);
3796 		obj2 = cfg_tuple_get(obj, "type");
3797 		str = cfg_obj_asstring(obj2);
3798 		if (strcasecmp(str, "client") == 0) {
3799 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR;
3800 		} else if (strcasecmp(str, "auth") == 0) {
3801 			dt |= DNS_DTTYPE_AQ | DNS_DTTYPE_AR;
3802 		} else if (strcasecmp(str, "resolver") == 0) {
3803 			dt |= DNS_DTTYPE_RQ | DNS_DTTYPE_RR;
3804 		} else if (strcasecmp(str, "forwarder") == 0) {
3805 			dt |= DNS_DTTYPE_FQ | DNS_DTTYPE_FR;
3806 		} else if (strcasecmp(str, "update") == 0) {
3807 			dt |= DNS_DTTYPE_UQ | DNS_DTTYPE_UR;
3808 		} else if (strcasecmp(str, "all") == 0) {
3809 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR | DNS_DTTYPE_AQ |
3810 			      DNS_DTTYPE_AR | DNS_DTTYPE_RQ | DNS_DTTYPE_RR |
3811 			      DNS_DTTYPE_FQ | DNS_DTTYPE_FR | DNS_DTTYPE_UQ |
3812 			      DNS_DTTYPE_UR;
3813 		}
3814 
3815 		obj2 = cfg_tuple_get(obj, "mode");
3816 		if (obj2 == NULL || cfg_obj_isvoid(obj2)) {
3817 			dttypes |= dt;
3818 			continue;
3819 		}
3820 
3821 		str = cfg_obj_asstring(obj2);
3822 		if (strcasecmp(str, "query") == 0) {
3823 			dt &= ~DNS_DTTYPE_RESPONSE;
3824 		} else if (strcasecmp(str, "response") == 0) {
3825 			dt &= ~DNS_DTTYPE_QUERY;
3826 		}
3827 
3828 		dttypes |= dt;
3829 	}
3830 
3831 	if (named_g_server->dtenv == NULL && dttypes != 0) {
3832 		dns_dtmode_t dmode;
3833 		uint64_t max_size = 0;
3834 		uint32_t rolls = 0;
3835 		isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment;
3836 
3837 		obj = NULL;
3838 		CHECKM(named_config_get(maps, "dnstap-output", &obj),
3839 		       "'dnstap-output' must be set if 'dnstap' is set");
3840 
3841 		obj2 = cfg_tuple_get(obj, "mode");
3842 		if (obj2 == NULL) {
3843 			CHECKM(ISC_R_FAILURE, "dnstap-output mode not found");
3844 		}
3845 		if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) {
3846 			dmode = dns_dtmode_file;
3847 		} else {
3848 			dmode = dns_dtmode_unix;
3849 		}
3850 
3851 		obj2 = cfg_tuple_get(obj, "path");
3852 		if (obj2 == NULL) {
3853 			CHECKM(ISC_R_FAILURE, "dnstap-output path not found");
3854 		}
3855 
3856 		dpath = cfg_obj_asstring(obj2);
3857 
3858 		obj2 = cfg_tuple_get(obj, "size");
3859 		if (obj2 != NULL && cfg_obj_isuint64(obj2)) {
3860 			max_size = cfg_obj_asuint64(obj2);
3861 			if (max_size > SIZE_MAX) {
3862 				cfg_obj_log(obj2, named_g_lctx, ISC_LOG_WARNING,
3863 					    "'dnstap-output size "
3864 					    "%" PRIu64 "' "
3865 					    "is too large for this "
3866 					    "system; reducing to %lu",
3867 					    max_size, (unsigned long)SIZE_MAX);
3868 				max_size = SIZE_MAX;
3869 			}
3870 		}
3871 
3872 		obj2 = cfg_tuple_get(obj, "versions");
3873 		if (obj2 != NULL && cfg_obj_isuint32(obj2)) {
3874 			rolls = cfg_obj_asuint32(obj2);
3875 		} else {
3876 			rolls = ISC_LOG_ROLLINFINITE;
3877 		}
3878 
3879 		obj2 = cfg_tuple_get(obj, "suffix");
3880 		if (obj2 != NULL && cfg_obj_isstring(obj2) &&
3881 		    strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0)
3882 		{
3883 			suffix = isc_log_rollsuffix_timestamp;
3884 		}
3885 
3886 		fopt = fstrm_iothr_options_init();
3887 		/*
3888 		 * Both network threads and worker threads may log dnstap data.
3889 		 */
3890 		fstrm_iothr_options_set_num_input_queues(fopt,
3891 							 2 * named_g_cpus);
3892 		fstrm_iothr_options_set_queue_model(
3893 			fopt, FSTRM_IOTHR_QUEUE_MODEL_MPSC);
3894 
3895 		obj = NULL;
3896 		result = named_config_get(maps, "fstrm-set-buffer-hint", &obj);
3897 		if (result == ISC_R_SUCCESS) {
3898 			i = cfg_obj_asuint32(obj);
3899 			fstrm_iothr_options_set_buffer_hint(fopt, i);
3900 		}
3901 
3902 		obj = NULL;
3903 		result = named_config_get(maps, "fstrm-set-flush-timeout",
3904 					  &obj);
3905 		if (result == ISC_R_SUCCESS) {
3906 			i = cfg_obj_asuint32(obj);
3907 			fstrm_iothr_options_set_flush_timeout(fopt, i);
3908 		}
3909 
3910 		obj = NULL;
3911 		result = named_config_get(maps, "fstrm-set-input-queue-size",
3912 					  &obj);
3913 		if (result == ISC_R_SUCCESS) {
3914 			i = cfg_obj_asuint32(obj);
3915 			fstrm_iothr_options_set_input_queue_size(fopt, i);
3916 		}
3917 
3918 		obj = NULL;
3919 		result = named_config_get(
3920 			maps, "fstrm-set-output-notify-threshold", &obj);
3921 		if (result == ISC_R_SUCCESS) {
3922 			i = cfg_obj_asuint32(obj);
3923 			fstrm_iothr_options_set_queue_notify_threshold(fopt, i);
3924 		}
3925 
3926 		obj = NULL;
3927 		result = named_config_get(maps, "fstrm-set-output-queue-model",
3928 					  &obj);
3929 		if (result == ISC_R_SUCCESS) {
3930 			if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0) {
3931 				i = FSTRM_IOTHR_QUEUE_MODEL_SPSC;
3932 			} else {
3933 				i = FSTRM_IOTHR_QUEUE_MODEL_MPSC;
3934 			}
3935 			fstrm_iothr_options_set_queue_model(fopt, i);
3936 		}
3937 
3938 		obj = NULL;
3939 		result = named_config_get(maps, "fstrm-set-output-queue-size",
3940 					  &obj);
3941 		if (result == ISC_R_SUCCESS) {
3942 			i = cfg_obj_asuint32(obj);
3943 			fstrm_iothr_options_set_output_queue_size(fopt, i);
3944 		}
3945 
3946 		obj = NULL;
3947 		result = named_config_get(maps, "fstrm-set-reopen-interval",
3948 					  &obj);
3949 		if (result == ISC_R_SUCCESS) {
3950 			i = cfg_obj_asduration(obj);
3951 			fstrm_iothr_options_set_reopen_interval(fopt, i);
3952 		}
3953 
3954 		CHECKM(dns_dt_create(named_g_mctx, dmode, dpath, &fopt,
3955 				     named_g_mainloop, &named_g_server->dtenv),
3956 		       "unable to create dnstap environment");
3957 
3958 		CHECKM(dns_dt_setupfile(named_g_server->dtenv, max_size, rolls,
3959 					suffix),
3960 		       "unable to set up dnstap logfile");
3961 	}
3962 
3963 	if (named_g_server->dtenv == NULL) {
3964 		return ISC_R_SUCCESS;
3965 	}
3966 
3967 	obj = NULL;
3968 	result = named_config_get(maps, "dnstap-version", &obj);
3969 	if (result != ISC_R_SUCCESS) {
3970 		/* not specified; use the product and version */
3971 		dns_dt_setversion(named_g_server->dtenv, PACKAGE_STRING);
3972 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3973 		/* Quoted string */
3974 		dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj));
3975 	}
3976 
3977 	obj = NULL;
3978 	result = named_config_get(maps, "dnstap-identity", &obj);
3979 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
3980 		/* "hostname" is interpreted as boolean true */
3981 		char buf[256];
3982 		if (gethostname(buf, sizeof(buf)) == 0) {
3983 			dns_dt_setidentity(named_g_server->dtenv, buf);
3984 		}
3985 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3986 		/* Quoted string */
3987 		dns_dt_setidentity(named_g_server->dtenv,
3988 				   cfg_obj_asstring(obj));
3989 	}
3990 
3991 	dns_dt_attach(named_g_server->dtenv, &view->dtenv);
3992 	view->dttypes = dttypes;
3993 
3994 	result = ISC_R_SUCCESS;
3995 
3996 cleanup:
3997 	if (fopt != NULL) {
3998 		fstrm_iothr_options_destroy(&fopt);
3999 	}
4000 
4001 	return result;
4002 }
4003 #endif /* HAVE_DNSTAP */
4004 
4005 static isc_result_t
4006 create_mapped_acl(void) {
4007 	isc_result_t result;
4008 	dns_acl_t *acl = NULL;
4009 	struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT;
4010 	isc_netaddr_t addr;
4011 
4012 	isc_netaddr_fromin6(&addr, &in6);
4013 
4014 	dns_acl_create(named_g_mctx, 1, &acl);
4015 
4016 	result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
4017 	if (result == ISC_R_SUCCESS) {
4018 		dns_acl_attach(acl, &named_g_mapped);
4019 	}
4020 	dns_acl_detach(&acl);
4021 	return result;
4022 }
4023 
4024 /*%
4025  * A callback for the cfg_pluginlist_foreach() call in configure_view() below.
4026  * If registering any plugin fails, registering subsequent ones is not
4027  * attempted.
4028  */
4029 static isc_result_t
4030 register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
4031 		    const char *plugin_path, const char *parameters,
4032 		    void *callback_data) {
4033 	dns_view_t *view = callback_data;
4034 	char full_path[PATH_MAX];
4035 	isc_result_t result;
4036 
4037 	result = ns_plugin_expandpath(plugin_path, full_path,
4038 				      sizeof(full_path));
4039 	if (result != ISC_R_SUCCESS) {
4040 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4041 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4042 			      "%s: plugin configuration failed: "
4043 			      "unable to get full plugin path: %s",
4044 			      plugin_path, isc_result_totext(result));
4045 		return result;
4046 	}
4047 
4048 	result = ns_plugin_register(full_path, parameters, config,
4049 				    cfg_obj_file(obj), cfg_obj_line(obj),
4050 				    named_g_mctx, named_g_lctx,
4051 				    named_g_aclconfctx, view);
4052 	if (result != ISC_R_SUCCESS) {
4053 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4054 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4055 			      "%s: plugin configuration failed: %s", full_path,
4056 			      isc_result_totext(result));
4057 	}
4058 
4059 	return result;
4060 }
4061 
4062 /*
4063  * Determine if a minimal-sized cache can be used for a given view, according
4064  * to 'maps' (implicit defaults, global options, view options) and 'optionmaps'
4065  * (global options, view options).  This is only allowed for views which have
4066  * recursion disabled and do not have "max-cache-size" set explicitly.  Using
4067  * minimal-sized caches prevents a situation in which all explicitly configured
4068  * and built-in views inherit the default "max-cache-size 90%;" setting, which
4069  * could lead to memory exhaustion with multiple views configured.
4070  */
4071 static bool
4072 minimal_cache_allowed(const cfg_obj_t *maps[4],
4073 		      const cfg_obj_t *optionmaps[3]) {
4074 	const cfg_obj_t *obj;
4075 
4076 	/*
4077 	 * Do not use a minimal-sized cache for a view with recursion enabled.
4078 	 */
4079 	obj = NULL;
4080 	(void)named_config_get(maps, "recursion", &obj);
4081 	INSIST(obj != NULL);
4082 	if (cfg_obj_asboolean(obj)) {
4083 		return false;
4084 	}
4085 
4086 	/*
4087 	 * Do not use a minimal-sized cache if a specific size was requested.
4088 	 */
4089 	obj = NULL;
4090 	(void)named_config_get(optionmaps, "max-cache-size", &obj);
4091 	if (obj != NULL) {
4092 		return false;
4093 	}
4094 
4095 	return true;
4096 }
4097 
4098 static const char *const response_synonyms[] = { "response", NULL };
4099 
4100 /*
4101  * Configure 'view' according to 'vconfig', taking defaults from
4102  * 'config' where values are missing in 'vconfig'.
4103  *
4104  * When configuring the default view, 'vconfig' will be NULL and the
4105  * global defaults in 'config' used exclusively.
4106  */
4107 static isc_result_t
4108 configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
4109 	       cfg_obj_t *vconfig, named_cachelist_t *cachelist,
4110 	       dns_kasplist_t *kasplist, dns_keystorelist_t *keystores,
4111 	       const cfg_obj_t *bindkeys, isc_mem_t *mctx,
4112 	       cfg_aclconfctx_t *actx, bool need_hints) {
4113 	const cfg_obj_t *maps[4];
4114 	const cfg_obj_t *cfgmaps[3];
4115 	const cfg_obj_t *optionmaps[3];
4116 	const cfg_obj_t *options = NULL;
4117 	const cfg_obj_t *voptions = NULL;
4118 	const cfg_obj_t *forwardtype;
4119 	const cfg_obj_t *forwarders;
4120 	const cfg_obj_t *alternates;
4121 	const cfg_obj_t *zonelist;
4122 	const cfg_obj_t *dlzlist;
4123 	const cfg_obj_t *dlz;
4124 	const cfg_obj_t *prefetch_trigger;
4125 	const cfg_obj_t *prefetch_eligible;
4126 	unsigned int dlzargc;
4127 	char **dlzargv;
4128 	const cfg_obj_t *dyndb_list, *plugin_list;
4129 	const cfg_obj_t *disabled;
4130 	const cfg_obj_t *obj, *obj2;
4131 	const cfg_listelt_t *element = NULL;
4132 	const cfg_listelt_t *zone_element_latest = NULL;
4133 	in_port_t port;
4134 	dns_cache_t *cache = NULL;
4135 	isc_result_t result;
4136 	size_t max_cache_size;
4137 	uint32_t max_cache_size_percent = 0;
4138 	size_t max_adb_size;
4139 	uint32_t lame_ttl, fail_ttl;
4140 	uint32_t max_stale_ttl = 0;
4141 	uint32_t stale_refresh_time = 0;
4142 	dns_tsigkeyring_t *ring = NULL;
4143 	dns_transport_list_t *transports = NULL;
4144 	dns_view_t *pview = NULL; /* Production view */
4145 	dns_dispatch_t *dispatch4 = NULL;
4146 	dns_dispatch_t *dispatch6 = NULL;
4147 	bool rpz_configured = false;
4148 	bool catz_configured = false;
4149 	bool shared_cache = false;
4150 	int i = 0, j = 0, k = 0;
4151 	const char *str;
4152 	const char *cachename = NULL;
4153 	dns_order_t *order = NULL;
4154 	uint32_t udpsize;
4155 	uint32_t maxbits;
4156 	unsigned int resopts = 0;
4157 	dns_zone_t *zone = NULL;
4158 	uint32_t max_clients_per_query;
4159 	bool empty_zones_enable;
4160 	const cfg_obj_t *disablelist = NULL;
4161 	isc_stats_t *resstats = NULL;
4162 	dns_stats_t *resquerystats = NULL;
4163 	bool auto_root = false;
4164 	named_cache_t *nsc;
4165 	bool zero_no_soattl;
4166 	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
4167 	unsigned int query_timeout;
4168 	bool old_rpz_ok = false;
4169 	dns_dyndbctx_t *dctx = NULL;
4170 	dns_ntatable_t *ntatable = NULL;
4171 	const char *qminmode = NULL;
4172 	dns_adb_t *adb = NULL;
4173 
4174 	REQUIRE(DNS_VIEW_VALID(view));
4175 
4176 	if (config != NULL) {
4177 		(void)cfg_map_get(config, "options", &options);
4178 	}
4179 
4180 	/*
4181 	 * maps: view options, options, defaults
4182 	 * cfgmaps: view options, config
4183 	 * optionmaps: view options, options
4184 	 */
4185 	if (vconfig != NULL) {
4186 		voptions = cfg_tuple_get(vconfig, "options");
4187 		maps[i++] = voptions;
4188 		optionmaps[j++] = voptions;
4189 		cfgmaps[k++] = voptions;
4190 	}
4191 	if (options != NULL) {
4192 		maps[i++] = options;
4193 		optionmaps[j++] = options;
4194 	}
4195 
4196 	maps[i++] = named_g_defaults;
4197 	maps[i] = NULL;
4198 	optionmaps[j] = NULL;
4199 	if (config != NULL) {
4200 		cfgmaps[k++] = config;
4201 	}
4202 	cfgmaps[k] = NULL;
4203 
4204 	/*
4205 	 * Set the view's port number for outgoing queries.
4206 	 */
4207 	CHECKM(named_config_getport(config, "port", &port), "port");
4208 	dns_view_setdstport(view, port);
4209 
4210 	/*
4211 	 * Make the list of response policy zone names for a view that
4212 	 * is used for real lookups and so cares about hints.
4213 	 */
4214 	obj = NULL;
4215 	if (view->rdclass == dns_rdataclass_in && need_hints &&
4216 	    named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS)
4217 	{
4218 		CHECK(configure_rpz(view, NULL, maps, obj, &old_rpz_ok));
4219 		rpz_configured = true;
4220 	}
4221 
4222 	obj = NULL;
4223 	if (view->rdclass != dns_rdataclass_in && need_hints &&
4224 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
4225 	{
4226 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4227 			    "'catalog-zones' option is only supported "
4228 			    "for views with class IN");
4229 	}
4230 
4231 	obj = NULL;
4232 	if (view->rdclass == dns_rdataclass_in && need_hints &&
4233 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
4234 	{
4235 		CHECK(configure_catz(view, NULL, config, obj));
4236 		catz_configured = true;
4237 	}
4238 
4239 	/*
4240 	 * Configure the zones.
4241 	 */
4242 	zonelist = NULL;
4243 	if (voptions != NULL) {
4244 		(void)cfg_map_get(voptions, "zone", &zonelist);
4245 	} else {
4246 		(void)cfg_map_get(config, "zone", &zonelist);
4247 	}
4248 
4249 	/*
4250 	 * Load zone configuration
4251 	 */
4252 	for (element = cfg_list_first(zonelist); element != NULL;
4253 	     element = cfg_list_next(element))
4254 	{
4255 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
4256 		CHECK(configure_zone(config, zconfig, vconfig, view, viewlist,
4257 				     kasplist, keystores, actx, false,
4258 				     old_rpz_ok, false, false));
4259 		zone_element_latest = element;
4260 	}
4261 
4262 	/*
4263 	 * Check that a primary or secondary zone was found for each
4264 	 * zone named in the response policy statement, unless we are
4265 	 * using RPZ service interface.
4266 	 */
4267 	if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
4268 		dns_rpz_num_t n;
4269 
4270 		for (n = 0; n < view->rpzs->p.num_zones; ++n) {
4271 			if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
4272 				char namebuf[DNS_NAME_FORMATSIZE];
4273 
4274 				dns_name_format(&view->rpzs->zones[n]->origin,
4275 						namebuf, sizeof(namebuf));
4276 				isc_log_write(named_g_lctx,
4277 					      NAMED_LOGCATEGORY_GENERAL,
4278 					      NAMED_LOGMODULE_SERVER,
4279 					      DNS_RPZ_ERROR_LEVEL,
4280 					      "rpz '%s' is not a primary or a "
4281 					      "secondary zone",
4282 					      namebuf);
4283 				result = ISC_R_NOTFOUND;
4284 				goto cleanup;
4285 			}
4286 		}
4287 	}
4288 
4289 	/*
4290 	 * If we're allowing added zones, then load zone configuration
4291 	 * from the newzone file for zones that were added during previous
4292 	 * runs.
4293 	 */
4294 	CHECK(configure_newzones(view, config, vconfig, actx));
4295 
4296 	/*
4297 	 * Create Dynamically Loadable Zone driver.
4298 	 */
4299 	dlzlist = NULL;
4300 	if (voptions != NULL) {
4301 		(void)cfg_map_get(voptions, "dlz", &dlzlist);
4302 	} else {
4303 		(void)cfg_map_get(config, "dlz", &dlzlist);
4304 	}
4305 
4306 	for (element = cfg_list_first(dlzlist); element != NULL;
4307 	     element = cfg_list_next(element))
4308 	{
4309 		dlz = cfg_listelt_value(element);
4310 
4311 		obj = NULL;
4312 		(void)cfg_map_get(dlz, "database", &obj);
4313 		if (obj != NULL) {
4314 			dns_dlzdb_t *dlzdb = NULL;
4315 			const cfg_obj_t *name, *search = NULL;
4316 			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
4317 
4318 			if (s == NULL) {
4319 				result = ISC_R_NOMEMORY;
4320 				goto cleanup;
4321 			}
4322 
4323 			result = isc_commandline_strtoargv(mctx, s, &dlzargc,
4324 							   &dlzargv, 0);
4325 			if (result != ISC_R_SUCCESS) {
4326 				isc_mem_free(mctx, s);
4327 				goto cleanup;
4328 			}
4329 
4330 			name = cfg_map_getname(dlz);
4331 			result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
4332 					       dlzargv[0], dlzargc, dlzargv,
4333 					       &dlzdb);
4334 			isc_mem_free(mctx, s);
4335 			isc_mem_cput(mctx, dlzargv, dlzargc, sizeof(*dlzargv));
4336 			if (result != ISC_R_SUCCESS) {
4337 				goto cleanup;
4338 			}
4339 
4340 			/*
4341 			 * If the DLZ backend supports configuration,
4342 			 * and is searchable, then call its configure
4343 			 * method now.  If not searchable, we'll take
4344 			 * care of it when we process the zone statement.
4345 			 */
4346 			(void)cfg_map_get(dlz, "search", &search);
4347 			if (search == NULL || cfg_obj_asboolean(search)) {
4348 				dlzdb->search = true;
4349 				result = dns_dlzconfigure(
4350 					view, dlzdb, dlzconfigure_callback);
4351 				if (result != ISC_R_SUCCESS) {
4352 					goto cleanup;
4353 				}
4354 				ISC_LIST_APPEND(view->dlz_searched, dlzdb,
4355 						link);
4356 			} else {
4357 				dlzdb->search = false;
4358 				ISC_LIST_APPEND(view->dlz_unsearched, dlzdb,
4359 						link);
4360 			}
4361 		}
4362 	}
4363 
4364 	/*
4365 	 * Obtain configuration parameters that affect the decision of whether
4366 	 * we can reuse/share an existing cache.
4367 	 */
4368 	obj = NULL;
4369 	result = named_config_get(maps, "max-cache-size", &obj);
4370 	INSIST(result == ISC_R_SUCCESS);
4371 	/*
4372 	 * If "-T maxcachesize=..." is in effect, it overrides any other
4373 	 * "max-cache-size" setting found in configuration, either implicit or
4374 	 * explicit.  For simplicity, the value passed to that command line
4375 	 * option is always treated as the number of bytes to set
4376 	 * "max-cache-size" to.
4377 	 */
4378 	if (named_g_maxcachesize != 0) {
4379 		max_cache_size = named_g_maxcachesize;
4380 	} else if (minimal_cache_allowed(maps, optionmaps)) {
4381 		/*
4382 		 * dns_cache_setcachesize() will adjust this to the smallest
4383 		 * allowed value.
4384 		 */
4385 		max_cache_size = 1;
4386 	} else if (cfg_obj_isstring(obj)) {
4387 		str = cfg_obj_asstring(obj);
4388 		INSIST(strcasecmp(str, "unlimited") == 0);
4389 		max_cache_size = 0;
4390 	} else if (cfg_obj_ispercentage(obj)) {
4391 		max_cache_size = SIZE_AS_PERCENT;
4392 		max_cache_size_percent = cfg_obj_aspercentage(obj);
4393 	} else {
4394 		uint64_t value = cfg_obj_asuint64(obj);
4395 		if (value > SIZE_MAX) {
4396 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4397 				    "'max-cache-size "
4398 				    "%" PRIu64 "' "
4399 				    "is too large for this "
4400 				    "system; reducing to %lu",
4401 				    value, (unsigned long)SIZE_MAX);
4402 			value = SIZE_MAX;
4403 		}
4404 		max_cache_size = (size_t)value;
4405 	}
4406 
4407 	if (max_cache_size == SIZE_AS_PERCENT) {
4408 		uint64_t totalphys = isc_meminfo_totalphys();
4409 
4410 		max_cache_size =
4411 			(size_t)(totalphys * max_cache_size_percent / 100);
4412 		if (totalphys == 0) {
4413 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4414 				    "Unable to determine amount of physical "
4415 				    "memory, setting 'max-cache-size' to "
4416 				    "unlimited");
4417 		} else {
4418 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
4419 				    "'max-cache-size %d%%' "
4420 				    "- setting to %" PRIu64 "MB "
4421 				    "(out of %" PRIu64 "MB)",
4422 				    max_cache_size_percent,
4423 				    (uint64_t)(max_cache_size / (1024 * 1024)),
4424 				    totalphys / (1024 * 1024));
4425 		}
4426 	}
4427 
4428 	/* Check-names. */
4429 	obj = NULL;
4430 	result = named_checknames_get(maps, response_synonyms, &obj);
4431 	INSIST(result == ISC_R_SUCCESS);
4432 
4433 	str = cfg_obj_asstring(obj);
4434 	if (strcasecmp(str, "fail") == 0) {
4435 		resopts |= DNS_RESOLVER_CHECKNAMES |
4436 			   DNS_RESOLVER_CHECKNAMESFAIL;
4437 		view->checknames = true;
4438 	} else if (strcasecmp(str, "warn") == 0) {
4439 		resopts |= DNS_RESOLVER_CHECKNAMES;
4440 		view->checknames = false;
4441 	} else if (strcasecmp(str, "ignore") == 0) {
4442 		view->checknames = false;
4443 	} else {
4444 		UNREACHABLE();
4445 	}
4446 
4447 	obj = NULL;
4448 	result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj);
4449 	INSIST(result == ISC_R_SUCCESS);
4450 	zero_no_soattl = cfg_obj_asboolean(obj);
4451 
4452 	obj = NULL;
4453 	result = named_config_get(maps, "resolver-use-dns64", &obj);
4454 	INSIST(result == ISC_R_SUCCESS);
4455 	view->usedns64 = cfg_obj_asboolean(obj);
4456 
4457 	obj = NULL;
4458 	result = named_config_get(maps, "dns64", &obj);
4459 	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
4460 	    strcmp(view->name, "_meta"))
4461 	{
4462 		isc_netaddr_t na, suffix, *sp;
4463 		unsigned int prefixlen;
4464 		const char *server, *contact;
4465 		const cfg_obj_t *myobj;
4466 
4467 		myobj = NULL;
4468 		result = named_config_get(maps, "dns64-server", &myobj);
4469 		if (result == ISC_R_SUCCESS) {
4470 			server = cfg_obj_asstring(myobj);
4471 		} else {
4472 			server = NULL;
4473 		}
4474 
4475 		myobj = NULL;
4476 		result = named_config_get(maps, "dns64-contact", &myobj);
4477 		if (result == ISC_R_SUCCESS) {
4478 			contact = cfg_obj_asstring(myobj);
4479 		} else {
4480 			contact = NULL;
4481 		}
4482 
4483 		for (element = cfg_list_first(obj); element != NULL;
4484 		     element = cfg_list_next(element))
4485 		{
4486 			const cfg_obj_t *map = cfg_listelt_value(element);
4487 			dns_dns64_t *dns64 = NULL;
4488 			unsigned int dns64options = 0;
4489 
4490 			cfg_obj_asnetprefix(cfg_map_getname(map), &na,
4491 					    &prefixlen);
4492 
4493 			obj = NULL;
4494 			(void)cfg_map_get(map, "suffix", &obj);
4495 			if (obj != NULL) {
4496 				sp = &suffix;
4497 				isc_netaddr_fromsockaddr(
4498 					sp, cfg_obj_assockaddr(obj));
4499 			} else {
4500 				sp = NULL;
4501 			}
4502 
4503 			clients = mapped = excluded = NULL;
4504 			obj = NULL;
4505 			(void)cfg_map_get(map, "clients", &obj);
4506 			if (obj != NULL) {
4507 				result = cfg_acl_fromconfig(obj, config,
4508 							    named_g_lctx, actx,
4509 							    mctx, 0, &clients);
4510 				if (result != ISC_R_SUCCESS) {
4511 					goto cleanup;
4512 				}
4513 			}
4514 			obj = NULL;
4515 			(void)cfg_map_get(map, "mapped", &obj);
4516 			if (obj != NULL) {
4517 				result = cfg_acl_fromconfig(obj, config,
4518 							    named_g_lctx, actx,
4519 							    mctx, 0, &mapped);
4520 				if (result != ISC_R_SUCCESS) {
4521 					goto cleanup;
4522 				}
4523 			}
4524 			obj = NULL;
4525 			(void)cfg_map_get(map, "exclude", &obj);
4526 			if (obj != NULL) {
4527 				result = cfg_acl_fromconfig(obj, config,
4528 							    named_g_lctx, actx,
4529 							    mctx, 0, &excluded);
4530 				if (result != ISC_R_SUCCESS) {
4531 					goto cleanup;
4532 				}
4533 			} else {
4534 				if (named_g_mapped == NULL) {
4535 					result = create_mapped_acl();
4536 					if (result != ISC_R_SUCCESS) {
4537 						goto cleanup;
4538 					}
4539 				}
4540 				dns_acl_attach(named_g_mapped, &excluded);
4541 			}
4542 
4543 			obj = NULL;
4544 			(void)cfg_map_get(map, "recursive-only", &obj);
4545 			if (obj != NULL && cfg_obj_asboolean(obj)) {
4546 				dns64options |= DNS_DNS64_RECURSIVE_ONLY;
4547 			}
4548 
4549 			obj = NULL;
4550 			(void)cfg_map_get(map, "break-dnssec", &obj);
4551 			if (obj != NULL && cfg_obj_asboolean(obj)) {
4552 				dns64options |= DNS_DNS64_BREAK_DNSSEC;
4553 			}
4554 
4555 			result = dns_dns64_create(mctx, &na, prefixlen, sp,
4556 						  clients, mapped, excluded,
4557 						  dns64options, &dns64);
4558 			if (result != ISC_R_SUCCESS) {
4559 				goto cleanup;
4560 			}
4561 			dns_dns64_append(&view->dns64, dns64);
4562 			view->dns64cnt++;
4563 			result = dns64_reverse(view, mctx, &na, prefixlen,
4564 					       server, contact);
4565 			if (result != ISC_R_SUCCESS) {
4566 				goto cleanup;
4567 			}
4568 			if (clients != NULL) {
4569 				dns_acl_detach(&clients);
4570 			}
4571 			if (mapped != NULL) {
4572 				dns_acl_detach(&mapped);
4573 			}
4574 			if (excluded != NULL) {
4575 				dns_acl_detach(&excluded);
4576 			}
4577 		}
4578 	}
4579 
4580 	obj = NULL;
4581 	result = named_config_get(maps, "dnssec-accept-expired", &obj);
4582 	INSIST(result == ISC_R_SUCCESS);
4583 	view->acceptexpired = cfg_obj_asboolean(obj);
4584 
4585 	obj = NULL;
4586 	/* 'optionmaps', not 'maps': don't check named_g_defaults yet */
4587 	(void)named_config_get(optionmaps, "dnssec-validation", &obj);
4588 	if (obj == NULL) {
4589 		/*
4590 		 * Default to VALIDATION_DEFAULT as set in config.c.
4591 		 */
4592 		(void)cfg_map_get(named_g_defaults, "dnssec-validation", &obj);
4593 		INSIST(obj != NULL);
4594 	}
4595 	if (obj != NULL) {
4596 		if (cfg_obj_isboolean(obj)) {
4597 			view->enablevalidation = cfg_obj_asboolean(obj);
4598 		} else {
4599 			/*
4600 			 * If dnssec-validation is set but not boolean,
4601 			 * then it must be "auto"
4602 			 */
4603 			view->enablevalidation = true;
4604 			auto_root = true;
4605 		}
4606 	}
4607 
4608 	obj = NULL;
4609 	result = named_config_get(maps, "max-cache-ttl", &obj);
4610 	INSIST(result == ISC_R_SUCCESS);
4611 	view->maxcachettl = cfg_obj_asduration(obj);
4612 
4613 	obj = NULL;
4614 	result = named_config_get(maps, "max-ncache-ttl", &obj);
4615 	INSIST(result == ISC_R_SUCCESS);
4616 	view->maxncachettl = cfg_obj_asduration(obj);
4617 
4618 	obj = NULL;
4619 	result = named_config_get(maps, "min-cache-ttl", &obj);
4620 	INSIST(result == ISC_R_SUCCESS);
4621 	view->mincachettl = cfg_obj_asduration(obj);
4622 
4623 	obj = NULL;
4624 	result = named_config_get(maps, "min-ncache-ttl", &obj);
4625 	INSIST(result == ISC_R_SUCCESS);
4626 	view->minncachettl = cfg_obj_asduration(obj);
4627 
4628 	obj = NULL;
4629 	result = named_config_get(maps, "synth-from-dnssec", &obj);
4630 	INSIST(result == ISC_R_SUCCESS);
4631 	view->synthfromdnssec = cfg_obj_asboolean(obj);
4632 
4633 	obj = NULL;
4634 	result = named_config_get(maps, "stale-cache-enable", &obj);
4635 	INSIST(result == ISC_R_SUCCESS);
4636 	if (cfg_obj_asboolean(obj)) {
4637 		obj = NULL;
4638 		result = named_config_get(maps, "max-stale-ttl", &obj);
4639 		INSIST(result == ISC_R_SUCCESS);
4640 		max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4641 	}
4642 	/*
4643 	 * If 'stale-cache-enable' is false, max_stale_ttl is set to 0,
4644 	 * meaning keeping stale RRsets in cache is disabled.
4645 	 */
4646 
4647 	obj = NULL;
4648 	result = named_config_get(maps, "stale-answer-enable", &obj);
4649 	INSIST(result == ISC_R_SUCCESS);
4650 	view->staleanswersenable = cfg_obj_asboolean(obj);
4651 
4652 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
4653 				   view->rdclass, &pview);
4654 	if (result == ISC_R_SUCCESS) {
4655 		view->staleanswersok = pview->staleanswersok;
4656 		dns_view_detach(&pview);
4657 	} else {
4658 		view->staleanswersok = dns_stale_answer_conf;
4659 	}
4660 
4661 	obj = NULL;
4662 	result = named_config_get(maps, "stale-answer-client-timeout", &obj);
4663 	INSIST(result == ISC_R_SUCCESS);
4664 	if (cfg_obj_isstring(obj)) {
4665 		/*
4666 		 * The only string values available for this option
4667 		 * are "disabled" and "off".
4668 		 * We use (uint32_t) -1 to represent disabled since
4669 		 * a value of zero means that stale data can be used
4670 		 * to promptly answer the query, while an attempt to
4671 		 * refresh the RRset will still be made in background.
4672 		 */
4673 		view->staleanswerclienttimeout = (uint32_t)-1;
4674 	} else {
4675 		view->staleanswerclienttimeout = cfg_obj_asuint32(obj);
4676 
4677 		/*
4678 		 * BIND 9 no longer supports non-zero values of
4679 		 * stale-answer-client-timeout.
4680 		 */
4681 		if (view->staleanswerclienttimeout != 0) {
4682 			view->staleanswerclienttimeout = 0;
4683 			isc_log_write(
4684 				named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4685 				NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
4686 				"BIND 9 no longer supports non-zero values of "
4687 				"stale-answer-client-timeout, adjusted to 0");
4688 		}
4689 	}
4690 
4691 	obj = NULL;
4692 	result = named_config_get(maps, "stale-refresh-time", &obj);
4693 	INSIST(result == ISC_R_SUCCESS);
4694 	stale_refresh_time = cfg_obj_asduration(obj);
4695 
4696 	/*
4697 	 * Configure the view's cache.
4698 	 *
4699 	 * First, check to see if there are any attach-cache options.  If yes,
4700 	 * attempt to lookup an existing cache at attach it to the view.  If
4701 	 * there is not one, then try to reuse an existing cache if possible;
4702 	 * otherwise create a new cache.
4703 	 *
4704 	 * Note that the ADB is not preserved or shared in either case.
4705 	 *
4706 	 * When a matching view is found, the associated statistics are also
4707 	 * retrieved and reused.
4708 	 *
4709 	 * XXX Determining when it is safe to reuse or share a cache is tricky.
4710 	 * When the view's configuration changes, the cached data may become
4711 	 * invalid because it reflects our old view of the world.  We check
4712 	 * some of the configuration parameters that could invalidate the cache
4713 	 * or otherwise make it unshareable, but there are other configuration
4714 	 * options that should be checked.  For example, if a view uses a
4715 	 * forwarder, changes in the forwarder configuration may invalidate
4716 	 * the cache.  At the moment, it's the administrator's responsibility to
4717 	 * ensure these configuration options don't invalidate reusing/sharing.
4718 	 */
4719 	obj = NULL;
4720 	result = named_config_get(maps, "attach-cache", &obj);
4721 	if (result == ISC_R_SUCCESS) {
4722 		cachename = cfg_obj_asstring(obj);
4723 	} else {
4724 		cachename = view->name;
4725 	}
4726 	cache = NULL;
4727 	nsc = cachelist_find(cachelist, cachename, view->rdclass);
4728 	if (nsc != NULL) {
4729 		if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
4730 				    max_cache_size, max_stale_ttl,
4731 				    stale_refresh_time))
4732 		{
4733 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4734 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4735 				      "views %s and %s can't share the cache "
4736 				      "due to configuration parameter mismatch",
4737 				      nsc->primaryview->name, view->name);
4738 			result = ISC_R_FAILURE;
4739 			goto cleanup;
4740 		}
4741 		dns_cache_attach(nsc->cache, &cache);
4742 		shared_cache = true;
4743 	} else {
4744 		if (strcmp(cachename, view->name) == 0) {
4745 			result = dns_viewlist_find(&named_g_server->viewlist,
4746 						   cachename, view->rdclass,
4747 						   &pview);
4748 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4749 			{
4750 				goto cleanup;
4751 			}
4752 			if (pview != NULL) {
4753 				if (!cache_reusable(pview, view,
4754 						    zero_no_soattl))
4755 				{
4756 					isc_log_write(named_g_lctx,
4757 						      NAMED_LOGCATEGORY_GENERAL,
4758 						      NAMED_LOGMODULE_SERVER,
4759 						      ISC_LOG_DEBUG(1),
4760 						      "cache cannot be reused "
4761 						      "for view %s due to "
4762 						      "configuration parameter "
4763 						      "mismatch",
4764 						      view->name);
4765 				} else {
4766 					INSIST(pview->cache != NULL);
4767 					isc_log_write(named_g_lctx,
4768 						      NAMED_LOGCATEGORY_GENERAL,
4769 						      NAMED_LOGMODULE_SERVER,
4770 						      ISC_LOG_DEBUG(3),
4771 						      "reusing existing cache");
4772 					dns_cache_attach(pview->cache, &cache);
4773 				}
4774 				dns_resolver_getstats(pview->resolver,
4775 						      &resstats);
4776 				dns_resolver_getquerystats(pview->resolver,
4777 							   &resquerystats);
4778 				dns_view_detach(&pview);
4779 			}
4780 		}
4781 		if (cache == NULL) {
4782 			/*
4783 			 * Create a cache with the desired name.  This normally
4784 			 * equals the view name, but may also be a forward
4785 			 * reference to a view that share the cache with this
4786 			 * view but is not yet configured.  If it is not the
4787 			 * view name but not a forward reference either, then it
4788 			 * is simply a named cache that is not shared.
4789 			 */
4790 			CHECK(dns_cache_create(named_g_loopmgr, view->rdclass,
4791 					       cachename, mctx, &cache));
4792 		}
4793 		nsc = isc_mem_get(mctx, sizeof(*nsc));
4794 		nsc->cache = NULL;
4795 		dns_cache_attach(cache, &nsc->cache);
4796 		nsc->primaryview = view;
4797 		nsc->needflush = false;
4798 		nsc->adbsizeadjusted = false;
4799 		nsc->rdclass = view->rdclass;
4800 		ISC_LINK_INIT(nsc, link);
4801 		ISC_LIST_APPEND(*cachelist, nsc, link);
4802 	}
4803 	dns_view_setcache(view, cache, shared_cache);
4804 
4805 	dns_cache_setcachesize(cache, max_cache_size);
4806 	dns_cache_setservestalettl(cache, max_stale_ttl);
4807 	dns_cache_setservestalerefresh(cache, stale_refresh_time);
4808 
4809 	dns_cache_detach(&cache);
4810 
4811 	obj = NULL;
4812 	result = named_config_get(maps, "stale-answer-ttl", &obj);
4813 	INSIST(result == ISC_R_SUCCESS);
4814 	view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4815 
4816 	/*
4817 	 * Resolver.
4818 	 */
4819 	CHECK(get_view_querysource_dispatch(
4820 		maps, AF_INET, &dispatch4,
4821 		(ISC_LIST_PREV(view, link) == NULL)));
4822 	CHECK(get_view_querysource_dispatch(
4823 		maps, AF_INET6, &dispatch6,
4824 		(ISC_LIST_PREV(view, link) == NULL)));
4825 	if (dispatch4 == NULL && dispatch6 == NULL) {
4826 		UNEXPECTED_ERROR("unable to obtain either an IPv4 or"
4827 				 " an IPv6 dispatch");
4828 		result = ISC_R_UNEXPECTED;
4829 		goto cleanup;
4830 	}
4831 
4832 	CHECK(dns_view_createresolver(view, named_g_netmgr, resopts,
4833 				      named_g_server->tlsctx_client_cache,
4834 				      dispatch4, dispatch6));
4835 
4836 	if (resstats == NULL) {
4837 		isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
4838 	}
4839 	dns_resolver_setstats(view->resolver, resstats);
4840 	if (resquerystats == NULL) {
4841 		dns_rdatatypestats_create(mctx, &resquerystats);
4842 	}
4843 	dns_resolver_setquerystats(view->resolver, resquerystats);
4844 
4845 	/*
4846 	 * Set the ADB cache size to 1/8th of the max-cache-size or
4847 	 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
4848 	 */
4849 	max_adb_size = 0;
4850 	if (max_cache_size != 0U) {
4851 		max_adb_size = max_cache_size / 8;
4852 		if (max_adb_size == 0U) {
4853 			max_adb_size = 1; /* Force minimum. */
4854 		}
4855 		if (view != nsc->primaryview &&
4856 		    max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE)
4857 		{
4858 			max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
4859 			if (!nsc->adbsizeadjusted) {
4860 				dns_view_getadb(nsc->primaryview, &adb);
4861 				if (adb != NULL) {
4862 					dns_adb_setadbsize(
4863 						adb,
4864 						MAX_ADB_SIZE_FOR_CACHESHARE);
4865 					nsc->adbsizeadjusted = true;
4866 					dns_adb_detach(&adb);
4867 				}
4868 			}
4869 		}
4870 	}
4871 	dns_view_getadb(view, &adb);
4872 	if (adb != NULL) {
4873 		dns_adb_setadbsize(adb, max_adb_size);
4874 		dns_adb_detach(&adb);
4875 	}
4876 
4877 	/*
4878 	 * Set up ADB quotas
4879 	 */
4880 	{
4881 		uint32_t fps, freq;
4882 		double low, high, discount;
4883 
4884 		obj = NULL;
4885 		result = named_config_get(maps, "fetches-per-server", &obj);
4886 		INSIST(result == ISC_R_SUCCESS);
4887 		obj2 = cfg_tuple_get(obj, "fetches");
4888 		fps = cfg_obj_asuint32(obj2);
4889 		obj2 = cfg_tuple_get(obj, "response");
4890 		if (!cfg_obj_isvoid(obj2)) {
4891 			const char *resp = cfg_obj_asstring(obj2);
4892 			isc_result_t r = DNS_R_SERVFAIL;
4893 
4894 			if (strcasecmp(resp, "drop") == 0) {
4895 				r = DNS_R_DROP;
4896 			} else if (strcasecmp(resp, "fail") == 0) {
4897 				r = DNS_R_SERVFAIL;
4898 			} else {
4899 				UNREACHABLE();
4900 			}
4901 
4902 			dns_resolver_setquotaresponse(view->resolver,
4903 						      dns_quotatype_server, r);
4904 		}
4905 
4906 		obj = NULL;
4907 		result = named_config_get(maps, "fetch-quota-params", &obj);
4908 		INSIST(result == ISC_R_SUCCESS);
4909 
4910 		obj2 = cfg_tuple_get(obj, "frequency");
4911 		freq = cfg_obj_asuint32(obj2);
4912 
4913 		obj2 = cfg_tuple_get(obj, "low");
4914 		low = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4915 
4916 		obj2 = cfg_tuple_get(obj, "high");
4917 		high = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4918 
4919 		obj2 = cfg_tuple_get(obj, "discount");
4920 		discount = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4921 
4922 		dns_view_getadb(view, &adb);
4923 		if (adb != NULL) {
4924 			dns_adb_setquota(adb, fps, freq, low, high, discount);
4925 			dns_adb_detach(&adb);
4926 		}
4927 	}
4928 
4929 	/*
4930 	 * Set resolver's lame-ttl.
4931 	 */
4932 	obj = NULL;
4933 	result = named_config_get(maps, "lame-ttl", &obj);
4934 	INSIST(result == ISC_R_SUCCESS);
4935 	lame_ttl = cfg_obj_asduration(obj);
4936 	if (lame_ttl > 0) {
4937 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4938 			    "disabling lame cache despite lame-ttl > 0 as it "
4939 			    "may cause performance issues");
4940 	}
4941 
4942 	/*
4943 	 * Set the resolver's query timeout.
4944 	 */
4945 	obj = NULL;
4946 	result = named_config_get(maps, "resolver-query-timeout", &obj);
4947 	INSIST(result == ISC_R_SUCCESS);
4948 	query_timeout = cfg_obj_asuint32(obj);
4949 	dns_resolver_settimeout(view->resolver, query_timeout);
4950 
4951 	/* Specify whether to use 0-TTL for negative response for SOA query */
4952 	dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
4953 
4954 	/*
4955 	 * Set the resolver's EDNS UDP size.
4956 	 */
4957 	obj = NULL;
4958 	result = named_config_get(maps, "edns-udp-size", &obj);
4959 	INSIST(result == ISC_R_SUCCESS);
4960 	udpsize = cfg_obj_asuint32(obj);
4961 	if (udpsize < 512) {
4962 		udpsize = 512;
4963 	}
4964 	if (udpsize > 4096) {
4965 		udpsize = 4096;
4966 	}
4967 	dns_view_setudpsize(view, (uint16_t)udpsize);
4968 
4969 	/*
4970 	 * Set the maximum UDP response size.
4971 	 */
4972 	obj = NULL;
4973 	result = named_config_get(maps, "max-udp-size", &obj);
4974 	INSIST(result == ISC_R_SUCCESS);
4975 	udpsize = cfg_obj_asuint32(obj);
4976 	if (udpsize < 512) {
4977 		udpsize = 512;
4978 	}
4979 	if (udpsize > 4096) {
4980 		udpsize = 4096;
4981 	}
4982 	view->maxudp = udpsize;
4983 
4984 	/*
4985 	 * Set the maximum UDP when a COOKIE is not provided.
4986 	 */
4987 	obj = NULL;
4988 	result = named_config_get(maps, "nocookie-udp-size", &obj);
4989 	INSIST(result == ISC_R_SUCCESS);
4990 	udpsize = cfg_obj_asuint32(obj);
4991 	if (udpsize < 128) {
4992 		udpsize = 128;
4993 	}
4994 	if (udpsize > view->maxudp) {
4995 		udpsize = view->maxudp;
4996 	}
4997 	view->nocookieudp = udpsize;
4998 
4999 	/*
5000 	 * Set the maximum rsa exponent bits.
5001 	 */
5002 	obj = NULL;
5003 	result = named_config_get(maps, "max-rsa-exponent-size", &obj);
5004 	INSIST(result == ISC_R_SUCCESS);
5005 	maxbits = cfg_obj_asuint32(obj);
5006 	if (maxbits != 0 && maxbits < 35) {
5007 		maxbits = 35;
5008 	}
5009 	if (maxbits > 4096) {
5010 		maxbits = 4096;
5011 	}
5012 	view->maxbits = maxbits;
5013 
5014 	/*
5015 	 * Set supported DNSSEC algorithms.
5016 	 */
5017 	disabled = NULL;
5018 	(void)named_config_get(maps, "disable-algorithms", &disabled);
5019 	if (disabled != NULL) {
5020 		for (element = cfg_list_first(disabled); element != NULL;
5021 		     element = cfg_list_next(element))
5022 		{
5023 			CHECK(disable_algorithms(cfg_listelt_value(element),
5024 						 view->resolver));
5025 		}
5026 	}
5027 
5028 	/*
5029 	 * Set supported DS digest types.
5030 	 */
5031 	disabled = NULL;
5032 	(void)named_config_get(maps, "disable-ds-digests", &disabled);
5033 	if (disabled != NULL) {
5034 		for (element = cfg_list_first(disabled); element != NULL;
5035 		     element = cfg_list_next(element))
5036 		{
5037 			CHECK(disable_ds_digests(cfg_listelt_value(element),
5038 						 view->resolver));
5039 		}
5040 	}
5041 
5042 	/*
5043 	 * A global or view "forwarders" option, if present,
5044 	 * creates an entry for "." in the forwarding table.
5045 	 */
5046 	forwardtype = NULL;
5047 	forwarders = NULL;
5048 	(void)named_config_get(maps, "forward", &forwardtype);
5049 	(void)named_config_get(maps, "forwarders", &forwarders);
5050 	if (forwarders != NULL) {
5051 		CHECK(configure_forward(config, view, dns_rootname, forwarders,
5052 					forwardtype));
5053 	}
5054 
5055 	/*
5056 	 * Dual Stack Servers.
5057 	 */
5058 	alternates = NULL;
5059 	(void)named_config_get(maps, "dual-stack-servers", &alternates);
5060 	if (alternates != NULL) {
5061 		CHECK(configure_alternates(config, view, alternates));
5062 	}
5063 
5064 	/*
5065 	 * We have default hints for class IN if we need them.
5066 	 */
5067 	if (view->rdclass == dns_rdataclass_in && view->hints == NULL) {
5068 		dns_view_sethints(view, named_g_server->in_roothints);
5069 	}
5070 
5071 	/*
5072 	 * If we still have no hints, this is a non-IN view with no
5073 	 * "hints zone" configured.  Issue a warning, except if this
5074 	 * is a root server.  Root servers never need to consult
5075 	 * their hints, so it's no point requiring users to configure
5076 	 * them.
5077 	 */
5078 	if (view->hints == NULL) {
5079 		dns_zone_t *rootzone = NULL;
5080 		(void)dns_view_findzone(view, dns_rootname, DNS_ZTFIND_EXACT,
5081 					&rootzone);
5082 		if (rootzone != NULL) {
5083 			dns_zone_detach(&rootzone);
5084 			need_hints = false;
5085 		}
5086 		if (need_hints) {
5087 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
5088 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
5089 				      "no root hints for view '%s'",
5090 				      view->name);
5091 		}
5092 	}
5093 
5094 	/*
5095 	 * Configure the view's transports (DoT/DoH)
5096 	 */
5097 	CHECK(named_transports_fromconfig(config, vconfig, view->mctx,
5098 					  &transports));
5099 	dns_view_settransports(view, transports);
5100 	dns_transport_list_detach(&transports);
5101 
5102 	/*
5103 	 * Configure the view's TSIG keys.
5104 	 */
5105 	CHECK(named_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
5106 	if (named_g_server->sessionkey != NULL) {
5107 		dns_tsigkey_t *tsigkey = NULL;
5108 		result = dns_tsigkey_createfromkey(
5109 			named_g_server->session_keyname,
5110 			named_g_server->session_keyalg,
5111 			named_g_server->sessionkey, false, false, NULL, 0, 0,
5112 			mctx, &tsigkey);
5113 		if (result == ISC_R_SUCCESS) {
5114 			result = dns_tsigkeyring_add(ring, tsigkey);
5115 			dns_tsigkey_detach(&tsigkey);
5116 		}
5117 		CHECK(result);
5118 	}
5119 	dns_view_setkeyring(view, ring);
5120 	dns_tsigkeyring_detach(&ring);
5121 
5122 	/*
5123 	 * See if we can re-use a dynamic key ring.
5124 	 */
5125 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
5126 				   view->rdclass, &pview);
5127 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
5128 		goto cleanup;
5129 	}
5130 	if (pview != NULL) {
5131 		dns_view_getdynamickeyring(pview, &ring);
5132 		if (ring != NULL) {
5133 			dns_view_setdynamickeyring(view, ring);
5134 		}
5135 		dns_tsigkeyring_detach(&ring);
5136 		dns_view_detach(&pview);
5137 	} else {
5138 		dns_view_restorekeyring(view);
5139 	}
5140 
5141 	/*
5142 	 * Configure the view's peer list.
5143 	 */
5144 	{
5145 		const cfg_obj_t *peers = NULL;
5146 		dns_peerlist_t *newpeers = NULL;
5147 
5148 		(void)named_config_get(cfgmaps, "server", &peers);
5149 		CHECK(dns_peerlist_new(mctx, &newpeers));
5150 		for (element = cfg_list_first(peers); element != NULL;
5151 		     element = cfg_list_next(element))
5152 		{
5153 			const cfg_obj_t *cpeer = cfg_listelt_value(element);
5154 			dns_peer_t *peer;
5155 
5156 			CHECK(configure_peer(cpeer, mctx, &peer));
5157 			dns_peerlist_addpeer(newpeers, peer);
5158 			dns_peer_detach(&peer);
5159 		}
5160 		dns_peerlist_detach(&view->peers);
5161 		view->peers = newpeers; /* Transfer ownership. */
5162 	}
5163 
5164 	/*
5165 	 *	Configure the views rrset-order.
5166 	 */
5167 	{
5168 		const cfg_obj_t *rrsetorder = NULL;
5169 
5170 		(void)named_config_get(maps, "rrset-order", &rrsetorder);
5171 		CHECK(dns_order_create(mctx, &order));
5172 		for (element = cfg_list_first(rrsetorder); element != NULL;
5173 		     element = cfg_list_next(element))
5174 		{
5175 			const cfg_obj_t *ent = cfg_listelt_value(element);
5176 
5177 			CHECK(configure_order(order, ent));
5178 		}
5179 		if (view->order != NULL) {
5180 			dns_order_detach(&view->order);
5181 		}
5182 		dns_order_attach(order, &view->order);
5183 		dns_order_detach(&order);
5184 	}
5185 	/*
5186 	 * Copy the aclenv object.
5187 	 */
5188 	dns_aclenv_copy(view->aclenv, ns_interfacemgr_getaclenv(
5189 					      named_g_server->interfacemgr));
5190 
5191 	/*
5192 	 * Configure the "match-clients" and "match-destinations" ACL.
5193 	 * (These are only meaningful at the view level, but 'config'
5194 	 * must be passed so that named ACLs defined at the global level
5195 	 * can be retrieved.)
5196 	 */
5197 	CHECK(configure_view_acl(vconfig, config, NULL, "match-clients", NULL,
5198 				 actx, named_g_mctx, &view->matchclients));
5199 	CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations",
5200 				 NULL, actx, named_g_mctx,
5201 				 &view->matchdestinations));
5202 
5203 	/*
5204 	 * Configure the "match-recursive-only" option.
5205 	 */
5206 	obj = NULL;
5207 	(void)named_config_get(maps, "match-recursive-only", &obj);
5208 	if (obj != NULL && cfg_obj_asboolean(obj)) {
5209 		view->matchrecursiveonly = true;
5210 	} else {
5211 		view->matchrecursiveonly = false;
5212 	}
5213 
5214 	/*
5215 	 * Configure other configurable data.
5216 	 */
5217 	obj = NULL;
5218 	result = named_config_get(maps, "recursion", &obj);
5219 	INSIST(result == ISC_R_SUCCESS);
5220 	view->recursion = cfg_obj_asboolean(obj);
5221 
5222 	obj = NULL;
5223 	result = named_config_get(maps, "qname-minimization", &obj);
5224 	INSIST(result == ISC_R_SUCCESS);
5225 	qminmode = cfg_obj_asstring(obj);
5226 	INSIST(qminmode != NULL);
5227 	if (!strcmp(qminmode, "strict")) {
5228 		view->qminimization = true;
5229 		view->qmin_strict = true;
5230 	} else if (!strcmp(qminmode, "relaxed")) {
5231 		view->qminimization = true;
5232 		view->qmin_strict = false;
5233 	} else { /* "disabled" or "off" */
5234 		view->qminimization = false;
5235 		view->qmin_strict = false;
5236 	}
5237 
5238 	obj = NULL;
5239 	result = named_config_get(maps, "auth-nxdomain", &obj);
5240 	INSIST(result == ISC_R_SUCCESS);
5241 	view->auth_nxdomain = cfg_obj_asboolean(obj);
5242 
5243 	obj = NULL;
5244 	result = named_config_get(maps, "minimal-any", &obj);
5245 	INSIST(result == ISC_R_SUCCESS);
5246 	view->minimal_any = cfg_obj_asboolean(obj);
5247 
5248 	obj = NULL;
5249 	result = named_config_get(maps, "minimal-responses", &obj);
5250 	INSIST(result == ISC_R_SUCCESS);
5251 	if (cfg_obj_isboolean(obj)) {
5252 		if (cfg_obj_asboolean(obj)) {
5253 			view->minimalresponses = dns_minimal_yes;
5254 		} else {
5255 			view->minimalresponses = dns_minimal_no;
5256 		}
5257 	} else {
5258 		str = cfg_obj_asstring(obj);
5259 		if (strcasecmp(str, "no-auth") == 0) {
5260 			view->minimalresponses = dns_minimal_noauth;
5261 		} else if (strcasecmp(str, "no-auth-recursive") == 0) {
5262 			view->minimalresponses = dns_minimal_noauthrec;
5263 		} else {
5264 			UNREACHABLE();
5265 		}
5266 	}
5267 
5268 	obj = NULL;
5269 	result = named_config_get(maps, "transfer-format", &obj);
5270 	INSIST(result == ISC_R_SUCCESS);
5271 	str = cfg_obj_asstring(obj);
5272 	if (strcasecmp(str, "many-answers") == 0) {
5273 		view->transfer_format = dns_many_answers;
5274 	} else if (strcasecmp(str, "one-answer") == 0) {
5275 		view->transfer_format = dns_one_answer;
5276 	} else {
5277 		UNREACHABLE();
5278 	}
5279 
5280 	obj = NULL;
5281 	result = named_config_get(maps, "trust-anchor-telemetry", &obj);
5282 	INSIST(result == ISC_R_SUCCESS);
5283 	view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
5284 
5285 	obj = NULL;
5286 	result = named_config_get(maps, "root-key-sentinel", &obj);
5287 	INSIST(result == ISC_R_SUCCESS);
5288 	view->root_key_sentinel = cfg_obj_asboolean(obj);
5289 
5290 	/*
5291 	 * Set the "allow-query", "allow-query-cache", "allow-recursion",
5292 	 * "allow-recursion-on" and "allow-query-cache-on" ACLs if
5293 	 * configured in named.conf, but NOT from the global defaults.
5294 	 * This is done by leaving the third argument to configure_view_acl()
5295 	 * NULL.
5296 	 *
5297 	 * We ignore the global defaults here because these ACLs
5298 	 * can inherit from each other.  If any are still unset after
5299 	 * applying the inheritance rules, we'll look up the defaults at
5300 	 * that time.
5301 	 */
5302 
5303 	/* named.conf only */
5304 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query", NULL,
5305 				 actx, named_g_mctx, &view->queryacl));
5306 
5307 	/* named.conf only */
5308 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache",
5309 				 NULL, actx, named_g_mctx, &view->cacheacl));
5310 	/* named.conf only */
5311 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
5312 				 NULL, actx, named_g_mctx, &view->cacheonacl));
5313 
5314 	CHECK(configure_view_acl(vconfig, config, named_g_config, "allow-proxy",
5315 				 NULL, actx, named_g_mctx, &view->proxyacl));
5316 
5317 	CHECK(configure_view_acl(vconfig, config, named_g_config,
5318 				 "allow-proxy-on", NULL, actx, named_g_mctx,
5319 				 &view->proxyonacl));
5320 
5321 	if (strcmp(view->name, "_bind") != 0 &&
5322 	    view->rdclass != dns_rdataclass_chaos)
5323 	{
5324 		/* named.conf only */
5325 		CHECK(configure_view_acl(vconfig, config, NULL,
5326 					 "allow-recursion", NULL, actx,
5327 					 named_g_mctx, &view->recursionacl));
5328 		/* named.conf only */
5329 		CHECK(configure_view_acl(vconfig, config, NULL,
5330 					 "allow-recursion-on", NULL, actx,
5331 					 named_g_mctx, &view->recursiononacl));
5332 	}
5333 
5334 	if (view->recursion) {
5335 		/*
5336 		 * "allow-query-cache" inherits from "allow-recursion" if set,
5337 		 * otherwise from "allow-query" if set.
5338 		 */
5339 		if (view->cacheacl == NULL) {
5340 			if (view->recursionacl != NULL) {
5341 				dns_acl_attach(view->recursionacl,
5342 					       &view->cacheacl);
5343 			} else if (view->queryacl != NULL) {
5344 				dns_acl_attach(view->queryacl, &view->cacheacl);
5345 			}
5346 		}
5347 
5348 		/*
5349 		 * "allow-recursion" inherits from "allow-query-cache" if set,
5350 		 * otherwise from "allow-query" if set.
5351 		 */
5352 		if (view->recursionacl == NULL) {
5353 			if (view->cacheacl != NULL) {
5354 				dns_acl_attach(view->cacheacl,
5355 					       &view->recursionacl);
5356 			} else if (view->queryacl != NULL) {
5357 				dns_acl_attach(view->queryacl,
5358 					       &view->recursionacl);
5359 			}
5360 		}
5361 
5362 		/*
5363 		 * "allow-query-cache-on" inherits from "allow-recursion-on"
5364 		 * if set.
5365 		 */
5366 		if (view->cacheonacl == NULL) {
5367 			if (view->recursiononacl != NULL) {
5368 				dns_acl_attach(view->recursiononacl,
5369 					       &view->cacheonacl);
5370 			}
5371 		}
5372 
5373 		/*
5374 		 * "allow-recursion-on" inherits from "allow-query-cache-on"
5375 		 * if set.
5376 		 */
5377 		if (view->recursiononacl == NULL) {
5378 			if (view->cacheonacl != NULL) {
5379 				dns_acl_attach(view->cacheonacl,
5380 					       &view->recursiononacl);
5381 			}
5382 		}
5383 
5384 		/*
5385 		 * If any are still unset at this point, we now get default
5386 		 * values for from the global config.
5387 		 */
5388 
5389 		if (view->recursionacl == NULL) {
5390 			/* global default only */
5391 			CHECK(configure_view_acl(
5392 				NULL, NULL, named_g_config, "allow-recursion",
5393 				NULL, actx, named_g_mctx, &view->recursionacl));
5394 		}
5395 		if (view->recursiononacl == NULL) {
5396 			/* global default only */
5397 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5398 						 "allow-recursion-on", NULL,
5399 						 actx, named_g_mctx,
5400 						 &view->recursiononacl));
5401 		}
5402 		if (view->cacheacl == NULL) {
5403 			/* global default only */
5404 			CHECK(configure_view_acl(
5405 				NULL, NULL, named_g_config, "allow-query-cache",
5406 				NULL, actx, named_g_mctx, &view->cacheacl));
5407 		}
5408 		if (view->cacheonacl == NULL) {
5409 			/* global default only */
5410 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5411 						 "allow-query-cache-on", NULL,
5412 						 actx, named_g_mctx,
5413 						 &view->cacheonacl));
5414 		}
5415 	} else {
5416 		/*
5417 		 * We're not recursive; if the query-cache ACLs haven't
5418 		 * been set at the options/view level, set them to none.
5419 		 */
5420 		if (view->cacheacl == NULL) {
5421 			CHECK(dns_acl_none(mctx, &view->cacheacl));
5422 		}
5423 		if (view->cacheonacl == NULL) {
5424 			CHECK(dns_acl_none(mctx, &view->cacheonacl));
5425 		}
5426 	}
5427 
5428 	/*
5429 	 * Finished setting recursion and query-cache ACLs, so now we
5430 	 * can get the allow-query default if it wasn't set in named.conf
5431 	 */
5432 	if (view->queryacl == NULL) {
5433 		/* global default only */
5434 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5435 					 "allow-query", NULL, actx,
5436 					 named_g_mctx, &view->queryacl));
5437 	}
5438 
5439 	/*
5440 	 * Ignore case when compressing responses to the specified
5441 	 * clients. This causes case not always to be preserved,
5442 	 * and is needed by some broken clients.
5443 	 */
5444 	CHECK(configure_view_acl(vconfig, config, named_g_config,
5445 				 "no-case-compress", NULL, actx, named_g_mctx,
5446 				 &view->nocasecompress));
5447 
5448 	/*
5449 	 * Disable name compression completely, this is a tradeoff
5450 	 * between CPU and network usage.
5451 	 */
5452 	obj = NULL;
5453 	result = named_config_get(maps, "message-compression", &obj);
5454 	INSIST(result == ISC_R_SUCCESS);
5455 	view->msgcompression = cfg_obj_asboolean(obj);
5456 
5457 	/*
5458 	 * Filter setting on addresses in the answer section.
5459 	 */
5460 	CHECK(configure_view_acl(vconfig, config, named_g_config,
5461 				 "deny-answer-addresses", "acl", actx,
5462 				 named_g_mctx, &view->denyansweracl));
5463 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
5464 				       "except-from", named_g_mctx,
5465 				       &view->answeracl_exclude));
5466 
5467 	/*
5468 	 * Filter setting on names (CNAME/DNAME targets) in the answer section.
5469 	 */
5470 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5471 				       "name", named_g_mctx,
5472 				       &view->denyanswernames));
5473 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5474 				       "except-from", named_g_mctx,
5475 				       &view->answernames_exclude));
5476 
5477 	/*
5478 	 * Configure sortlist, if set
5479 	 */
5480 	CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx,
5481 				      &view->sortlist));
5482 
5483 	/*
5484 	 * Configure default allow-update and allow-update-forwarding ACLs,
5485 	 * so they can be inherited by zones. (XXX: These are not
5486 	 * read from the options/view level here. However, they may be
5487 	 * read from there in zoneconf.c:configure_zone_acl() later.)
5488 	 */
5489 	if (view->updateacl == NULL) {
5490 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5491 					 "allow-update", NULL, actx,
5492 					 named_g_mctx, &view->updateacl));
5493 	}
5494 	if (view->upfwdacl == NULL) {
5495 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5496 					 "allow-update-forwarding", NULL, actx,
5497 					 named_g_mctx, &view->upfwdacl));
5498 	}
5499 
5500 	/*
5501 	 * Configure default allow-transfer and allow-notify ACLs so they
5502 	 * can be inherited by zones.
5503 	 */
5504 	if (view->transferacl == NULL) {
5505 		CHECK(configure_view_acl(vconfig, config, named_g_config,
5506 					 "allow-transfer", NULL, actx,
5507 					 named_g_mctx, &view->transferacl));
5508 	}
5509 	if (view->notifyacl == NULL) {
5510 		CHECK(configure_view_acl(vconfig, config, named_g_config,
5511 					 "allow-notify", NULL, actx,
5512 					 named_g_mctx, &view->notifyacl));
5513 	}
5514 
5515 	obj = NULL;
5516 	result = named_config_get(maps, "provide-ixfr", &obj);
5517 	INSIST(result == ISC_R_SUCCESS);
5518 	view->provideixfr = cfg_obj_asboolean(obj);
5519 
5520 	obj = NULL;
5521 	result = named_config_get(maps, "request-nsid", &obj);
5522 	INSIST(result == ISC_R_SUCCESS);
5523 	view->requestnsid = cfg_obj_asboolean(obj);
5524 
5525 	obj = NULL;
5526 	result = named_config_get(maps, "send-cookie", &obj);
5527 	INSIST(result == ISC_R_SUCCESS);
5528 	view->sendcookie = cfg_obj_asboolean(obj);
5529 
5530 	obj = NULL;
5531 	if (view->pad_acl != NULL) {
5532 		dns_acl_detach(&view->pad_acl);
5533 	}
5534 	result = named_config_get(optionmaps, "response-padding", &obj);
5535 	if (result == ISC_R_SUCCESS) {
5536 		const cfg_obj_t *padobj = cfg_tuple_get(obj, "block-size");
5537 		const cfg_obj_t *aclobj = cfg_tuple_get(obj, "acl");
5538 		uint32_t padding = cfg_obj_asuint32(padobj);
5539 
5540 		if (padding > 512U) {
5541 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
5542 				    "response-padding block-size cannot "
5543 				    "exceed 512: lowering");
5544 			padding = 512U;
5545 		}
5546 		view->padding = (uint16_t)padding;
5547 		CHECK(cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx,
5548 					 named_g_mctx, 0, &view->pad_acl));
5549 	}
5550 
5551 	obj = NULL;
5552 	result = named_config_get(maps, "require-server-cookie", &obj);
5553 	INSIST(result == ISC_R_SUCCESS);
5554 	view->requireservercookie = cfg_obj_asboolean(obj);
5555 
5556 	obj = NULL;
5557 	result = named_config_get(maps, "v6-bias", &obj);
5558 	INSIST(result == ISC_R_SUCCESS);
5559 	view->v6bias = cfg_obj_asuint32(obj) * 1000;
5560 
5561 	obj = NULL;
5562 	result = named_config_get(maps, "max-clients-per-query", &obj);
5563 	INSIST(result == ISC_R_SUCCESS);
5564 	max_clients_per_query = cfg_obj_asuint32(obj);
5565 
5566 	obj = NULL;
5567 	result = named_config_get(maps, "clients-per-query", &obj);
5568 	INSIST(result == ISC_R_SUCCESS);
5569 	dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj),
5570 					max_clients_per_query);
5571 
5572 	/*
5573 	 * This is used for the cache and also as a default value
5574 	 * for zone databases.
5575 	 */
5576 	obj = NULL;
5577 	result = named_config_get(maps, "max-records-per-type", &obj);
5578 	INSIST(result == ISC_R_SUCCESS);
5579 	dns_view_setmaxrrperset(view, cfg_obj_asuint32(obj));
5580 
5581 	/*
5582 	 * This is used for the cache and also as a default value
5583 	 * for zone databases.
5584 	 */
5585 	obj = NULL;
5586 	result = named_config_get(maps, "max-types-per-name", &obj);
5587 	INSIST(result == ISC_R_SUCCESS);
5588 	dns_view_setmaxtypepername(view, cfg_obj_asuint32(obj));
5589 
5590 	obj = NULL;
5591 	result = named_config_get(maps, "max-recursion-depth", &obj);
5592 	INSIST(result == ISC_R_SUCCESS);
5593 	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
5594 
5595 	obj = NULL;
5596 	result = named_config_get(maps, "max-recursion-queries", &obj);
5597 	INSIST(result == ISC_R_SUCCESS);
5598 	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
5599 
5600 	obj = NULL;
5601 	result = named_config_get(maps, "max-query-restarts", &obj);
5602 	INSIST(result == ISC_R_SUCCESS);
5603 	dns_view_setmaxrestarts(view, cfg_obj_asuint32(obj));
5604 
5605 	obj = NULL;
5606 	result = named_config_get(maps, "max-validations-per-fetch", &obj);
5607 	if (result == ISC_R_SUCCESS) {
5608 		dns_resolver_setmaxvalidations(view->resolver,
5609 					       cfg_obj_asuint32(obj));
5610 	}
5611 
5612 	obj = NULL;
5613 	result = named_config_get(maps, "max-validation-failures-per-fetch",
5614 				  &obj);
5615 	if (result == ISC_R_SUCCESS) {
5616 		dns_resolver_setmaxvalidationfails(view->resolver,
5617 						   cfg_obj_asuint32(obj));
5618 	}
5619 
5620 	obj = NULL;
5621 	result = named_config_get(maps, "fetches-per-zone", &obj);
5622 	INSIST(result == ISC_R_SUCCESS);
5623 	obj2 = cfg_tuple_get(obj, "fetches");
5624 	dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
5625 	obj2 = cfg_tuple_get(obj, "response");
5626 	if (!cfg_obj_isvoid(obj2)) {
5627 		const char *resp = cfg_obj_asstring(obj2);
5628 		isc_result_t r = DNS_R_SERVFAIL;
5629 
5630 		if (strcasecmp(resp, "drop") == 0) {
5631 			r = DNS_R_DROP;
5632 		} else if (strcasecmp(resp, "fail") == 0) {
5633 			r = DNS_R_SERVFAIL;
5634 		} else {
5635 			UNREACHABLE();
5636 		}
5637 
5638 		dns_resolver_setquotaresponse(view->resolver,
5639 					      dns_quotatype_zone, r);
5640 	}
5641 
5642 	obj = NULL;
5643 	result = named_config_get(maps, "prefetch", &obj);
5644 	INSIST(result == ISC_R_SUCCESS);
5645 	prefetch_trigger = cfg_tuple_get(obj, "trigger");
5646 	view->prefetch_trigger = cfg_obj_asuint32(prefetch_trigger);
5647 	if (view->prefetch_trigger > 10) {
5648 		view->prefetch_trigger = 10;
5649 	}
5650 	prefetch_eligible = cfg_tuple_get(obj, "eligible");
5651 	if (cfg_obj_isvoid(prefetch_eligible)) {
5652 		int m;
5653 		for (m = 1; maps[m] != NULL; m++) {
5654 			obj = NULL;
5655 			result = named_config_get(&maps[m], "prefetch", &obj);
5656 			INSIST(result == ISC_R_SUCCESS);
5657 			prefetch_eligible = cfg_tuple_get(obj, "eligible");
5658 			if (cfg_obj_isuint32(prefetch_eligible)) {
5659 				break;
5660 			}
5661 		}
5662 		INSIST(cfg_obj_isuint32(prefetch_eligible));
5663 	}
5664 	view->prefetch_eligible = cfg_obj_asuint32(prefetch_eligible);
5665 	if (view->prefetch_eligible < view->prefetch_trigger + 6) {
5666 		view->prefetch_eligible = view->prefetch_trigger + 6;
5667 	}
5668 
5669 	/*
5670 	 * For now, there is only one kind of trusted keys, the
5671 	 * "security roots".
5672 	 */
5673 	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
5674 					auto_root));
5675 
5676 	obj = NULL;
5677 	result = named_config_get(maps, "dnssec-must-be-secure", &obj);
5678 	if (result == ISC_R_SUCCESS) {
5679 		CHECK(mustbesecure(obj, view->resolver));
5680 	}
5681 
5682 	obj = NULL;
5683 	result = named_config_get(maps, "nta-recheck", &obj);
5684 	INSIST(result == ISC_R_SUCCESS);
5685 	view->nta_recheck = cfg_obj_asduration(obj);
5686 
5687 	obj = NULL;
5688 	result = named_config_get(maps, "nta-lifetime", &obj);
5689 	INSIST(result == ISC_R_SUCCESS);
5690 	view->nta_lifetime = cfg_obj_asduration(obj);
5691 
5692 	obj = NULL;
5693 	result = named_config_get(maps, "preferred-glue", &obj);
5694 	if (result == ISC_R_SUCCESS) {
5695 		str = cfg_obj_asstring(obj);
5696 		if (strcasecmp(str, "a") == 0) {
5697 			view->preferred_glue = dns_rdatatype_a;
5698 		} else if (strcasecmp(str, "aaaa") == 0) {
5699 			view->preferred_glue = dns_rdatatype_aaaa;
5700 		} else {
5701 			view->preferred_glue = 0;
5702 		}
5703 	} else {
5704 		view->preferred_glue = 0;
5705 	}
5706 
5707 	/*
5708 	 * Load DynDB modules.
5709 	 */
5710 	dyndb_list = NULL;
5711 	if (voptions != NULL) {
5712 		(void)cfg_map_get(voptions, "dyndb", &dyndb_list);
5713 	} else {
5714 		(void)cfg_map_get(config, "dyndb", &dyndb_list);
5715 	}
5716 
5717 	for (element = cfg_list_first(dyndb_list); element != NULL;
5718 	     element = cfg_list_next(element))
5719 	{
5720 		const cfg_obj_t *dyndb = cfg_listelt_value(element);
5721 
5722 		if (dctx == NULL) {
5723 			const void *hashinit = isc_hash_get_initializer();
5724 			CHECK(dns_dyndb_createctx(mctx, hashinit, named_g_lctx,
5725 						  view, named_g_server->zonemgr,
5726 						  named_g_loopmgr, &dctx));
5727 		}
5728 
5729 		CHECK(configure_dyndb(dyndb, mctx, dctx));
5730 	}
5731 
5732 	/*
5733 	 * Load plugins.
5734 	 */
5735 	plugin_list = NULL;
5736 	if (voptions != NULL) {
5737 		(void)cfg_map_get(voptions, "plugin", &plugin_list);
5738 	} else {
5739 		(void)cfg_map_get(config, "plugin", &plugin_list);
5740 	}
5741 
5742 	if (plugin_list != NULL) {
5743 		INSIST(view->hooktable == NULL);
5744 		CHECK(ns_hooktable_create(view->mctx,
5745 					  (ns_hooktable_t **)&view->hooktable));
5746 		view->hooktable_free = ns_hooktable_free;
5747 
5748 		ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
5749 		view->plugins_free = ns_plugins_free;
5750 
5751 		CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
5752 					     register_one_plugin, view));
5753 	}
5754 
5755 	/*
5756 	 * Setup automatic empty zones.  If recursion is off then
5757 	 * they are disabled by default.
5758 	 */
5759 	obj = NULL;
5760 	(void)named_config_get(maps, "empty-zones-enable", &obj);
5761 	(void)named_config_get(maps, "disable-empty-zone", &disablelist);
5762 	if (obj == NULL && disablelist == NULL &&
5763 	    view->rdclass == dns_rdataclass_in)
5764 	{
5765 		empty_zones_enable = view->recursion;
5766 	} else if (view->rdclass == dns_rdataclass_in) {
5767 		if (obj != NULL) {
5768 			empty_zones_enable = cfg_obj_asboolean(obj);
5769 		} else {
5770 			empty_zones_enable = view->recursion;
5771 		}
5772 	} else {
5773 		empty_zones_enable = false;
5774 	}
5775 
5776 	if (empty_zones_enable) {
5777 		const char *empty;
5778 		int empty_zone = 0;
5779 		dns_fixedname_t fixed;
5780 		dns_name_t *name;
5781 		isc_buffer_t buffer;
5782 		char server[DNS_NAME_FORMATSIZE + 1];
5783 		char contact[DNS_NAME_FORMATSIZE + 1];
5784 		const char *empty_dbtype[4] = { "_builtin", "empty", NULL,
5785 						NULL };
5786 		int empty_dbtypec = 4;
5787 		dns_zonestat_level_t statlevel = dns_zonestat_none;
5788 
5789 		name = dns_fixedname_initname(&fixed);
5790 
5791 		obj = NULL;
5792 		result = named_config_get(maps, "empty-server", &obj);
5793 		if (result == ISC_R_SUCCESS) {
5794 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5795 						  dns_rootname, 0, NULL));
5796 			isc_buffer_init(&buffer, server, sizeof(server) - 1);
5797 			CHECK(dns_name_totext(name, 0, &buffer));
5798 			server[isc_buffer_usedlength(&buffer)] = 0;
5799 			empty_dbtype[2] = server;
5800 		} else {
5801 			empty_dbtype[2] = "@";
5802 		}
5803 
5804 		obj = NULL;
5805 		result = named_config_get(maps, "empty-contact", &obj);
5806 		if (result == ISC_R_SUCCESS) {
5807 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5808 						  dns_rootname, 0, NULL));
5809 			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
5810 			CHECK(dns_name_totext(name, 0, &buffer));
5811 			contact[isc_buffer_usedlength(&buffer)] = 0;
5812 			empty_dbtype[3] = contact;
5813 		} else {
5814 			empty_dbtype[3] = ".";
5815 		}
5816 
5817 		obj = NULL;
5818 		result = named_config_get(maps, "zone-statistics", &obj);
5819 		INSIST(result == ISC_R_SUCCESS);
5820 		if (cfg_obj_isboolean(obj)) {
5821 			if (cfg_obj_asboolean(obj)) {
5822 				statlevel = dns_zonestat_full;
5823 			} else {
5824 				statlevel = dns_zonestat_none;
5825 			}
5826 		} else {
5827 			const char *levelstr = cfg_obj_asstring(obj);
5828 			if (strcasecmp(levelstr, "full") == 0) {
5829 				statlevel = dns_zonestat_full;
5830 			} else if (strcasecmp(levelstr, "terse") == 0) {
5831 				statlevel = dns_zonestat_terse;
5832 			} else if (strcasecmp(levelstr, "none") == 0) {
5833 				statlevel = dns_zonestat_none;
5834 			} else {
5835 				UNREACHABLE();
5836 			}
5837 		}
5838 
5839 		for (empty = empty_zones[empty_zone]; empty != NULL;
5840 		     empty = empty_zones[++empty_zone])
5841 		{
5842 			dns_forwarders_t *dnsforwarders = NULL;
5843 			dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
5844 
5845 			/*
5846 			 * Look for zone on drop list.
5847 			 */
5848 			CHECK(dns_name_fromstring(name, empty, dns_rootname, 0,
5849 						  NULL));
5850 			if (disablelist != NULL &&
5851 			    on_disable_list(disablelist, name))
5852 			{
5853 				continue;
5854 			}
5855 
5856 			/*
5857 			 * This zone already exists.
5858 			 */
5859 			(void)dns_view_findzone(view, name, DNS_ZTFIND_EXACT,
5860 						&zone);
5861 			if (zone != NULL) {
5862 				dns_zone_detach(&zone);
5863 				continue;
5864 			}
5865 
5866 			/*
5867 			 * If we would forward this name don't add a
5868 			 * empty zone for it.
5869 			 */
5870 			result = dns_fwdtable_find(view->fwdtable, name,
5871 						   &dnsforwarders);
5872 			if (result == ISC_R_SUCCESS ||
5873 			    result == DNS_R_PARTIALMATCH)
5874 			{
5875 				fwdpolicy = dnsforwarders->fwdpolicy;
5876 				dns_forwarders_detach(&dnsforwarders);
5877 			}
5878 			if (fwdpolicy == dns_fwdpolicy_only) {
5879 				continue;
5880 			}
5881 
5882 			/*
5883 			 * See if we can re-use a existing zone.
5884 			 */
5885 			result = dns_viewlist_find(&named_g_server->viewlist,
5886 						   view->name, view->rdclass,
5887 						   &pview);
5888 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
5889 			{
5890 				goto cleanup;
5891 			}
5892 
5893 			if (pview != NULL) {
5894 				(void)dns_view_findzone(
5895 					pview, name, DNS_ZTFIND_EXACT, &zone);
5896 				dns_view_detach(&pview);
5897 			}
5898 
5899 			CHECK(create_empty_zone(zone, name, view, zonelist,
5900 						empty_dbtype, empty_dbtypec,
5901 						statlevel));
5902 			if (zone != NULL) {
5903 				dns_zone_detach(&zone);
5904 			}
5905 		}
5906 	}
5907 
5908 	obj = NULL;
5909 	if (view->rdclass == dns_rdataclass_in) {
5910 		(void)named_config_get(maps, "ipv4only-enable", &obj);
5911 	}
5912 	if (view->rdclass == dns_rdataclass_in && (obj != NULL)
5913 		    ? cfg_obj_asboolean(obj)
5914 		    : !ISC_LIST_EMPTY(view->dns64))
5915 	{
5916 		const char *server, *contact;
5917 		dns_fixedname_t fixed;
5918 		dns_name_t *name;
5919 		struct {
5920 			const char *name;
5921 			const char *type;
5922 		} zones[] = {
5923 			{ "ipv4only.arpa", "ipv4only" },
5924 			{ "170.0.0.192.in-addr.arpa", "ipv4reverse" },
5925 			{ "171.0.0.192.in-addr.arpa", "ipv4reverse" },
5926 		};
5927 		size_t ipv4only_zone;
5928 
5929 		obj = NULL;
5930 		result = named_config_get(maps, "ipv4only-server", &obj);
5931 		if (result == ISC_R_SUCCESS) {
5932 			server = cfg_obj_asstring(obj);
5933 		} else {
5934 			server = NULL;
5935 		}
5936 
5937 		obj = NULL;
5938 		result = named_config_get(maps, "ipv4only-contact", &obj);
5939 		if (result == ISC_R_SUCCESS) {
5940 			contact = cfg_obj_asstring(obj);
5941 		} else {
5942 			contact = NULL;
5943 		}
5944 
5945 		name = dns_fixedname_initname(&fixed);
5946 		for (ipv4only_zone = 0; ipv4only_zone < ARRAY_SIZE(zones);
5947 		     ipv4only_zone++)
5948 		{
5949 			dns_forwarders_t *dnsforwarders = NULL;
5950 			dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
5951 
5952 			CHECK(dns_name_fromstring(name,
5953 						  zones[ipv4only_zone].name,
5954 						  dns_rootname, 0, NULL));
5955 
5956 			(void)dns_view_findzone(view, name, DNS_ZTFIND_EXACT,
5957 						&zone);
5958 			if (zone != NULL) {
5959 				dns_zone_detach(&zone);
5960 				continue;
5961 			}
5962 
5963 			/*
5964 			 * If we would forward this name don't add it.
5965 			 */
5966 			result = dns_fwdtable_find(view->fwdtable, name,
5967 						   &dnsforwarders);
5968 			if (result == ISC_R_SUCCESS ||
5969 			    result == DNS_R_PARTIALMATCH)
5970 			{
5971 				fwdpolicy = dnsforwarders->fwdpolicy;
5972 				dns_forwarders_detach(&dnsforwarders);
5973 			}
5974 			if (fwdpolicy == dns_fwdpolicy_only) {
5975 				continue;
5976 			}
5977 
5978 			/*
5979 			 * See if we can re-use a existing zone.
5980 			 */
5981 			result = dns_viewlist_find(&named_g_server->viewlist,
5982 						   view->name, view->rdclass,
5983 						   &pview);
5984 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
5985 			{
5986 				goto cleanup;
5987 			}
5988 
5989 			if (pview != NULL) {
5990 				(void)dns_view_findzone(
5991 					pview, name, DNS_ZTFIND_EXACT, &zone);
5992 				dns_view_detach(&pview);
5993 			}
5994 
5995 			CHECK(create_ipv4only_zone(zone, view, name,
5996 						   zones[ipv4only_zone].type,
5997 						   mctx, server, contact));
5998 			if (zone != NULL) {
5999 				dns_zone_detach(&zone);
6000 			}
6001 		}
6002 	}
6003 
6004 	obj = NULL;
6005 	result = named_config_get(maps, "rate-limit", &obj);
6006 	if (result == ISC_R_SUCCESS) {
6007 		result = configure_rrl(view, config, obj);
6008 		if (result != ISC_R_SUCCESS) {
6009 			goto cleanup;
6010 		}
6011 	}
6012 
6013 	/*
6014 	 * Set the servfail-ttl.
6015 	 */
6016 	obj = NULL;
6017 	result = named_config_get(maps, "servfail-ttl", &obj);
6018 	INSIST(result == ISC_R_SUCCESS);
6019 	fail_ttl = cfg_obj_asduration(obj);
6020 	if (fail_ttl > 30) {
6021 		fail_ttl = 30;
6022 	}
6023 	dns_view_setfailttl(view, fail_ttl);
6024 
6025 	/*
6026 	 * Name space to look up redirect information in.
6027 	 */
6028 	obj = NULL;
6029 	result = named_config_get(maps, "nxdomain-redirect", &obj);
6030 	if (result == ISC_R_SUCCESS) {
6031 		dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
6032 		CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
6033 					  dns_rootname, 0, NULL));
6034 		view->redirectzone = name;
6035 	} else {
6036 		view->redirectzone = NULL;
6037 	}
6038 
6039 	/*
6040 	 * Exceptions to DNSSEC validation.
6041 	 */
6042 	obj = NULL;
6043 	result = named_config_get(maps, "validate-except", &obj);
6044 	if (result == ISC_R_SUCCESS) {
6045 		result = dns_view_getntatable(view, &ntatable);
6046 	}
6047 	if (result == ISC_R_SUCCESS) {
6048 		for (element = cfg_list_first(obj); element != NULL;
6049 		     element = cfg_list_next(element))
6050 		{
6051 			dns_fixedname_t fntaname;
6052 			dns_name_t *ntaname;
6053 
6054 			ntaname = dns_fixedname_initname(&fntaname);
6055 			obj = cfg_listelt_value(element);
6056 			CHECK(dns_name_fromstring(ntaname,
6057 						  cfg_obj_asstring(obj),
6058 						  dns_rootname, 0, NULL));
6059 			CHECK(dns_ntatable_add(ntatable, ntaname, true, 0,
6060 					       0xffffffffU));
6061 		}
6062 	}
6063 
6064 #ifdef HAVE_DNSTAP
6065 	/*
6066 	 * Set up the dnstap environment and configure message
6067 	 * types to log.
6068 	 */
6069 	CHECK(configure_dnstap(maps, view));
6070 #endif /* HAVE_DNSTAP */
6071 
6072 	result = ISC_R_SUCCESS;
6073 
6074 cleanup:
6075 	/*
6076 	 * Revert to the old view if there was an error.
6077 	 */
6078 	if (result != ISC_R_SUCCESS) {
6079 		isc_result_t result2;
6080 
6081 		result2 = dns_viewlist_find(&named_g_server->viewlist,
6082 					    view->name, view->rdclass, &pview);
6083 		if (result2 == ISC_R_SUCCESS) {
6084 			dns_view_thaw(pview);
6085 
6086 			obj = NULL;
6087 			if (rpz_configured &&
6088 			    pview->rdclass == dns_rdataclass_in && need_hints &&
6089 			    named_config_get(maps, "response-policy", &obj) ==
6090 				    ISC_R_SUCCESS)
6091 			{
6092 				/*
6093 				 * We are swapping the places of the `view` and
6094 				 * `pview` in the function's parameters list
6095 				 * because we are reverting the same operation
6096 				 * done previously in the "correct" order.
6097 				 */
6098 				result2 = configure_rpz(pview, view, maps, obj,
6099 							&old_rpz_ok);
6100 				if (result2 != ISC_R_SUCCESS) {
6101 					isc_log_write(named_g_lctx,
6102 						      NAMED_LOGCATEGORY_GENERAL,
6103 						      NAMED_LOGMODULE_SERVER,
6104 						      ISC_LOG_ERROR,
6105 						      "rpz configuration "
6106 						      "revert failed for view "
6107 						      "'%s'",
6108 						      pview->name);
6109 				}
6110 			}
6111 
6112 			obj = NULL;
6113 			if (catz_configured &&
6114 			    pview->rdclass == dns_rdataclass_in && need_hints &&
6115 			    named_config_get(maps, "catalog-zones", &obj) ==
6116 				    ISC_R_SUCCESS)
6117 			{
6118 				/*
6119 				 * We are swapping the places of the `view` and
6120 				 * `pview` in the function's parameters list
6121 				 * because we are reverting the same operation
6122 				 * done previously in the "correct" order.
6123 				 */
6124 				result2 = configure_catz(pview, view, config,
6125 							 obj);
6126 				if (result2 != ISC_R_SUCCESS) {
6127 					isc_log_write(named_g_lctx,
6128 						      NAMED_LOGCATEGORY_GENERAL,
6129 						      NAMED_LOGMODULE_SERVER,
6130 						      ISC_LOG_ERROR,
6131 						      "catz configuration "
6132 						      "revert failed for view "
6133 						      "'%s'",
6134 						      pview->name);
6135 				}
6136 			}
6137 
6138 			dns_view_freeze(pview);
6139 		}
6140 
6141 		if (pview != NULL) {
6142 			dns_view_detach(&pview);
6143 		}
6144 
6145 		if (zone_element_latest != NULL) {
6146 			for (element = cfg_list_first(zonelist);
6147 			     element != NULL; element = cfg_list_next(element))
6148 			{
6149 				const cfg_obj_t *zconfig =
6150 					cfg_listelt_value(element);
6151 				configure_zone_setviewcommit(result, zconfig,
6152 							     view);
6153 				if (element == zone_element_latest) {
6154 					/*
6155 					 * This was the latest element that was
6156 					 * successfully configured earlier.
6157 					 */
6158 					break;
6159 				}
6160 			}
6161 		}
6162 	}
6163 
6164 	if (ntatable != NULL) {
6165 		dns_ntatable_detach(&ntatable);
6166 	}
6167 	if (clients != NULL) {
6168 		dns_acl_detach(&clients);
6169 	}
6170 	if (mapped != NULL) {
6171 		dns_acl_detach(&mapped);
6172 	}
6173 	if (excluded != NULL) {
6174 		dns_acl_detach(&excluded);
6175 	}
6176 	if (ring != NULL) {
6177 		dns_tsigkeyring_detach(&ring);
6178 	}
6179 	if (zone != NULL) {
6180 		dns_zone_detach(&zone);
6181 	}
6182 	if (dispatch4 != NULL) {
6183 		dns_dispatch_detach(&dispatch4);
6184 	}
6185 	if (dispatch6 != NULL) {
6186 		dns_dispatch_detach(&dispatch6);
6187 	}
6188 	if (resstats != NULL) {
6189 		isc_stats_detach(&resstats);
6190 	}
6191 	if (resquerystats != NULL) {
6192 		dns_stats_detach(&resquerystats);
6193 	}
6194 	if (order != NULL) {
6195 		dns_order_detach(&order);
6196 	}
6197 	if (cache != NULL) {
6198 		dns_cache_detach(&cache);
6199 	}
6200 	if (dctx != NULL) {
6201 		dns_dyndb_destroyctx(&dctx);
6202 	}
6203 
6204 	return result;
6205 }
6206 
6207 static isc_result_t
6208 configure_hints(dns_view_t *view, const char *filename) {
6209 	isc_result_t result;
6210 	dns_db_t *db;
6211 
6212 	db = NULL;
6213 	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
6214 	if (result == ISC_R_SUCCESS) {
6215 		dns_view_sethints(view, db);
6216 		dns_db_detach(&db);
6217 	}
6218 
6219 	return result;
6220 }
6221 
6222 static isc_result_t
6223 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
6224 		     const cfg_obj_t *alternates) {
6225 	const cfg_obj_t *portobj;
6226 	const cfg_obj_t *addresses;
6227 	const cfg_listelt_t *element;
6228 	isc_result_t result = ISC_R_SUCCESS;
6229 	in_port_t port;
6230 
6231 	/*
6232 	 * Determine which port to send requests to.
6233 	 */
6234 	CHECKM(named_config_getport(config, "port", &port), "port");
6235 
6236 	if (alternates != NULL) {
6237 		portobj = cfg_tuple_get(alternates, "port");
6238 		if (cfg_obj_isuint32(portobj)) {
6239 			uint32_t val = cfg_obj_asuint32(portobj);
6240 			if (val > UINT16_MAX) {
6241 				cfg_obj_log(portobj, named_g_lctx,
6242 					    ISC_LOG_ERROR,
6243 					    "port '%u' out of range", val);
6244 				return ISC_R_RANGE;
6245 			}
6246 			port = (in_port_t)val;
6247 		}
6248 	}
6249 
6250 	addresses = NULL;
6251 	if (alternates != NULL) {
6252 		addresses = cfg_tuple_get(alternates, "addresses");
6253 	}
6254 
6255 	for (element = cfg_list_first(addresses); element != NULL;
6256 	     element = cfg_list_next(element))
6257 	{
6258 		const cfg_obj_t *alternate = cfg_listelt_value(element);
6259 		isc_sockaddr_t sa;
6260 
6261 		if (!cfg_obj_issockaddr(alternate)) {
6262 			dns_fixedname_t fixed;
6263 			dns_name_t *name;
6264 			const char *str = cfg_obj_asstring(
6265 				cfg_tuple_get(alternate, "name"));
6266 			isc_buffer_t buffer;
6267 			in_port_t myport = port;
6268 
6269 			isc_buffer_constinit(&buffer, str, strlen(str));
6270 			isc_buffer_add(&buffer, strlen(str));
6271 			name = dns_fixedname_initname(&fixed);
6272 			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
6273 						NULL));
6274 
6275 			portobj = cfg_tuple_get(alternate, "port");
6276 			if (cfg_obj_isuint32(portobj)) {
6277 				uint32_t val = cfg_obj_asuint32(portobj);
6278 				if (val > UINT16_MAX) {
6279 					cfg_obj_log(portobj, named_g_lctx,
6280 						    ISC_LOG_ERROR,
6281 						    "port '%u' out of range",
6282 						    val);
6283 					return ISC_R_RANGE;
6284 				}
6285 				myport = (in_port_t)val;
6286 			}
6287 			dns_resolver_addalternate(view->resolver, NULL, name,
6288 						  myport);
6289 			continue;
6290 		}
6291 
6292 		sa = *cfg_obj_assockaddr(alternate);
6293 		if (isc_sockaddr_getport(&sa) == 0) {
6294 			isc_sockaddr_setport(&sa, port);
6295 		}
6296 		dns_resolver_addalternate(view->resolver, &sa, NULL, 0);
6297 	}
6298 
6299 cleanup:
6300 	return result;
6301 }
6302 
6303 static isc_result_t
6304 validate_tls(const cfg_obj_t *config, dns_view_t *view, const cfg_obj_t *obj,
6305 	     isc_log_t *logctx, const char *str, dns_name_t **name) {
6306 	dns_fixedname_t fname;
6307 	dns_name_t *nm = dns_fixedname_initname(&fname);
6308 	isc_result_t result = dns_name_fromstring(nm, str, dns_rootname, 0,
6309 						  NULL);
6310 
6311 	if (result != ISC_R_SUCCESS) {
6312 		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
6313 			    "'%s' is not a valid name", str);
6314 		return result;
6315 	}
6316 
6317 	if (strcasecmp(str, "ephemeral") != 0) {
6318 		const cfg_obj_t *tlsmap = find_maplist(config, "tls", str);
6319 
6320 		if (tlsmap == NULL) {
6321 			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
6322 				    "tls '%s' is not defined", str);
6323 			return ISC_R_FAILURE;
6324 		}
6325 	}
6326 
6327 	if (name != NULL && *name == NULL) {
6328 		*name = isc_mem_get(view->mctx, sizeof(dns_name_t));
6329 		dns_name_init(*name, NULL);
6330 		dns_name_dup(nm, view->mctx, *name);
6331 	}
6332 
6333 	return ISC_R_SUCCESS;
6334 }
6335 
6336 static isc_result_t
6337 configure_forward(const cfg_obj_t *config, dns_view_t *view,
6338 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
6339 		  const cfg_obj_t *forwardtype) {
6340 	const cfg_obj_t *portobj = NULL;
6341 	const cfg_obj_t *tlspobj = NULL;
6342 	const cfg_obj_t *faddresses = NULL;
6343 	const cfg_listelt_t *element = NULL;
6344 	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
6345 	dns_forwarderlist_t fwdlist;
6346 	dns_forwarder_t *fwd = NULL;
6347 	isc_result_t result;
6348 	in_port_t port;
6349 	in_port_t tls_port;
6350 	const char *tls = NULL;
6351 
6352 	ISC_LIST_INIT(fwdlist);
6353 
6354 	/*
6355 	 * Determine which port to send forwarded requests to.
6356 	 */
6357 	CHECKM(named_config_getport(config, "port", &port), "port");
6358 	CHECKM(named_config_getport(config, "tls-port", &tls_port), "tls-port");
6359 
6360 	if (forwarders != NULL) {
6361 		portobj = cfg_tuple_get(forwarders, "port");
6362 		if (cfg_obj_isuint32(portobj)) {
6363 			uint32_t val = cfg_obj_asuint32(portobj);
6364 			if (val > UINT16_MAX) {
6365 				cfg_obj_log(portobj, named_g_lctx,
6366 					    ISC_LOG_ERROR,
6367 					    "port '%u' out of range", val);
6368 				return ISC_R_RANGE;
6369 			}
6370 			port = tls_port = (in_port_t)val;
6371 		}
6372 	}
6373 
6374 	/*
6375 	 * TLS value for forwarded requests.
6376 	 */
6377 	if (forwarders != NULL) {
6378 		tlspobj = cfg_tuple_get(forwarders, "tls");
6379 		if (cfg_obj_isstring(tlspobj)) {
6380 			tls = cfg_obj_asstring(tlspobj);
6381 			if (tls != NULL) {
6382 				result = validate_tls(config, view, tlspobj,
6383 						      named_g_lctx, tls, NULL);
6384 				if (result != ISC_R_SUCCESS) {
6385 					return result;
6386 				}
6387 			}
6388 		}
6389 	}
6390 
6391 	faddresses = NULL;
6392 	if (forwarders != NULL) {
6393 		faddresses = cfg_tuple_get(forwarders, "addresses");
6394 	}
6395 
6396 	for (element = cfg_list_first(faddresses); element != NULL;
6397 	     element = cfg_list_next(element))
6398 	{
6399 		const cfg_obj_t *forwarder = cfg_listelt_value(element);
6400 		const char *cur_tls = NULL;
6401 
6402 		fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
6403 		fwd->tlsname = NULL;
6404 		cur_tls = cfg_obj_getsockaddrtls(forwarder);
6405 		if (cur_tls == NULL) {
6406 			cur_tls = tls;
6407 		}
6408 		if (cur_tls != NULL) {
6409 			result = validate_tls(config, view, faddresses,
6410 					      named_g_lctx, cur_tls,
6411 					      &fwd->tlsname);
6412 			if (result != ISC_R_SUCCESS) {
6413 				isc_mem_put(view->mctx, fwd,
6414 					    sizeof(dns_forwarder_t));
6415 				goto cleanup;
6416 			}
6417 		}
6418 		fwd->addr = *cfg_obj_assockaddr(forwarder);
6419 		if (isc_sockaddr_getport(&fwd->addr) == 0) {
6420 			isc_sockaddr_setport(&fwd->addr,
6421 					     cur_tls != NULL ? tls_port : port);
6422 		}
6423 		ISC_LINK_INIT(fwd, link);
6424 		ISC_LIST_APPEND(fwdlist, fwd, link);
6425 	}
6426 
6427 	if (ISC_LIST_EMPTY(fwdlist)) {
6428 		if (forwardtype != NULL) {
6429 			cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING,
6430 				    "no forwarders seen; disabling "
6431 				    "forwarding");
6432 		}
6433 		fwdpolicy = dns_fwdpolicy_none;
6434 	} else {
6435 		if (forwardtype == NULL) {
6436 			fwdpolicy = dns_fwdpolicy_first;
6437 		} else {
6438 			const char *forwardstr = cfg_obj_asstring(forwardtype);
6439 			if (strcasecmp(forwardstr, "first") == 0) {
6440 				fwdpolicy = dns_fwdpolicy_first;
6441 			} else if (strcasecmp(forwardstr, "only") == 0) {
6442 				fwdpolicy = dns_fwdpolicy_only;
6443 			} else {
6444 				UNREACHABLE();
6445 			}
6446 		}
6447 	}
6448 
6449 	result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
6450 				     fwdpolicy);
6451 	if (result != ISC_R_SUCCESS) {
6452 		char namebuf[DNS_NAME_FORMATSIZE];
6453 		dns_name_format(origin, namebuf, sizeof(namebuf));
6454 		cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING,
6455 			    "could not set up forwarding for domain '%s': %s",
6456 			    namebuf, isc_result_totext(result));
6457 		goto cleanup;
6458 	}
6459 
6460 	if (fwdpolicy == dns_fwdpolicy_only) {
6461 		dns_view_sfd_add(view, origin);
6462 	}
6463 
6464 	result = ISC_R_SUCCESS;
6465 
6466 cleanup:
6467 
6468 	while (!ISC_LIST_EMPTY(fwdlist)) {
6469 		fwd = ISC_LIST_HEAD(fwdlist);
6470 		ISC_LIST_UNLINK(fwdlist, fwd, link);
6471 		if (fwd->tlsname != NULL) {
6472 			dns_name_free(fwd->tlsname, view->mctx);
6473 			isc_mem_put(view->mctx, fwd->tlsname,
6474 				    sizeof(dns_name_t));
6475 		}
6476 		isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
6477 	}
6478 
6479 	return result;
6480 }
6481 
6482 static isc_result_t
6483 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
6484 	     dns_rdataclass_t *classp) {
6485 	isc_result_t result = ISC_R_SUCCESS;
6486 	const char *viewname;
6487 	dns_rdataclass_t viewclass;
6488 
6489 	REQUIRE(namep != NULL && *namep == NULL);
6490 	REQUIRE(classp != NULL);
6491 
6492 	if (vconfig != NULL) {
6493 		const cfg_obj_t *classobj = NULL;
6494 
6495 		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
6496 		classobj = cfg_tuple_get(vconfig, "class");
6497 		CHECK(named_config_getclass(classobj, dns_rdataclass_in,
6498 					    &viewclass));
6499 		if (dns_rdataclass_ismeta(viewclass)) {
6500 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6501 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6502 				      "view '%s': class must not be meta",
6503 				      viewname);
6504 			CHECK(ISC_R_FAILURE);
6505 		}
6506 	} else {
6507 		viewname = "_default";
6508 		viewclass = dns_rdataclass_in;
6509 	}
6510 
6511 	*namep = viewname;
6512 	*classp = viewclass;
6513 
6514 cleanup:
6515 	return result;
6516 }
6517 
6518 /*
6519  * Find a view based on its configuration info and attach to it.
6520  *
6521  * If 'vconfig' is NULL, attach to the default view.
6522  */
6523 static isc_result_t
6524 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6525 	  dns_view_t **viewp) {
6526 	isc_result_t result;
6527 	const char *viewname = NULL;
6528 	dns_rdataclass_t viewclass;
6529 	dns_view_t *view = NULL;
6530 
6531 	result = get_viewinfo(vconfig, &viewname, &viewclass);
6532 	if (result != ISC_R_SUCCESS) {
6533 		return result;
6534 	}
6535 
6536 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6537 	if (result != ISC_R_SUCCESS) {
6538 		return result;
6539 	}
6540 
6541 	*viewp = view;
6542 	return ISC_R_SUCCESS;
6543 }
6544 
6545 /*
6546  * Create a new view and add it to the list.
6547  *
6548  * If 'vconfig' is NULL, create the default view.
6549  *
6550  * The view created is attached to '*viewp'.
6551  */
6552 static isc_result_t
6553 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6554 	    dns_view_t **viewp) {
6555 	isc_result_t result;
6556 	const char *viewname = NULL;
6557 	dns_rdataclass_t viewclass;
6558 	dns_view_t *view = NULL;
6559 
6560 	result = get_viewinfo(vconfig, &viewname, &viewclass);
6561 	if (result != ISC_R_SUCCESS) {
6562 		return result;
6563 	}
6564 
6565 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6566 	if (result == ISC_R_SUCCESS) {
6567 		return ISC_R_EXISTS;
6568 	}
6569 	if (result != ISC_R_NOTFOUND) {
6570 		return result;
6571 	}
6572 	INSIST(view == NULL);
6573 
6574 	result = dns_view_create(named_g_mctx, named_g_loopmgr,
6575 				 named_g_dispatchmgr, viewclass, viewname,
6576 				 &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, dns_view_t *view,
6594 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
6595 	       dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
6596 	       bool added, bool old_rpz_ok, 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 *viewobj = NULL;
6608 	isc_result_t result = ISC_R_SUCCESS;
6609 	isc_result_t tresult;
6610 	isc_buffer_t buffer;
6611 	dns_fixedname_t fixorigin;
6612 	dns_name_t *origin;
6613 	const char *zname;
6614 	dns_rdataclass_t zclass;
6615 	const char *ztypestr;
6616 	dns_rpz_num_t rpz_num;
6617 	bool zone_is_catz = false;
6618 	bool zone_maybe_inline = false;
6619 	bool inline_signing = false;
6620 	bool fullsign = false;
6621 
6622 	options = NULL;
6623 	(void)cfg_map_get(config, "options", &options);
6624 
6625 	zoptions = cfg_tuple_get(zconfig, "options");
6626 
6627 	/*
6628 	 * Get the zone origin as a dns_name_t.
6629 	 */
6630 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
6631 	isc_buffer_constinit(&buffer, zname, strlen(zname));
6632 	isc_buffer_add(&buffer, strlen(zname));
6633 	dns_fixedname_init(&fixorigin);
6634 	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
6635 				dns_rootname, 0, NULL));
6636 	origin = dns_fixedname_name(&fixorigin);
6637 
6638 	CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"),
6639 				    view->rdclass, &zclass));
6640 	if (zclass != view->rdclass) {
6641 		const char *vname = NULL;
6642 		if (vconfig != NULL) {
6643 			vname = cfg_obj_asstring(
6644 				cfg_tuple_get(vconfig, "name"));
6645 		} else {
6646 			vname = "<default view>";
6647 		}
6648 
6649 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6650 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6651 			      "zone '%s': wrong class for view '%s'", zname,
6652 			      vname);
6653 		result = ISC_R_FAILURE;
6654 		goto cleanup;
6655 	}
6656 
6657 	(void)cfg_map_get(zoptions, "in-view", &viewobj);
6658 	if (viewobj != NULL) {
6659 		const char *inview = cfg_obj_asstring(viewobj);
6660 		dns_view_t *otherview = NULL;
6661 
6662 		if (viewlist == NULL) {
6663 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6664 				    "'in-view' option is not permitted in "
6665 				    "dynamically added zones");
6666 			result = ISC_R_FAILURE;
6667 			goto cleanup;
6668 		}
6669 
6670 		result = dns_viewlist_find(viewlist, inview, view->rdclass,
6671 					   &otherview);
6672 		if (result != ISC_R_SUCCESS) {
6673 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6674 				    "view '%s' is not yet defined.", inview);
6675 			result = ISC_R_FAILURE;
6676 			goto cleanup;
6677 		}
6678 
6679 		result = dns_view_findzone(otherview, origin, DNS_ZTFIND_EXACT,
6680 					   &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 		} else {
6737 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6738 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
6739 				      "ignoring non-root hint zone '%s'",
6740 				      zname);
6741 			result = ISC_R_SUCCESS;
6742 		}
6743 		/* Skip ordinary zone processing. */
6744 		goto cleanup;
6745 	}
6746 
6747 	/*
6748 	 * "forward zones" aren't zones either.  Translate this syntax into
6749 	 * the appropriate selective forwarding configuration and return.
6750 	 */
6751 	if (strcasecmp(ztypestr, "forward") == 0) {
6752 		forwardtype = NULL;
6753 		forwarders = NULL;
6754 
6755 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6756 		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
6757 		CHECK(configure_forward(config, view, origin, forwarders,
6758 					forwardtype));
6759 		goto cleanup;
6760 	}
6761 
6762 	/*
6763 	 * Redirect zones only require minimal configuration.
6764 	 */
6765 	if (strcasecmp(ztypestr, "redirect") == 0) {
6766 		if (view->redirect != NULL) {
6767 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6768 				    "redirect zone already exists");
6769 			result = ISC_R_EXISTS;
6770 			goto cleanup;
6771 		}
6772 		result = dns_viewlist_find(viewlist, view->name, view->rdclass,
6773 					   &pview);
6774 		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6775 			goto cleanup;
6776 		}
6777 		if (pview != NULL && pview->redirect != NULL) {
6778 			dns_zone_attach(pview->redirect, &zone);
6779 			dns_zone_setview(zone, view);
6780 		} else {
6781 			CHECK(dns_zonemgr_createzone(named_g_server->zonemgr,
6782 						     &zone));
6783 			CHECK(dns_zone_setorigin(zone, origin));
6784 			dns_zone_setview(zone, view);
6785 			CHECK(dns_zonemgr_managezone(named_g_server->zonemgr,
6786 						     zone));
6787 			dns_zone_setstats(zone, named_g_server->zonestats);
6788 		}
6789 		CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
6790 					   kasplist, keystores, zone, NULL));
6791 		dns_zone_attach(zone, &view->redirect);
6792 		goto cleanup;
6793 	}
6794 
6795 	if (!modify) {
6796 		/*
6797 		 * Check for duplicates in the new zone table.
6798 		 */
6799 		result = dns_view_findzone(view, origin, DNS_ZTFIND_EXACT,
6800 					   &dupzone);
6801 		if (result == ISC_R_SUCCESS) {
6802 			/*
6803 			 * We already have this zone!
6804 			 */
6805 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6806 				    "zone '%s' already exists", zname);
6807 			dns_zone_detach(&dupzone);
6808 			result = ISC_R_EXISTS;
6809 			goto cleanup;
6810 		}
6811 		INSIST(dupzone == NULL);
6812 	}
6813 
6814 	/*
6815 	 * Note whether this is a response policy zone and which one if so,
6816 	 * unless we are using RPZ service interface.  In that case, the
6817 	 * BIND zone database has nothing to do with rpz and so we don't care.
6818 	 */
6819 	for (rpz_num = 0;; ++rpz_num) {
6820 		if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
6821 		    view->rpzs->p.dnsrps_enabled)
6822 		{
6823 			rpz_num = DNS_RPZ_INVALID_NUM;
6824 			break;
6825 		}
6826 		if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
6827 		{
6828 			break;
6829 		}
6830 	}
6831 
6832 	if (!is_catz_member && view->catzs != NULL &&
6833 	    dns_catz_zone_get(view->catzs, origin) != NULL)
6834 	{
6835 		zone_is_catz = true;
6836 	}
6837 
6838 	/*
6839 	 * See if we can reuse an existing zone.  This is
6840 	 * only possible if all of these are true:
6841 	 *   - The zone's view exists
6842 	 *   - A zone with the right name exists in the view
6843 	 *   - The zone is compatible with the config
6844 	 *     options (e.g., an existing primary zone cannot
6845 	 *     be reused if the options specify a secondary zone)
6846 	 *   - The zone was not and is still not a response policy zone
6847 	 *     or the zone is a policy zone with an unchanged number
6848 	 *     and we are using the old policy zone summary data.
6849 	 */
6850 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6851 				   view->rdclass, &pview);
6852 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6853 		goto cleanup;
6854 	}
6855 	if (pview != NULL) {
6856 		result = dns_view_findzone(pview, origin, DNS_ZTFIND_EXACT,
6857 					   &zone);
6858 	}
6859 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6860 		goto cleanup;
6861 	}
6862 
6863 	if (zone != NULL &&
6864 	    !named_zone_reusable(zone, zconfig, vconfig, config, kasplist))
6865 	{
6866 		dns_zone_detach(&zone);
6867 		fullsign = true;
6868 	}
6869 
6870 	if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
6871 			     (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
6872 	{
6873 		dns_zone_detach(&zone);
6874 	}
6875 
6876 	if (zone != NULL) {
6877 		/*
6878 		 * We found a reusable zone.  Make it use the
6879 		 * new view.
6880 		 */
6881 		dns_zone_setview(zone, view);
6882 	} else {
6883 		/*
6884 		 * We cannot reuse an existing zone, we have
6885 		 * to create a new one.
6886 		 */
6887 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6888 		CHECK(dns_zone_setorigin(zone, origin));
6889 		dns_zone_setview(zone, view);
6890 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6891 		dns_zone_setstats(zone, named_g_server->zonestats);
6892 	}
6893 	if (rpz_num != DNS_RPZ_INVALID_NUM) {
6894 		result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
6895 		if (result != ISC_R_SUCCESS) {
6896 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6897 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6898 				      "zone '%s': incompatible"
6899 				      " masterfile-format or database"
6900 				      " for a response policy zone",
6901 				      zname);
6902 			goto cleanup;
6903 		}
6904 	}
6905 
6906 	if (zone_is_catz) {
6907 		dns_zone_catz_enable(zone, view->catzs);
6908 	} else if (dns_zone_catz_is_enabled(zone)) {
6909 		dns_zone_catz_disable(zone);
6910 	}
6911 
6912 	/*
6913 	 * If the zone contains a 'forwarders' statement, configure
6914 	 * selective forwarding.
6915 	 */
6916 	forwarders = NULL;
6917 	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) {
6918 		forwardtype = NULL;
6919 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6920 		CHECK(configure_forward(config, view, origin, forwarders,
6921 					forwardtype));
6922 	}
6923 
6924 	/*
6925 	 * Mark whether the zone was originally added at runtime or not
6926 	 */
6927 	dns_zone_setadded(zone, added);
6928 
6929 	/*
6930 	 * Determine if we need to set up inline signing.
6931 	 */
6932 	zone_maybe_inline = (strcasecmp(ztypestr, "primary") == 0 ||
6933 			     strcasecmp(ztypestr, "master") == 0 ||
6934 			     strcasecmp(ztypestr, "secondary") == 0 ||
6935 			     strcasecmp(ztypestr, "slave") == 0);
6936 
6937 	if (zone_maybe_inline) {
6938 		inline_signing = named_zone_inlinesigning(zconfig, vconfig,
6939 							  config, kasplist);
6940 	}
6941 	if (inline_signing) {
6942 		dns_zone_getraw(zone, &raw);
6943 		if (raw == NULL) {
6944 			dns_zone_create(&raw, dns_zone_getmem(zone),
6945 					dns_zone_gettid(zone));
6946 			CHECK(dns_zone_setorigin(raw, origin));
6947 			dns_zone_setview(raw, view);
6948 			dns_zone_setstats(raw, named_g_server->zonestats);
6949 			CHECK(dns_zone_link(zone, raw));
6950 		}
6951 		if (cfg_map_get(zoptions, "ixfr-from-differences",
6952 				&ixfrfromdiffs) == ISC_R_SUCCESS)
6953 		{
6954 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6955 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6956 				      "zone '%s': 'ixfr-from-differences' is "
6957 				      "ignored for inline-signed zones",
6958 				      zname);
6959 		}
6960 	}
6961 
6962 	/*
6963 	 * Configure the zone.
6964 	 */
6965 	CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
6966 				   keystores, zone, raw));
6967 
6968 	/*
6969 	 * Add the zone to its view in the new view list.
6970 	 */
6971 	if (!modify) {
6972 		CHECK(dns_view_addzone(view, zone));
6973 	}
6974 
6975 	if (zone_is_catz) {
6976 		/*
6977 		 * force catz reload if the zone is loaded;
6978 		 * if it's not it'll get reloaded on zone load
6979 		 */
6980 		dns_db_t *db = NULL;
6981 
6982 		tresult = dns_zone_getdb(zone, &db);
6983 		if (tresult == ISC_R_SUCCESS) {
6984 			dns_catz_dbupdate_callback(db, view->catzs);
6985 			dns_db_detach(&db);
6986 		}
6987 	}
6988 
6989 	/*
6990 	 * Ensure that zone keys are reloaded on reconfig
6991 	 */
6992 	if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) {
6993 		dns_zone_rekey(zone, fullsign);
6994 	}
6995 
6996 cleanup:
6997 	if (zone != NULL) {
6998 		dns_zone_detach(&zone);
6999 	}
7000 	if (raw != NULL) {
7001 		dns_zone_detach(&raw);
7002 	}
7003 	if (pview != NULL) {
7004 		dns_view_detach(&pview);
7005 	}
7006 
7007 	return result;
7008 }
7009 
7010 /*
7011  * Configure built-in zone for storing managed-key data.
7012  */
7013 static isc_result_t
7014 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
7015 	isc_result_t result;
7016 	dns_view_t *pview = NULL;
7017 	dns_zone_t *zone = NULL;
7018 	dns_acl_t *none = NULL;
7019 	char filename[PATH_MAX];
7020 	bool defaultview;
7021 
7022 	REQUIRE(view != NULL);
7023 
7024 	/* See if we can re-use an existing keydata zone. */
7025 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
7026 				   view->rdclass, &pview);
7027 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
7028 		return result;
7029 	}
7030 
7031 	if (pview != NULL) {
7032 		if (pview->managed_keys != NULL) {
7033 			dns_zone_attach(pview->managed_keys,
7034 					&view->managed_keys);
7035 			dns_zone_setview(pview->managed_keys, view);
7036 			dns_zone_setviewcommit(pview->managed_keys);
7037 			dns_view_detach(&pview);
7038 			dns_zone_synckeyzone(view->managed_keys);
7039 			return ISC_R_SUCCESS;
7040 		}
7041 
7042 		dns_view_detach(&pview);
7043 	}
7044 
7045 	/* No existing keydata zone was found; create one */
7046 	CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
7047 	CHECK(dns_zone_setorigin(zone, dns_rootname));
7048 
7049 	defaultview = (strcmp(view->name, "_default") == 0);
7050 	CHECK(isc_file_sanitize(
7051 		directory, defaultview ? "managed-keys" : view->name,
7052 		defaultview ? "bind" : "mkeys", filename, sizeof(filename)));
7053 	CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text,
7054 			       &dns_master_style_default));
7055 
7056 	dns_zone_setview(zone, view);
7057 	dns_zone_settype(zone, dns_zone_key);
7058 	dns_zone_setclass(zone, view->rdclass);
7059 
7060 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
7061 
7062 	CHECK(dns_acl_none(mctx, &none));
7063 	dns_zone_setqueryacl(zone, none);
7064 	dns_zone_setqueryonacl(zone, none);
7065 	dns_acl_detach(&none);
7066 
7067 	dns_zone_setdialup(zone, dns_dialuptype_no);
7068 	dns_zone_setcheckdstype(zone, dns_checkdstype_no);
7069 	dns_zone_setnotifytype(zone, dns_notifytype_no);
7070 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
7071 	dns_zone_setjournalsize(zone, 0);
7072 
7073 	dns_zone_setstats(zone, named_g_server->zonestats);
7074 	setquerystats(zone, mctx, dns_zonestat_none);
7075 
7076 	if (view->managed_keys != NULL) {
7077 		dns_zone_detach(&view->managed_keys);
7078 	}
7079 	dns_zone_attach(zone, &view->managed_keys);
7080 
7081 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7082 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7083 		      "set up managed keys zone for view %s, file '%s'",
7084 		      view->name, filename);
7085 
7086 cleanup:
7087 	if (zone != NULL) {
7088 		dns_zone_detach(&zone);
7089 	}
7090 	if (none != NULL) {
7091 		dns_acl_detach(&none);
7092 	}
7093 
7094 	return result;
7095 }
7096 
7097 /*
7098  * Configure a single server quota.
7099  */
7100 static void
7101 configure_server_quota(const cfg_obj_t **maps, const char *name,
7102 		       isc_quota_t *quota) {
7103 	const cfg_obj_t *obj = NULL;
7104 	isc_result_t result;
7105 
7106 	result = named_config_get(maps, name, &obj);
7107 	INSIST(result == ISC_R_SUCCESS);
7108 	isc_quota_max(quota, cfg_obj_asuint32(obj));
7109 }
7110 
7111 /*
7112  * This function is called as soon as the 'directory' statement has been
7113  * parsed.  This can be extended to support other options if necessary.
7114  */
7115 static isc_result_t
7116 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
7117 	isc_result_t result;
7118 	const char *directory;
7119 
7120 	REQUIRE(strcasecmp("directory", clausename) == 0);
7121 
7122 	UNUSED(arg);
7123 	UNUSED(clausename);
7124 
7125 	/*
7126 	 * Change directory.
7127 	 */
7128 	directory = cfg_obj_asstring(obj);
7129 
7130 	if (!isc_file_ischdiridempotent(directory)) {
7131 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
7132 			    "option 'directory' contains relative path '%s'",
7133 			    directory);
7134 	}
7135 
7136 	if (!isc_file_isdirwritable(directory)) {
7137 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7138 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7139 			      "directory '%s' is not writable", directory);
7140 		return ISC_R_NOPERM;
7141 	}
7142 
7143 	result = isc_dir_chdir(directory);
7144 	if (result != ISC_R_SUCCESS) {
7145 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7146 			    "change directory to '%s' failed: %s", directory,
7147 			    isc_result_totext(result));
7148 		return result;
7149 	}
7150 
7151 	char cwd[PATH_MAX];
7152 	if (getcwd(cwd, sizeof(cwd)) == cwd) {
7153 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7154 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7155 			      "the working directory is now '%s'", cwd);
7156 	}
7157 
7158 	return ISC_R_SUCCESS;
7159 }
7160 
7161 /*
7162  * This event callback is invoked to do periodic network interface
7163  * scanning.
7164  */
7165 
7166 static void
7167 interface_timer_tick(void *arg) {
7168 	named_server_t *server = (named_server_t *)arg;
7169 
7170 	(void)ns_interfacemgr_scan(server->interfacemgr, false, false);
7171 }
7172 
7173 static void
7174 heartbeat_timer_tick(void *arg) {
7175 	named_server_t *server = (named_server_t *)arg;
7176 	dns_view_t *view = NULL;
7177 
7178 	view = ISC_LIST_HEAD(server->viewlist);
7179 	while (view != NULL) {
7180 		dns_view_dialup(view);
7181 		view = ISC_LIST_NEXT(view, link);
7182 	}
7183 }
7184 
7185 typedef struct {
7186 	isc_mem_t *mctx;
7187 	isc_loop_t *loop;
7188 	dns_fetch_t *fetch;
7189 	dns_view_t *view;
7190 	dns_fixedname_t tatname;
7191 	dns_fixedname_t keyname;
7192 	dns_rdataset_t rdataset;
7193 	dns_rdataset_t sigrdataset;
7194 } ns_tat_t;
7195 
7196 static int
7197 cid(const void *a, const void *b) {
7198 	const uint16_t ida = *(const uint16_t *)a;
7199 	const uint16_t idb = *(const uint16_t *)b;
7200 	if (ida < idb) {
7201 		return -1;
7202 	} else if (ida > idb) {
7203 		return 1;
7204 	} else {
7205 		return 0;
7206 	}
7207 }
7208 
7209 static void
7210 tat_done(void *arg) {
7211 	dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
7212 	ns_tat_t *tat = NULL;
7213 
7214 	INSIST(resp != NULL);
7215 
7216 	tat = resp->arg;
7217 
7218 	INSIST(tat != NULL);
7219 
7220 	/* Free resources which are not of interest */
7221 	if (resp->node != NULL) {
7222 		dns_db_detachnode(resp->db, &resp->node);
7223 	}
7224 	if (resp->db != NULL) {
7225 		dns_db_detach(&resp->db);
7226 	}
7227 	isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
7228 	dns_resolver_destroyfetch(&tat->fetch);
7229 	if (dns_rdataset_isassociated(&tat->rdataset)) {
7230 		dns_rdataset_disassociate(&tat->rdataset);
7231 	}
7232 	if (dns_rdataset_isassociated(&tat->sigrdataset)) {
7233 		dns_rdataset_disassociate(&tat->sigrdataset);
7234 	}
7235 	dns_view_detach(&tat->view);
7236 	isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
7237 }
7238 
7239 struct dotat_arg {
7240 	dns_view_t *view;
7241 	isc_loop_t *loop;
7242 };
7243 
7244 /*%
7245  * Prepare the QNAME for the TAT query to be sent by processing the trust
7246  * anchors present at 'keynode' of 'keytable'.  Store the result in 'dst' and
7247  * the domain name which 'keynode' is associated with in 'origin'.
7248  *
7249  * A maximum of 12 key IDs can be reported in a single TAT query due to the
7250  * 63-octet length limit for any single label in a domain name.  If there are
7251  * more than 12 keys configured at 'keynode', only the first 12 will be
7252  * reported in the TAT query.
7253  */
7254 static isc_result_t
7255 get_tat_qname(dns_name_t *target, dns_name_t *keyname, dns_keynode_t *keynode) {
7256 	dns_rdataset_t dsset;
7257 	unsigned int i, n = 0;
7258 	uint16_t ids[12];
7259 	isc_textregion_t r;
7260 	char label[64];
7261 	int m;
7262 
7263 	dns_rdataset_init(&dsset);
7264 	if (dns_keynode_dsset(keynode, &dsset)) {
7265 		isc_result_t result;
7266 
7267 		for (result = dns_rdataset_first(&dsset);
7268 		     result == ISC_R_SUCCESS;
7269 		     result = dns_rdataset_next(&dsset))
7270 		{
7271 			dns_rdata_t rdata = DNS_RDATA_INIT;
7272 			dns_rdata_ds_t ds;
7273 
7274 			dns_rdata_reset(&rdata);
7275 			dns_rdataset_current(&dsset, &rdata);
7276 			result = dns_rdata_tostruct(&rdata, &ds, NULL);
7277 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
7278 			if (n < (sizeof(ids) / sizeof(ids[0]))) {
7279 				ids[n] = ds.key_tag;
7280 				n++;
7281 			}
7282 		}
7283 		dns_rdataset_disassociate(&dsset);
7284 	}
7285 
7286 	if (n == 0) {
7287 		return DNS_R_EMPTYNAME;
7288 	}
7289 
7290 	if (n > 1) {
7291 		qsort(ids, n, sizeof(ids[0]), cid);
7292 	}
7293 
7294 	/*
7295 	 * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
7296 	 * of the keyid.
7297 	 */
7298 	label[0] = 0;
7299 	r.base = label;
7300 	r.length = sizeof(label);
7301 	m = snprintf(r.base, r.length, "_ta");
7302 	if (m < 0 || (unsigned int)m > r.length) {
7303 		return ISC_R_FAILURE;
7304 	}
7305 	isc_textregion_consume(&r, m);
7306 	for (i = 0; i < n; i++) {
7307 		m = snprintf(r.base, r.length, "-%04x", ids[i]);
7308 		if (m < 0 || (unsigned int)m > r.length) {
7309 			return ISC_R_FAILURE;
7310 		}
7311 		isc_textregion_consume(&r, m);
7312 	}
7313 
7314 	return dns_name_fromstring(target, label, keyname, 0, NULL);
7315 }
7316 
7317 static void
7318 tat_send(void *arg) {
7319 	ns_tat_t *tat = (ns_tat_t *)arg;
7320 	char namebuf[DNS_NAME_FORMATSIZE];
7321 	dns_fixedname_t fdomain;
7322 	dns_name_t *domain = NULL;
7323 	dns_rdataset_t nameservers;
7324 	isc_result_t result;
7325 	dns_name_t *keyname = NULL;
7326 	dns_name_t *tatname = NULL;
7327 
7328 	keyname = dns_fixedname_name(&tat->keyname);
7329 	tatname = dns_fixedname_name(&tat->tatname);
7330 
7331 	dns_name_format(tatname, namebuf, sizeof(namebuf));
7332 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7333 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7334 		      "%s: sending trust-anchor-telemetry query '%s/NULL'",
7335 		      tat->view->name, namebuf);
7336 
7337 	/*
7338 	 * TAT queries should be sent to the authoritative servers for a given
7339 	 * zone.  If this function is called for a keytable node corresponding
7340 	 * to a locally served zone, calling dns_resolver_createfetch() with
7341 	 * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be
7342 	 * resolved locally, without sending any TAT queries upstream.
7343 	 *
7344 	 * Work around this issue by calling dns_view_findzonecut() first.  If
7345 	 * the zone is served locally, the NS RRset for the given domain name
7346 	 * will be retrieved from local data; if it is not, the deepest zone
7347 	 * cut we have for it will be retrieved from cache.  In either case,
7348 	 * passing the results to dns_resolver_createfetch() will prevent it
7349 	 * from returning NXDOMAIN for 'tatname' while still allowing it to
7350 	 * chase down any potential delegations returned by upstream servers in
7351 	 * order to eventually find the destination host to send the TAT query
7352 	 * to.
7353 	 *
7354 	 * After the dns_view_findzonecut() call, 'domain' will hold the
7355 	 * deepest zone cut we can find for 'keyname' while 'nameservers' will
7356 	 * hold the NS RRset at that zone cut.
7357 	 */
7358 	domain = dns_fixedname_initname(&fdomain);
7359 	dns_rdataset_init(&nameservers);
7360 	result = dns_view_findzonecut(tat->view, keyname, domain, NULL, 0, 0,
7361 				      true, true, &nameservers, NULL);
7362 	if (result == ISC_R_SUCCESS) {
7363 		result = dns_resolver_createfetch(
7364 			tat->view->resolver, tatname, dns_rdatatype_null,
7365 			domain, &nameservers, NULL, NULL, 0, 0, 0, NULL,
7366 			tat->loop, tat_done, tat, &tat->rdataset,
7367 			&tat->sigrdataset, &tat->fetch);
7368 	}
7369 
7370 	/*
7371 	 * 'domain' holds the dns_name_t pointer inside a dst_key_t structure.
7372 	 * dns_resolver_createfetch() creates its own copy of 'domain' if it
7373 	 * succeeds.  Thus, 'domain' is not freed here.
7374 	 *
7375 	 * Even if dns_view_findzonecut() returned something else than
7376 	 * ISC_R_SUCCESS, it still could have associated 'nameservers'.
7377 	 * dns_resolver_createfetch() creates its own copy of 'nameservers' if
7378 	 * it succeeds.  Thus, we need to check whether 'nameservers' is
7379 	 * associated and release it if it is.
7380 	 */
7381 	if (dns_rdataset_isassociated(&nameservers)) {
7382 		dns_rdataset_disassociate(&nameservers);
7383 	}
7384 
7385 	if (result != ISC_R_SUCCESS) {
7386 		dns_view_detach(&tat->view);
7387 		isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
7388 	}
7389 }
7390 
7391 static void
7392 dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, dns_name_t *keyname,
7393       void *arg) {
7394 	struct dotat_arg *dotat_arg = (struct dotat_arg *)arg;
7395 	isc_result_t result;
7396 	dns_view_t *view = NULL;
7397 	ns_tat_t *tat = NULL;
7398 
7399 	REQUIRE(keytable != NULL);
7400 	REQUIRE(keynode != NULL);
7401 	REQUIRE(dotat_arg != NULL);
7402 
7403 	view = dotat_arg->view;
7404 
7405 	tat = isc_mem_get(view->mctx, sizeof(*tat));
7406 	*tat = (ns_tat_t){ 0 };
7407 
7408 	dns_rdataset_init(&tat->rdataset);
7409 	dns_rdataset_init(&tat->sigrdataset);
7410 	dns_name_copy(keyname, dns_fixedname_initname(&tat->keyname));
7411 	result = get_tat_qname(dns_fixedname_initname(&tat->tatname), keyname,
7412 			       keynode);
7413 	if (result != ISC_R_SUCCESS) {
7414 		isc_mem_put(view->mctx, tat, sizeof(*tat));
7415 		return;
7416 	}
7417 	isc_mem_attach(view->mctx, &tat->mctx);
7418 	tat->loop = dotat_arg->loop;
7419 	dns_view_attach(view, &tat->view);
7420 
7421 	/*
7422 	 * We don't want to be holding the keytable lock when calling
7423 	 * dns_view_findzonecut() as it creates a lock order loop so
7424 	 * call dns_view_findzonecut() in a event handler.
7425 	 *
7426 	 * zone->lock (dns_zone_setviewcommit) while holding view->lock
7427 	 * (dns_view_setviewcommit)
7428 	 *
7429 	 * keytable->lock (dns_keytable_find) while holding zone->lock
7430 	 * (zone_asyncload)
7431 	 *
7432 	 * view->lock (dns_view_findzonecut) while holding keytable->lock
7433 	 * (dns_keytable_forall)
7434 	 */
7435 	isc_async_run(named_g_mainloop, tat_send, tat);
7436 }
7437 
7438 static void
7439 tat_timer_tick(void *arg) {
7440 	isc_result_t result;
7441 	named_server_t *server = (named_server_t *)arg;
7442 	struct dotat_arg dotat_arg = { 0 };
7443 	dns_view_t *view = NULL;
7444 	dns_keytable_t *secroots = NULL;
7445 
7446 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
7447 	     view = ISC_LIST_NEXT(view, link))
7448 	{
7449 		if (!view->trust_anchor_telemetry || !view->enablevalidation) {
7450 			continue;
7451 		}
7452 
7453 		result = dns_view_getsecroots(view, &secroots);
7454 		if (result != ISC_R_SUCCESS) {
7455 			continue;
7456 		}
7457 
7458 		dotat_arg.view = view;
7459 		dotat_arg.loop = named_g_mainloop;
7460 		dns_keytable_forall(secroots, dotat, &dotat_arg);
7461 		dns_keytable_detach(&secroots);
7462 	}
7463 }
7464 
7465 static void
7466 pps_timer_tick(void *arg) {
7467 	static unsigned int oldrequests = 0;
7468 	unsigned int requests = atomic_load_relaxed(&ns_client_requests);
7469 
7470 	UNUSED(arg);
7471 
7472 	/*
7473 	 * Don't worry about wrapping as the overflow result will be right.
7474 	 */
7475 	dns_pps = (requests - oldrequests) / 1200;
7476 	oldrequests = requests;
7477 }
7478 
7479 /*
7480  * Replace the current value of '*field', a dynamically allocated
7481  * string or NULL, with a dynamically allocated copy of the
7482  * null-terminated string pointed to by 'value', or NULL.
7483  */
7484 static void
7485 setstring(named_server_t *server, char **field, const char *value) {
7486 	char *copy;
7487 
7488 	if (value != NULL) {
7489 		copy = isc_mem_strdup(server->mctx, value);
7490 	} else {
7491 		copy = NULL;
7492 	}
7493 
7494 	if (*field != NULL) {
7495 		isc_mem_free(server->mctx, *field);
7496 	}
7497 
7498 	*field = copy;
7499 }
7500 
7501 /*
7502  * Replace the current value of '*field', a dynamically allocated
7503  * string or NULL, with another dynamically allocated string
7504  * or NULL if whether 'obj' is a string or void value, respectively.
7505  */
7506 static void
7507 setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) {
7508 	if (cfg_obj_isvoid(obj)) {
7509 		setstring(server, field, NULL);
7510 	} else {
7511 		setstring(server, field, cfg_obj_asstring(obj));
7512 	}
7513 }
7514 
7515 static void
7516 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
7517 		 bool positive) {
7518 	const cfg_listelt_t *element;
7519 
7520 	for (element = cfg_list_first(ports); element != NULL;
7521 	     element = cfg_list_next(element))
7522 	{
7523 		const cfg_obj_t *obj = cfg_listelt_value(element);
7524 
7525 		if (cfg_obj_isuint32(obj)) {
7526 			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
7527 
7528 			if (positive) {
7529 				isc_portset_add(portset, port);
7530 			} else {
7531 				isc_portset_remove(portset, port);
7532 			}
7533 		} else {
7534 			const cfg_obj_t *obj_loport, *obj_hiport;
7535 			in_port_t loport, hiport;
7536 
7537 			obj_loport = cfg_tuple_get(obj, "loport");
7538 			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
7539 			obj_hiport = cfg_tuple_get(obj, "hiport");
7540 			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
7541 
7542 			if (positive) {
7543 				isc_portset_addrange(portset, loport, hiport);
7544 			} else {
7545 				isc_portset_removerange(portset, loport,
7546 							hiport);
7547 			}
7548 		}
7549 	}
7550 }
7551 
7552 static isc_result_t
7553 removed(dns_zone_t *zone, void *uap) {
7554 	if (dns_zone_getview(zone) != uap) {
7555 		return ISC_R_SUCCESS;
7556 	}
7557 
7558 	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed",
7559 		     dns_zonetype_name(dns_zone_gettype(zone)));
7560 	return ISC_R_SUCCESS;
7561 }
7562 
7563 static void
7564 cleanup_session_key(named_server_t *server, isc_mem_t *mctx) {
7565 	if (server->session_keyfile != NULL) {
7566 		isc_file_remove(server->session_keyfile);
7567 		isc_mem_free(mctx, server->session_keyfile);
7568 		server->session_keyfile = NULL;
7569 	}
7570 
7571 	if (server->session_keyname != NULL) {
7572 		if (dns_name_dynamic(server->session_keyname)) {
7573 			dns_name_free(server->session_keyname, mctx);
7574 		}
7575 		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
7576 		server->session_keyname = NULL;
7577 	}
7578 
7579 	if (server->sessionkey != NULL) {
7580 		dst_key_free(&server->sessionkey);
7581 	}
7582 
7583 	server->session_keyalg = DST_ALG_UNKNOWN;
7584 	server->session_keybits = 0;
7585 }
7586 
7587 static isc_result_t
7588 generate_session_key(const char *filename, const char *keynamestr,
7589 		     const dns_name_t *keyname, dst_algorithm_t alg,
7590 		     uint16_t bits, isc_mem_t *mctx, bool first_time,
7591 		     dst_key_t **keyp) {
7592 	isc_result_t result = ISC_R_SUCCESS;
7593 	dst_key_t *key = NULL;
7594 	isc_buffer_t key_txtbuffer;
7595 	isc_buffer_t key_rawbuffer;
7596 	char key_txtsecret[256];
7597 	char key_rawsecret[64];
7598 	isc_region_t key_rawregion;
7599 	FILE *fp = NULL;
7600 
7601 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7602 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7603 		      "generating session key for dynamic DNS");
7604 
7605 	/* generate key */
7606 	result = dst_key_generate(keyname, alg, bits, 1, 0, DNS_KEYPROTO_ANY,
7607 				  dns_rdataclass_in, NULL, mctx, &key, NULL);
7608 	if (result != ISC_R_SUCCESS) {
7609 		return result;
7610 	}
7611 
7612 	/*
7613 	 * Dump the key to the buffer for later use.
7614 	 */
7615 	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
7616 	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
7617 
7618 	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
7619 	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
7620 	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
7621 
7622 	/* Dump the key to the key file. */
7623 	fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time);
7624 	if (fp == NULL) {
7625 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7626 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7627 			      "could not create %s", filename);
7628 		result = ISC_R_NOPERM;
7629 		goto cleanup;
7630 	}
7631 
7632 	fprintf(fp,
7633 		"key \"%s\" {\n"
7634 		"\talgorithm %s;\n"
7635 		"\tsecret \"%.*s\";\n};\n",
7636 		keynamestr, dst_hmac_algorithm_totext(alg),
7637 		(int)isc_buffer_usedlength(&key_txtbuffer),
7638 		(char *)isc_buffer_base(&key_txtbuffer));
7639 
7640 	CHECK(isc_stdio_flush(fp));
7641 	result = isc_stdio_close(fp);
7642 	if (result != ISC_R_SUCCESS) {
7643 		goto cleanup;
7644 	}
7645 
7646 	*keyp = key;
7647 	return ISC_R_SUCCESS;
7648 
7649 cleanup:
7650 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7651 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7652 		      "failed to generate session key "
7653 		      "for dynamic DNS: %s",
7654 		      isc_result_totext(result));
7655 	if (fp != NULL) {
7656 		(void)isc_stdio_close(fp);
7657 		(void)isc_file_remove(filename);
7658 	}
7659 	if (key != NULL) {
7660 		dst_key_free(&key);
7661 	}
7662 
7663 	return result;
7664 }
7665 
7666 static isc_result_t
7667 configure_session_key(const cfg_obj_t **maps, named_server_t *server,
7668 		      isc_mem_t *mctx, bool first_time) {
7669 	const char *keyfile = NULL, *keynamestr = NULL, *algstr = NULL;
7670 	unsigned int algtype;
7671 	dns_fixedname_t fname;
7672 	dns_name_t *keyname = NULL;
7673 	isc_buffer_t buffer;
7674 	uint16_t bits;
7675 	const cfg_obj_t *obj = NULL;
7676 	bool need_deleteold = false;
7677 	bool need_createnew = false;
7678 	isc_result_t result;
7679 
7680 	obj = NULL;
7681 	result = named_config_get(maps, "session-keyfile", &obj);
7682 	if (result == ISC_R_SUCCESS) {
7683 		if (cfg_obj_isvoid(obj)) {
7684 			keyfile = NULL; /* disable it */
7685 		} else {
7686 			keyfile = cfg_obj_asstring(obj);
7687 		}
7688 	} else {
7689 		keyfile = named_g_defaultsessionkeyfile;
7690 	}
7691 
7692 	obj = NULL;
7693 	result = named_config_get(maps, "session-keyname", &obj);
7694 	INSIST(result == ISC_R_SUCCESS);
7695 	keynamestr = cfg_obj_asstring(obj);
7696 	isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
7697 	isc_buffer_add(&buffer, strlen(keynamestr));
7698 	keyname = dns_fixedname_initname(&fname);
7699 	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
7700 	if (result != ISC_R_SUCCESS) {
7701 		return result;
7702 	}
7703 
7704 	obj = NULL;
7705 	result = named_config_get(maps, "session-keyalg", &obj);
7706 	INSIST(result == ISC_R_SUCCESS);
7707 	algstr = cfg_obj_asstring(obj);
7708 	result = named_config_getkeyalgorithm(algstr, &algtype, &bits);
7709 	if (result != ISC_R_SUCCESS) {
7710 		const char *s = " (keeping current key)";
7711 
7712 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7713 			    "session-keyalg: "
7714 			    "unsupported or unknown algorithm '%s'%s",
7715 			    algstr, server->session_keyfile != NULL ? s : "");
7716 		return result;
7717 	}
7718 
7719 	/* See if we need to (re)generate a new key. */
7720 	if (keyfile == NULL) {
7721 		if (server->session_keyfile != NULL) {
7722 			need_deleteold = true;
7723 		}
7724 	} else if (server->session_keyfile == NULL) {
7725 		need_createnew = true;
7726 	} else if (strcmp(keyfile, server->session_keyfile) != 0 ||
7727 		   !dns_name_equal(server->session_keyname, keyname) ||
7728 		   server->session_keyalg != algtype ||
7729 		   server->session_keybits != bits)
7730 	{
7731 		need_deleteold = true;
7732 		need_createnew = true;
7733 	}
7734 
7735 	if (need_deleteold) {
7736 		INSIST(server->session_keyfile != NULL);
7737 		INSIST(server->session_keyname != NULL);
7738 		INSIST(server->sessionkey != NULL);
7739 
7740 		cleanup_session_key(server, mctx);
7741 	}
7742 
7743 	if (need_createnew) {
7744 		INSIST(server->sessionkey == NULL);
7745 		INSIST(server->session_keyfile == NULL);
7746 		INSIST(server->session_keyname == NULL);
7747 		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
7748 		INSIST(server->session_keybits == 0);
7749 
7750 		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
7751 		dns_name_init(server->session_keyname, NULL);
7752 		dns_name_dup(keyname, mctx, server->session_keyname);
7753 
7754 		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
7755 
7756 		server->session_keyalg = algtype;
7757 		server->session_keybits = bits;
7758 
7759 		CHECK(generate_session_key(keyfile, keynamestr, keyname,
7760 					   algtype, bits, mctx, first_time,
7761 					   &server->sessionkey));
7762 	}
7763 
7764 	return result;
7765 
7766 cleanup:
7767 	cleanup_session_key(server, mctx);
7768 	return result;
7769 }
7770 
7771 static isc_result_t
7772 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7773 	       cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx) {
7774 	isc_result_t result = ISC_R_SUCCESS;
7775 	bool allow = false;
7776 	ns_cfgctx_t *nzcfg = NULL;
7777 	const cfg_obj_t *maps[4];
7778 	const cfg_obj_t *options = NULL, *voptions = NULL;
7779 	const cfg_obj_t *nz = NULL;
7780 	const cfg_obj_t *nzdir = NULL;
7781 	const char *dir = NULL;
7782 	const cfg_obj_t *obj = NULL;
7783 	int i = 0;
7784 	uint64_t mapsize = 0ULL;
7785 
7786 	REQUIRE(config != NULL);
7787 
7788 	if (vconfig != NULL) {
7789 		voptions = cfg_tuple_get(vconfig, "options");
7790 	}
7791 	if (voptions != NULL) {
7792 		maps[i++] = voptions;
7793 	}
7794 	result = cfg_map_get(config, "options", &options);
7795 	if (result == ISC_R_SUCCESS) {
7796 		maps[i++] = options;
7797 	}
7798 	maps[i++] = named_g_defaults;
7799 	maps[i] = NULL;
7800 
7801 	result = named_config_get(maps, "allow-new-zones", &nz);
7802 	if (result == ISC_R_SUCCESS) {
7803 		allow = cfg_obj_asboolean(nz);
7804 	}
7805 	result = named_config_get(maps, "new-zones-directory", &nzdir);
7806 	if (result == ISC_R_SUCCESS) {
7807 		dir = cfg_obj_asstring(nzdir);
7808 		result = isc_file_isdirectory(dir);
7809 		if (result != ISC_R_SUCCESS) {
7810 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
7811 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7812 				      "invalid new-zones-directory %s: %s", dir,
7813 				      isc_result_totext(result));
7814 			return result;
7815 		}
7816 		if (!isc_file_isdirwritable(dir)) {
7817 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7818 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7819 				      "new-zones-directory '%s' "
7820 				      "is not writable",
7821 				      dir);
7822 			return ISC_R_NOPERM;
7823 		}
7824 
7825 		dns_view_setnewzonedir(view, dir);
7826 	}
7827 
7828 #ifdef HAVE_LMDB
7829 	result = named_config_get(maps, "lmdb-mapsize", &obj);
7830 	if (result == ISC_R_SUCCESS && obj != NULL) {
7831 		mapsize = cfg_obj_asuint64(obj);
7832 		if (mapsize < (1ULL << 20)) { /* 1 megabyte */
7833 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7834 				    "'lmdb-mapsize "
7835 				    "%" PRId64 "' "
7836 				    "is too small",
7837 				    mapsize);
7838 			return ISC_R_FAILURE;
7839 		} else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
7840 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7841 				    "'lmdb-mapsize "
7842 				    "%" PRId64 "' "
7843 				    "is too large",
7844 				    mapsize);
7845 			return ISC_R_FAILURE;
7846 		}
7847 	}
7848 #else  /* ifdef HAVE_LMDB */
7849 	UNUSED(obj);
7850 #endif /* HAVE_LMDB */
7851 
7852 	/*
7853 	 * A non-empty catalog-zones statement implies allow-new-zones
7854 	 */
7855 	if (!allow) {
7856 		const cfg_obj_t *cz = NULL;
7857 		result = named_config_get(maps, "catalog-zones", &cz);
7858 		if (result == ISC_R_SUCCESS) {
7859 			const cfg_listelt_t *e =
7860 				cfg_list_first(cfg_tuple_get(cz, "zone list"));
7861 			if (e != NULL) {
7862 				allow = true;
7863 			}
7864 		}
7865 	}
7866 
7867 	if (!allow) {
7868 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7869 		return ISC_R_SUCCESS;
7870 	}
7871 
7872 	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
7873 	*nzcfg = (ns_cfgctx_t){ 0 };
7874 
7875 	/*
7876 	 * We attach the parser that was used for config as well
7877 	 * as the one that will be used for added zones, to avoid
7878 	 * a shutdown race later.
7879 	 */
7880 	isc_mem_attach(view->mctx, &nzcfg->mctx);
7881 	cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
7882 	cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
7883 	cfg_aclconfctx_attach(actx, &nzcfg->actx);
7884 
7885 	result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy,
7886 				      mapsize);
7887 	if (result != ISC_R_SUCCESS) {
7888 		cfg_aclconfctx_detach(&nzcfg->actx);
7889 		cfg_parser_destroy(&nzcfg->add_parser);
7890 		cfg_parser_destroy(&nzcfg->conf_parser);
7891 		isc_mem_putanddetach(&nzcfg->mctx, nzcfg, sizeof(*nzcfg));
7892 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7893 		return result;
7894 	}
7895 
7896 	cfg_obj_attach(config, &nzcfg->config);
7897 	if (vconfig != NULL) {
7898 		cfg_obj_attach(vconfig, &nzcfg->vconfig);
7899 	}
7900 
7901 	result = load_nzf(view, nzcfg);
7902 	return result;
7903 }
7904 
7905 static void
7906 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
7907 			     dns_view_t *view) {
7908 	const char *zname;
7909 	dns_fixedname_t fixorigin;
7910 	dns_name_t *origin;
7911 	isc_result_t result2;
7912 	dns_view_t *pview = NULL;
7913 	dns_zone_t *zone = NULL;
7914 
7915 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
7916 	origin = dns_fixedname_initname(&fixorigin);
7917 
7918 	result2 = dns_name_fromstring(origin, zname, dns_rootname, 0, NULL);
7919 	if (result2 != ISC_R_SUCCESS) {
7920 		return;
7921 	}
7922 
7923 	result2 = dns_viewlist_find(&named_g_server->viewlist, view->name,
7924 				    view->rdclass, &pview);
7925 	if (result2 != ISC_R_SUCCESS) {
7926 		return;
7927 	}
7928 
7929 	result2 = dns_view_findzone(pview, origin, DNS_ZTFIND_EXACT, &zone);
7930 	if (result2 != ISC_R_SUCCESS) {
7931 		dns_view_detach(&pview);
7932 		return;
7933 	}
7934 
7935 	if (result == ISC_R_SUCCESS) {
7936 		dns_zone_setviewcommit(zone);
7937 	} else {
7938 		dns_zone_setviewrevert(zone);
7939 	}
7940 
7941 	dns_zone_detach(&zone);
7942 	dns_view_detach(&pview);
7943 }
7944 
7945 #ifndef HAVE_LMDB
7946 
7947 static isc_result_t
7948 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7949 		   cfg_aclconfctx_t *actx) {
7950 	isc_result_t result;
7951 	ns_cfgctx_t *nzctx;
7952 	const cfg_obj_t *zonelist;
7953 	const cfg_listelt_t *element;
7954 
7955 	nzctx = view->new_zone_config;
7956 	if (nzctx == NULL || nzctx->nzf_config == NULL) {
7957 		return ISC_R_SUCCESS;
7958 	}
7959 
7960 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7961 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7962 		      "loading additional zones for view '%s'", view->name);
7963 
7964 	zonelist = NULL;
7965 	cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
7966 
7967 	for (element = cfg_list_first(zonelist); element != NULL;
7968 	     element = cfg_list_next(element))
7969 	{
7970 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
7971 		CHECK(configure_zone(config, zconfig, vconfig, view,
7972 				     &named_g_server->viewlist,
7973 				     &named_g_server->kasplist,
7974 				     &named_g_server->keystorelist, actx, true,
7975 				     false, false, false));
7976 	}
7977 
7978 	result = ISC_R_SUCCESS;
7979 
7980 cleanup:
7981 	for (element = cfg_list_first(zonelist); element != NULL;
7982 	     element = cfg_list_next(element))
7983 	{
7984 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
7985 		configure_zone_setviewcommit(result, zconfig, view);
7986 	}
7987 
7988 	return result;
7989 }
7990 
7991 #else /* HAVE_LMDB */
7992 
7993 static isc_result_t
7994 data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text,
7995 	    cfg_obj_t **zoneconfig) {
7996 	isc_result_t result;
7997 	const char *zone_name;
7998 	size_t zone_name_len;
7999 	const char *zone_config;
8000 	size_t zone_config_len;
8001 	cfg_obj_t *zoneconf = NULL;
8002 	char bufname[DNS_NAME_FORMATSIZE];
8003 
8004 	REQUIRE(view != NULL);
8005 	REQUIRE(key != NULL);
8006 	REQUIRE(data != NULL);
8007 	REQUIRE(text != NULL);
8008 	REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
8009 
8010 	if (*text == NULL) {
8011 		isc_buffer_allocate(view->mctx, text, 256);
8012 	} else {
8013 		isc_buffer_clear(*text);
8014 	}
8015 
8016 	zone_name = (const char *)key->mv_data;
8017 	zone_name_len = key->mv_size;
8018 	INSIST(zone_name != NULL && zone_name_len > 0);
8019 
8020 	zone_config = (const char *)data->mv_data;
8021 	zone_config_len = data->mv_size;
8022 	INSIST(zone_config != NULL && zone_config_len > 0);
8023 
8024 	/* zone zonename { config; }; */
8025 	result = isc_buffer_reserve(*text, 6 + zone_name_len + 2 +
8026 						   zone_config_len + 2);
8027 	if (result != ISC_R_SUCCESS) {
8028 		goto cleanup;
8029 	}
8030 
8031 	CHECK(putstr(text, "zone \""));
8032 	CHECK(putmem(text, (const void *)zone_name, zone_name_len));
8033 	CHECK(putstr(text, "\" "));
8034 	CHECK(putmem(text, (const void *)zone_config, zone_config_len));
8035 	CHECK(putstr(text, ";\n"));
8036 
8037 	snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len,
8038 		 zone_name);
8039 
8040 	cfg_parser_reset(named_g_addparser);
8041 	result = cfg_parse_buffer(named_g_addparser, *text, bufname, 0,
8042 				  &cfg_type_addzoneconf, 0, &zoneconf);
8043 	if (result != ISC_R_SUCCESS) {
8044 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8045 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8046 			      "parsing config for zone '%.*s' in "
8047 			      "NZD database '%s' failed",
8048 			      (int)zone_name_len, zone_name, view->new_zone_db);
8049 		goto cleanup;
8050 	}
8051 
8052 	*zoneconfig = zoneconf;
8053 	zoneconf = NULL;
8054 	result = ISC_R_SUCCESS;
8055 
8056 cleanup:
8057 	if (zoneconf != NULL) {
8058 		cfg_obj_destroy(named_g_addparser, &zoneconf);
8059 	}
8060 
8061 	return result;
8062 }
8063 
8064 /*%
8065  * Prototype for a callback which can be used with for_all_newzone_cfgs().
8066  */
8067 typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
8068 					 cfg_obj_t *config, cfg_obj_t *vconfig,
8069 					 dns_view_t *view,
8070 					 cfg_aclconfctx_t *actx);
8071 
8072 /*%
8073  * For each zone found in a NZD opened by the caller, create an object
8074  * representing its configuration and invoke "callback" with the created
8075  * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all
8076  * these are non-global variables required to invoke configure_zone()).
8077  * Immediately interrupt processing if an error is encountered while
8078  * transforming NZD data into a zone configuration object or if "callback"
8079  * returns an error.
8080  *
8081  * Caller must hold 'view->new_zone_lock'.
8082  */
8083 static isc_result_t
8084 for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
8085 		     cfg_obj_t *vconfig, dns_view_t *view,
8086 		     cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi) {
8087 	const cfg_obj_t *zconfig, *zlist;
8088 	isc_result_t result = ISC_R_SUCCESS;
8089 	cfg_obj_t *zconfigobj = NULL;
8090 	isc_buffer_t *text = NULL;
8091 	MDB_cursor *cursor = NULL;
8092 	MDB_val data, key;
8093 	int status;
8094 
8095 	status = mdb_cursor_open(txn, dbi, &cursor);
8096 	if (status != MDB_SUCCESS) {
8097 		return ISC_R_FAILURE;
8098 	}
8099 
8100 	for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
8101 	     status == MDB_SUCCESS;
8102 	     status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
8103 	{
8104 		/*
8105 		 * Create a configuration object from data fetched from NZD.
8106 		 */
8107 		result = data_to_cfg(view, &key, &data, &text, &zconfigobj);
8108 		if (result != ISC_R_SUCCESS) {
8109 			break;
8110 		}
8111 
8112 		/*
8113 		 * Extract zone configuration from configuration object.
8114 		 */
8115 		zlist = NULL;
8116 		result = cfg_map_get(zconfigobj, "zone", &zlist);
8117 		if (result != ISC_R_SUCCESS) {
8118 			break;
8119 		} else if (!cfg_obj_islist(zlist)) {
8120 			result = ISC_R_FAILURE;
8121 			break;
8122 		}
8123 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
8124 
8125 		/*
8126 		 * Invoke callback.
8127 		 */
8128 		result = callback(zconfig, config, vconfig, view, actx);
8129 		if (result != ISC_R_SUCCESS) {
8130 			break;
8131 		}
8132 
8133 		/*
8134 		 * Destroy the configuration object created in this iteration.
8135 		 */
8136 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8137 	}
8138 
8139 	if (text != NULL) {
8140 		isc_buffer_free(&text);
8141 	}
8142 	if (zconfigobj != NULL) {
8143 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8144 	}
8145 	mdb_cursor_close(cursor);
8146 
8147 	return result;
8148 }
8149 
8150 /*%
8151  * Attempt to configure a zone found in NZD and return the result.
8152  */
8153 static isc_result_t
8154 configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
8155 		  cfg_obj_t *vconfig, dns_view_t *view,
8156 		  cfg_aclconfctx_t *actx) {
8157 	return configure_zone(
8158 		config, zconfig, vconfig, view, &named_g_server->viewlist,
8159 		&named_g_server->kasplist, &named_g_server->keystorelist, actx,
8160 		true, false, false, false);
8161 }
8162 
8163 /*%
8164  * Revert new view assignment for a zone found in NZD.
8165  */
8166 static isc_result_t
8167 configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config,
8168 			 cfg_obj_t *vconfig, dns_view_t *view,
8169 			 cfg_aclconfctx_t *actx) {
8170 	UNUSED(config);
8171 	UNUSED(vconfig);
8172 	UNUSED(actx);
8173 
8174 	configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view);
8175 
8176 	return ISC_R_SUCCESS;
8177 }
8178 
8179 static isc_result_t
8180 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
8181 		   cfg_aclconfctx_t *actx) {
8182 	isc_result_t result;
8183 	MDB_txn *txn = NULL;
8184 	MDB_dbi dbi;
8185 
8186 	if (view->new_zone_config == NULL) {
8187 		return ISC_R_SUCCESS;
8188 	}
8189 
8190 	LOCK(&view->new_zone_lock);
8191 
8192 	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
8193 	if (result != ISC_R_SUCCESS) {
8194 		UNLOCK(&view->new_zone_lock);
8195 		return ISC_R_SUCCESS;
8196 	}
8197 
8198 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8199 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8200 		      "loading NZD configs from '%s' "
8201 		      "for view '%s'",
8202 		      view->new_zone_db, view->name);
8203 
8204 	result = for_all_newzone_cfgs(configure_newzone, config, vconfig, view,
8205 				      actx, txn, dbi);
8206 	if (result != ISC_R_SUCCESS) {
8207 		/*
8208 		 * An error was encountered while attempting to configure zones
8209 		 * found in NZD.  As this error may have been caused by a
8210 		 * configure_zone() failure, try restoring a sane configuration
8211 		 * by reattaching all zones found in NZD to the old view.  If
8212 		 * this also fails, too bad, there is nothing more we can do in
8213 		 * terms of trying to make things right.
8214 		 */
8215 		(void)for_all_newzone_cfgs(configure_newzone_revert, config,
8216 					   vconfig, view, actx, txn, dbi);
8217 	}
8218 
8219 	(void)nzd_close(&txn, false);
8220 
8221 	UNLOCK(&view->new_zone_lock);
8222 
8223 	return result;
8224 }
8225 
8226 static isc_result_t
8227 get_newzone_config(dns_view_t *view, const char *zonename,
8228 		   cfg_obj_t **zoneconfig) {
8229 	isc_result_t result;
8230 	int status;
8231 	cfg_obj_t *zoneconf = NULL;
8232 	isc_buffer_t *text = NULL;
8233 	MDB_txn *txn = NULL;
8234 	MDB_dbi dbi;
8235 	MDB_val key, data;
8236 	char zname[DNS_NAME_FORMATSIZE];
8237 	dns_fixedname_t fname;
8238 	dns_name_t *name;
8239 	isc_buffer_t b;
8240 
8241 	INSIST(zoneconfig != NULL && *zoneconfig == NULL);
8242 
8243 	LOCK(&view->new_zone_lock);
8244 
8245 	CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
8246 
8247 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8248 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8249 		      "loading NZD config from '%s' "
8250 		      "for zone '%s'",
8251 		      view->new_zone_db, zonename);
8252 
8253 	/* Normalize zone name */
8254 	isc_buffer_constinit(&b, zonename, strlen(zonename));
8255 	isc_buffer_add(&b, strlen(zonename));
8256 	name = dns_fixedname_initname(&fname);
8257 	CHECK(dns_name_fromtext(name, &b, dns_rootname, DNS_NAME_DOWNCASE,
8258 				NULL));
8259 	dns_name_format(name, zname, sizeof(zname));
8260 
8261 	key.mv_data = zname;
8262 	key.mv_size = strlen(zname);
8263 
8264 	status = mdb_get(txn, dbi, &key, &data);
8265 	if (status != MDB_SUCCESS) {
8266 		CHECK(ISC_R_FAILURE);
8267 	}
8268 
8269 	CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
8270 
8271 	*zoneconfig = zoneconf;
8272 	zoneconf = NULL;
8273 	result = ISC_R_SUCCESS;
8274 
8275 cleanup:
8276 	(void)nzd_close(&txn, false);
8277 
8278 	UNLOCK(&view->new_zone_lock);
8279 
8280 	if (zoneconf != NULL) {
8281 		cfg_obj_destroy(named_g_addparser, &zoneconf);
8282 	}
8283 	if (text != NULL) {
8284 		isc_buffer_free(&text);
8285 	}
8286 
8287 	return result;
8288 }
8289 
8290 #endif /* HAVE_LMDB */
8291 
8292 static isc_result_t
8293 load_configuration(const char *filename, named_server_t *server,
8294 		   bool first_time) {
8295 	cfg_obj_t *config = NULL, *bindkeys = NULL;
8296 	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
8297 	const cfg_listelt_t *element;
8298 	const cfg_obj_t *builtin_views;
8299 	const cfg_obj_t *maps[3];
8300 	const cfg_obj_t *obj;
8301 	const cfg_obj_t *options;
8302 	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
8303 	const cfg_obj_t *kasps;
8304 	const cfg_obj_t *keystores;
8305 	dns_kasp_t *kasp = NULL;
8306 	dns_kasp_t *kasp_next = NULL;
8307 	dns_kasp_t *default_kasp = NULL;
8308 	dns_kasplist_t tmpkasplist, kasplist;
8309 	dns_keystore_t *keystore = NULL;
8310 	dns_keystore_t *keystore_next = NULL;
8311 	dns_keystorelist_t tmpkeystorelist, keystorelist;
8312 	const cfg_obj_t *views;
8313 
8314 	dns_view_t *view_next = NULL;
8315 	dns_viewlist_t tmpviewlist;
8316 	dns_viewlist_t viewlist, builtin_viewlist;
8317 	in_port_t listen_port, udpport_low, udpport_high;
8318 	int i, backlog;
8319 	isc_interval_t interval;
8320 	isc_logconfig_t *logc = NULL;
8321 	isc_portset_t *v4portset = NULL;
8322 	isc_portset_t *v6portset = NULL;
8323 	isc_result_t result;
8324 	uint32_t heartbeat_interval;
8325 	uint32_t interface_interval;
8326 	uint32_t udpsize;
8327 	uint32_t transfer_message_size;
8328 	uint32_t recv_tcp_buffer_size;
8329 	uint32_t send_tcp_buffer_size;
8330 	uint32_t recv_udp_buffer_size;
8331 	uint32_t send_udp_buffer_size;
8332 	named_cache_t *nsc;
8333 	named_cachelist_t cachelist, tmpcachelist;
8334 	ns_altsecret_t *altsecret;
8335 	ns_altsecretlist_t altsecrets, tmpaltsecrets;
8336 	uint32_t softquota = 0;
8337 	uint32_t max;
8338 	uint64_t initial, idle, keepalive, advertised;
8339 	bool loadbalancesockets;
8340 	bool exclusive = true;
8341 	dns_aclenv_t *env =
8342 		ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
8343 
8344 	/*
8345 	 * Require the reconfiguration to happen always on the main loop
8346 	 */
8347 	REQUIRE(isc_loop() == named_g_mainloop);
8348 
8349 	ISC_LIST_INIT(kasplist);
8350 	ISC_LIST_INIT(keystorelist);
8351 	ISC_LIST_INIT(viewlist);
8352 	ISC_LIST_INIT(builtin_viewlist);
8353 	ISC_LIST_INIT(cachelist);
8354 	ISC_LIST_INIT(altsecrets);
8355 
8356 	/* Ensure exclusive access to configuration data. */
8357 	isc_loopmgr_pause(named_g_loopmgr);
8358 
8359 	/* Create the ACL configuration context */
8360 	if (named_g_aclconfctx != NULL) {
8361 		cfg_aclconfctx_detach(&named_g_aclconfctx);
8362 	}
8363 	result = cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx);
8364 	if (result != ISC_R_SUCCESS) {
8365 		goto cleanup_exclusive;
8366 	}
8367 
8368 	/*
8369 	 * Shut down all dyndb instances.
8370 	 */
8371 	dns_dyndb_cleanup(false);
8372 
8373 	/*
8374 	 * Parse the global default pseudo-config file.
8375 	 */
8376 	if (first_time) {
8377 		result = named_config_parsedefaults(named_g_parser,
8378 						    &named_g_config);
8379 		if (result != ISC_R_SUCCESS) {
8380 			named_main_earlyfatal("unable to load "
8381 					      "internal defaults: %s",
8382 					      isc_result_totext(result));
8383 		}
8384 		RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
8385 					  &named_g_defaults) == ISC_R_SUCCESS);
8386 	}
8387 
8388 	/*
8389 	 * Log the current working directory.
8390 	 */
8391 	if (first_time) {
8392 		char cwd[PATH_MAX];
8393 		if (getcwd(cwd, sizeof(cwd)) == cwd) {
8394 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8395 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8396 				      "the initial working directory is '%s'",
8397 				      cwd);
8398 		}
8399 	}
8400 
8401 	/*
8402 	 * Parse the configuration file using the new config code.
8403 	 */
8404 	config = NULL;
8405 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8406 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8407 		      "loading configuration from '%s'", filename);
8408 	result = cfg_parser_create(named_g_mctx, named_g_lctx, &conf_parser);
8409 	if (result != ISC_R_SUCCESS) {
8410 		goto cleanup_exclusive;
8411 	}
8412 
8413 	cfg_parser_setcallback(conf_parser, directory_callback, NULL);
8414 	result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf,
8415 				&config);
8416 	if (result != ISC_R_SUCCESS) {
8417 		goto cleanup_conf_parser;
8418 	}
8419 
8420 	/*
8421 	 * Check the validity of the configuration.
8422 	 *
8423 	 * (Ignore plugin parameters for now; they will be
8424 	 * checked later when the modules are actually loaded and
8425 	 * registered.)
8426 	 */
8427 	result = isccfg_check_namedconf(config, BIND_CHECK_ALGORITHMS,
8428 					named_g_lctx, named_g_mctx);
8429 	if (result != ISC_R_SUCCESS) {
8430 		goto cleanup_config;
8431 	}
8432 
8433 	/* Let's recreate the TLS context cache */
8434 	if (server->tlsctx_server_cache != NULL) {
8435 		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
8436 	}
8437 
8438 	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_server_cache);
8439 
8440 	if (server->tlsctx_client_cache != NULL) {
8441 		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
8442 	}
8443 
8444 	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_client_cache);
8445 
8446 	dns_zonemgr_set_tlsctx_cache(server->zonemgr,
8447 				     server->tlsctx_client_cache);
8448 
8449 	/*
8450 	 * Fill in the maps array, used for resolving defaults.
8451 	 */
8452 	i = 0;
8453 	options = NULL;
8454 	result = cfg_map_get(config, "options", &options);
8455 	if (result == ISC_R_SUCCESS) {
8456 		maps[i++] = options;
8457 	}
8458 	maps[i++] = named_g_defaults;
8459 	maps[i] = NULL;
8460 
8461 #if HAVE_LIBNGHTTP2
8462 	obj = NULL;
8463 	result = named_config_get(maps, "http-port", &obj);
8464 	INSIST(result == ISC_R_SUCCESS);
8465 	named_g_httpport = (in_port_t)cfg_obj_asuint32(obj);
8466 
8467 	obj = NULL;
8468 	result = named_config_get(maps, "https-port", &obj);
8469 	INSIST(result == ISC_R_SUCCESS);
8470 	named_g_httpsport = (in_port_t)cfg_obj_asuint32(obj);
8471 
8472 	obj = NULL;
8473 	result = named_config_get(maps, "http-listener-clients", &obj);
8474 	INSIST(result == ISC_R_SUCCESS);
8475 	named_g_http_listener_clients = cfg_obj_asuint32(obj);
8476 
8477 	obj = NULL;
8478 	result = named_config_get(maps, "http-streams-per-connection", &obj);
8479 	INSIST(result == ISC_R_SUCCESS);
8480 	named_g_http_streams_per_conn = cfg_obj_asuint32(obj);
8481 #endif
8482 
8483 	/*
8484 	 * If "dnssec-validation auto" is turned on, the root key
8485 	 * will be used as a default trust anchor. The root key
8486 	 * is built in, but if bindkeys-file is set, then it will
8487 	 * be overridden with the key in that file.
8488 	 */
8489 	obj = NULL;
8490 	(void)named_config_get(maps, "bindkeys-file", &obj);
8491 	if (obj != NULL) {
8492 		setstring(server, &server->bindkeysfile, cfg_obj_asstring(obj));
8493 		INSIST(server->bindkeysfile != NULL);
8494 		if (access(server->bindkeysfile, R_OK) != 0) {
8495 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8496 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8497 				      "unable to open '%s'; using built-in "
8498 				      "keys instead",
8499 				      server->bindkeysfile);
8500 		} else {
8501 			result = cfg_parser_create(named_g_mctx, named_g_lctx,
8502 						   &bindkeys_parser);
8503 			if (result != ISC_R_SUCCESS) {
8504 				goto cleanup_config;
8505 			}
8506 
8507 			result = cfg_parse_file(bindkeys_parser,
8508 						server->bindkeysfile,
8509 						&cfg_type_bindkeys, &bindkeys);
8510 			if (result != ISC_R_SUCCESS) {
8511 				isc_log_write(
8512 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8513 					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8514 					"unable to parse '%s' "
8515 					"error '%s'; using "
8516 					"built-in keys instead",
8517 					server->bindkeysfile,
8518 					isc_result_totext(result));
8519 			}
8520 		}
8521 	} else {
8522 		setstring(server, &server->bindkeysfile, NULL);
8523 	}
8524 
8525 #if defined(HAVE_GEOIP2)
8526 	/*
8527 	 * Release any previously opened GeoIP2 databases.
8528 	 */
8529 	named_geoip_unload();
8530 
8531 	/*
8532 	 * Initialize GeoIP databases from the configured location.
8533 	 * This should happen before configuring any ACLs, so that we
8534 	 * know what databases are available and can reject any GeoIP
8535 	 * ACLs that can't work.
8536 	 */
8537 	obj = NULL;
8538 	result = named_config_get(maps, "geoip-directory", &obj);
8539 	INSIST(result == ISC_R_SUCCESS);
8540 	if (cfg_obj_isstring(obj)) {
8541 		char *dir = UNCONST(cfg_obj_asstring(obj));
8542 		named_geoip_load(dir);
8543 	}
8544 	named_g_aclconfctx->geoip = named_g_geoip;
8545 #endif /* HAVE_GEOIP2 */
8546 
8547 	/*
8548 	 * Configure various server options.
8549 	 */
8550 	configure_server_quota(maps, "transfers-out",
8551 			       &server->sctx->xfroutquota);
8552 	configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
8553 	configure_server_quota(maps, "recursive-clients",
8554 			       &server->sctx->recursionquota);
8555 	configure_server_quota(maps, "update-quota", &server->sctx->updquota);
8556 	configure_server_quota(maps, "sig0checks-quota",
8557 			       &server->sctx->sig0checksquota);
8558 
8559 	max = isc_quota_getmax(&server->sctx->recursionquota);
8560 	if (max > 1000) {
8561 		unsigned int margin = ISC_MAX(100, named_g_cpus + 1);
8562 		if (margin + 100 > max) {
8563 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8564 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8565 				      "'recursive-clients %d' too low when "
8566 				      "running with %d worker threads",
8567 				      max, named_g_cpus);
8568 			result = ISC_R_RANGE;
8569 
8570 			goto cleanup_bindkeys_parser;
8571 		}
8572 		softquota = max - margin;
8573 	} else {
8574 		softquota = (max * 90) / 100;
8575 	}
8576 	isc_quota_soft(&server->sctx->recursionquota, softquota);
8577 
8578 	obj = NULL;
8579 	result = named_config_get(maps, "sig0checks-quota-exempt", &obj);
8580 	if (result == ISC_R_SUCCESS) {
8581 		result = cfg_acl_fromconfig(
8582 			obj, config, named_g_lctx, named_g_aclconfctx,
8583 			named_g_mctx, 0, &server->sctx->sig0checksquota_exempt);
8584 		INSIST(result == ISC_R_SUCCESS);
8585 	}
8586 
8587 	/*
8588 	 * Set "blackhole". Only legal at options level; there is
8589 	 * no default.
8590 	 */
8591 	result = configure_view_acl(NULL, config, NULL, "blackhole", NULL,
8592 				    named_g_aclconfctx, named_g_mctx,
8593 				    &server->sctx->blackholeacl);
8594 	if (result != ISC_R_SUCCESS) {
8595 		goto cleanup_bindkeys_parser;
8596 	}
8597 
8598 	if (server->sctx->blackholeacl != NULL) {
8599 		dns_dispatchmgr_setblackhole(named_g_dispatchmgr,
8600 					     server->sctx->blackholeacl);
8601 	}
8602 
8603 	obj = NULL;
8604 	result = named_config_get(maps, "match-mapped-addresses", &obj);
8605 	INSIST(result == ISC_R_SUCCESS);
8606 	env->match_mapped = cfg_obj_asboolean(obj);
8607 
8608 	/*
8609 	 * Configure the network manager
8610 	 */
8611 	obj = NULL;
8612 	result = named_config_get(maps, "tcp-initial-timeout", &obj);
8613 	INSIST(result == ISC_R_SUCCESS);
8614 	initial = cfg_obj_asuint32(obj) * 100;
8615 	if (initial > MAX_INITIAL_TIMEOUT) {
8616 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8617 			    "tcp-initial-timeout value is out of range: "
8618 			    "lowering to %" PRIu32,
8619 			    MAX_INITIAL_TIMEOUT / 100);
8620 		initial = MAX_INITIAL_TIMEOUT;
8621 	} else if (initial < MIN_INITIAL_TIMEOUT) {
8622 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8623 			    "tcp-initial-timeout value is out of range: "
8624 			    "raising to %" PRIu32,
8625 			    MIN_INITIAL_TIMEOUT / 100);
8626 		initial = MIN_INITIAL_TIMEOUT;
8627 	}
8628 
8629 	obj = NULL;
8630 	result = named_config_get(maps, "tcp-idle-timeout", &obj);
8631 	INSIST(result == ISC_R_SUCCESS);
8632 	idle = cfg_obj_asuint32(obj) * 100;
8633 	if (idle > MAX_IDLE_TIMEOUT) {
8634 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8635 			    "tcp-idle-timeout value is out of range: "
8636 			    "lowering to %" PRIu32,
8637 			    MAX_IDLE_TIMEOUT / 100);
8638 		idle = MAX_IDLE_TIMEOUT;
8639 	} else if (idle < MIN_IDLE_TIMEOUT) {
8640 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8641 			    "tcp-idle-timeout value is out of range: "
8642 			    "raising to %" PRIu32,
8643 			    MIN_IDLE_TIMEOUT / 100);
8644 		idle = MIN_IDLE_TIMEOUT;
8645 	}
8646 
8647 	obj = NULL;
8648 	result = named_config_get(maps, "tcp-keepalive-timeout", &obj);
8649 	INSIST(result == ISC_R_SUCCESS);
8650 	keepalive = cfg_obj_asuint32(obj) * 100;
8651 	if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
8652 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8653 			    "tcp-keepalive-timeout value is out of range: "
8654 			    "lowering to %" PRIu32,
8655 			    MAX_KEEPALIVE_TIMEOUT / 100);
8656 		keepalive = MAX_KEEPALIVE_TIMEOUT;
8657 	} else if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
8658 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8659 			    "tcp-keepalive-timeout value is out of range: "
8660 			    "raising to %" PRIu32,
8661 			    MIN_KEEPALIVE_TIMEOUT / 100);
8662 		keepalive = MIN_KEEPALIVE_TIMEOUT;
8663 	}
8664 
8665 	obj = NULL;
8666 	result = named_config_get(maps, "tcp-advertised-timeout", &obj);
8667 	INSIST(result == ISC_R_SUCCESS);
8668 	advertised = cfg_obj_asuint32(obj) * 100;
8669 	if (advertised > MAX_ADVERTISED_TIMEOUT) {
8670 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8671 			    "tcp-advertized-timeout value is out of range: "
8672 			    "lowering to %" PRIu32,
8673 			    MAX_ADVERTISED_TIMEOUT / 100);
8674 		advertised = MAX_ADVERTISED_TIMEOUT;
8675 	}
8676 
8677 	isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
8678 			   advertised);
8679 
8680 #define CAP_IF_NOT_ZERO(v, min, max) \
8681 	if (v > 0 && v < min) {      \
8682 		v = min;             \
8683 	} else if (v > max) {        \
8684 		v = max;             \
8685 	}
8686 
8687 	/* Set the kernel send and receive buffer sizes */
8688 	obj = NULL;
8689 	result = named_config_get(maps, "tcp-receive-buffer", &obj);
8690 	INSIST(result == ISC_R_SUCCESS);
8691 	recv_tcp_buffer_size = cfg_obj_asuint32(obj);
8692 	CAP_IF_NOT_ZERO(recv_tcp_buffer_size, 4096, INT32_MAX);
8693 
8694 	obj = NULL;
8695 	result = named_config_get(maps, "tcp-send-buffer", &obj);
8696 	INSIST(result == ISC_R_SUCCESS);
8697 	send_tcp_buffer_size = cfg_obj_asuint32(obj);
8698 	CAP_IF_NOT_ZERO(send_tcp_buffer_size, 4096, INT32_MAX);
8699 
8700 	obj = NULL;
8701 	result = named_config_get(maps, "udp-receive-buffer", &obj);
8702 	INSIST(result == ISC_R_SUCCESS);
8703 	recv_udp_buffer_size = cfg_obj_asuint32(obj);
8704 	CAP_IF_NOT_ZERO(recv_udp_buffer_size, 4096, INT32_MAX);
8705 
8706 	obj = NULL;
8707 	result = named_config_get(maps, "udp-send-buffer", &obj);
8708 	INSIST(result == ISC_R_SUCCESS);
8709 	send_udp_buffer_size = cfg_obj_asuint32(obj);
8710 	CAP_IF_NOT_ZERO(send_udp_buffer_size, 4096, INT32_MAX);
8711 
8712 	isc_nm_setnetbuffers(named_g_netmgr, recv_tcp_buffer_size,
8713 			     send_tcp_buffer_size, recv_udp_buffer_size,
8714 			     send_udp_buffer_size);
8715 
8716 #undef CAP_IF_NOT_ZERO
8717 
8718 	/*
8719 	 * Configure sets of UDP query source ports.
8720 	 */
8721 	result = isc_portset_create(named_g_mctx, &v4portset);
8722 	if (result != ISC_R_SUCCESS) {
8723 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8724 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8725 			      "creating UDP/IPv4 port set: %s",
8726 			      isc_result_totext(result));
8727 		goto cleanup_bindkeys_parser;
8728 	}
8729 	result = isc_portset_create(named_g_mctx, &v6portset);
8730 	if (result != ISC_R_SUCCESS) {
8731 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8732 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8733 			      "creating UDP/IPv6 port set: %s",
8734 			      isc_result_totext(result));
8735 		goto cleanup_v4portset;
8736 	}
8737 
8738 	usev4ports = NULL;
8739 	usev6ports = NULL;
8740 	avoidv4ports = NULL;
8741 	avoidv6ports = NULL;
8742 
8743 	(void)named_config_get(maps, "use-v4-udp-ports", &usev4ports);
8744 	if (usev4ports != NULL) {
8745 		portset_fromconf(v4portset, usev4ports, true);
8746 	} else {
8747 		result = isc_net_getudpportrange(AF_INET, &udpport_low,
8748 						 &udpport_high);
8749 		if (result != ISC_R_SUCCESS) {
8750 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8751 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8752 				      "get the default UDP/IPv4 port range: %s",
8753 				      isc_result_totext(result));
8754 			goto cleanup_v6portset;
8755 		}
8756 
8757 		if (udpport_low == udpport_high) {
8758 			isc_portset_add(v4portset, udpport_low);
8759 		} else {
8760 			isc_portset_addrange(v4portset, udpport_low,
8761 					     udpport_high);
8762 		}
8763 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) {
8764 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8765 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8766 				      "using default UDP/IPv4 port range: "
8767 				      "[%d, %d]",
8768 				      udpport_low, udpport_high);
8769 		}
8770 	}
8771 	(void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
8772 	if (avoidv4ports != NULL) {
8773 		portset_fromconf(v4portset, avoidv4ports, false);
8774 	}
8775 
8776 	(void)named_config_get(maps, "use-v6-udp-ports", &usev6ports);
8777 	if (usev6ports != NULL) {
8778 		portset_fromconf(v6portset, usev6ports, true);
8779 	} else {
8780 		result = isc_net_getudpportrange(AF_INET6, &udpport_low,
8781 						 &udpport_high);
8782 		if (result != ISC_R_SUCCESS) {
8783 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8784 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8785 				      "get the default UDP/IPv6 port range: %s",
8786 				      isc_result_totext(result));
8787 			goto cleanup_v6portset;
8788 		}
8789 		if (udpport_low == udpport_high) {
8790 			isc_portset_add(v6portset, udpport_low);
8791 		} else {
8792 			isc_portset_addrange(v6portset, udpport_low,
8793 					     udpport_high);
8794 		}
8795 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) {
8796 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8797 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8798 				      "using default UDP/IPv6 port range: "
8799 				      "[%d, %d]",
8800 				      udpport_low, udpport_high);
8801 		}
8802 	}
8803 	(void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
8804 	if (avoidv6ports != NULL) {
8805 		portset_fromconf(v6portset, avoidv6ports, false);
8806 	}
8807 
8808 	dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset,
8809 				      v6portset);
8810 
8811 	/*
8812 	 * Set the EDNS UDP size when we don't match a view.
8813 	 */
8814 	obj = NULL;
8815 	result = named_config_get(maps, "edns-udp-size", &obj);
8816 	INSIST(result == ISC_R_SUCCESS);
8817 	udpsize = cfg_obj_asuint32(obj);
8818 	if (udpsize < 512) {
8819 		udpsize = 512;
8820 	}
8821 	if (udpsize > 4096) {
8822 		udpsize = 4096;
8823 	}
8824 	server->sctx->udpsize = (uint16_t)udpsize;
8825 
8826 	/* Set the transfer message size for TCP */
8827 	obj = NULL;
8828 	result = named_config_get(maps, "transfer-message-size", &obj);
8829 	INSIST(result == ISC_R_SUCCESS);
8830 	transfer_message_size = cfg_obj_asuint32(obj);
8831 	if (transfer_message_size < 512) {
8832 		transfer_message_size = 512;
8833 	} else if (transfer_message_size > 65535) {
8834 		transfer_message_size = 65535;
8835 	}
8836 	server->sctx->transfer_tcp_message_size =
8837 		(uint16_t)transfer_message_size;
8838 
8839 	/*
8840 	 * Configure the zone manager.
8841 	 */
8842 	obj = NULL;
8843 	result = named_config_get(maps, "transfers-in", &obj);
8844 	INSIST(result == ISC_R_SUCCESS);
8845 	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
8846 
8847 	obj = NULL;
8848 	result = named_config_get(maps, "transfers-per-ns", &obj);
8849 	INSIST(result == ISC_R_SUCCESS);
8850 	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
8851 
8852 	obj = NULL;
8853 	result = named_config_get(maps, "notify-rate", &obj);
8854 	INSIST(result == ISC_R_SUCCESS);
8855 	dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
8856 
8857 	obj = NULL;
8858 	result = named_config_get(maps, "startup-notify-rate", &obj);
8859 	INSIST(result == ISC_R_SUCCESS);
8860 	dns_zonemgr_setstartupnotifyrate(server->zonemgr,
8861 					 cfg_obj_asuint32(obj));
8862 
8863 	obj = NULL;
8864 	result = named_config_get(maps, "serial-query-rate", &obj);
8865 	INSIST(result == ISC_R_SUCCESS);
8866 	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
8867 
8868 	/*
8869 	 * Determine which port to use for listening for incoming connections.
8870 	 */
8871 	if (named_g_port != 0) {
8872 		listen_port = named_g_port;
8873 	} else {
8874 		result = named_config_getport(config, "port", &listen_port);
8875 		if (result != ISC_R_SUCCESS) {
8876 			goto cleanup_v6portset;
8877 		}
8878 	}
8879 
8880 	/*
8881 	 * Find the listen queue depth.
8882 	 */
8883 	obj = NULL;
8884 	result = named_config_get(maps, "tcp-listen-queue", &obj);
8885 	INSIST(result == ISC_R_SUCCESS);
8886 	backlog = cfg_obj_asuint32(obj);
8887 	if ((backlog > 0) && (backlog < 10)) {
8888 		backlog = 10;
8889 	}
8890 	ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
8891 
8892 	obj = NULL;
8893 	result = named_config_get(maps, "reuseport", &obj);
8894 	INSIST(result == ISC_R_SUCCESS);
8895 	loadbalancesockets = cfg_obj_asboolean(obj);
8896 #if HAVE_SO_REUSEPORT_LB
8897 	if (first_time) {
8898 		isc_nm_setloadbalancesockets(named_g_netmgr,
8899 					     cfg_obj_asboolean(obj));
8900 	} else if (loadbalancesockets !=
8901 		   isc_nm_getloadbalancesockets(named_g_netmgr))
8902 	{
8903 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8904 			    "changing reuseport value requires server restart");
8905 	}
8906 #else
8907 	if (loadbalancesockets) {
8908 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8909 			    "reuseport has no effect on this system");
8910 	}
8911 #endif
8912 
8913 	/*
8914 	 * Configure the interface manager according to the "listen-on"
8915 	 * statement.
8916 	 */
8917 	{
8918 		const cfg_obj_t *clistenon = NULL;
8919 		ns_listenlist_t *listenon = NULL;
8920 
8921 		/*
8922 		 * Even though listen-on is present in the default
8923 		 * configuration, this way is easier.
8924 		 */
8925 		if (options != NULL) {
8926 			(void)cfg_map_get(options, "listen-on", &clistenon);
8927 		}
8928 		if (clistenon != NULL) {
8929 			result = listenlist_fromconfig(
8930 				clistenon, config, named_g_aclconfctx,
8931 				named_g_mctx, AF_INET,
8932 				server->tlsctx_server_cache, &listenon);
8933 		} else {
8934 			/*
8935 			 * Not specified, use default.
8936 			 */
8937 			result = ns_listenlist_default(named_g_mctx,
8938 						       listen_port, true,
8939 						       AF_INET, &listenon);
8940 		}
8941 		if (result != ISC_R_SUCCESS) {
8942 			goto cleanup_v6portset;
8943 		}
8944 
8945 		if (listenon != NULL) {
8946 			ns_interfacemgr_setlistenon4(server->interfacemgr,
8947 						     listenon);
8948 			ns_listenlist_detach(&listenon);
8949 		}
8950 	}
8951 
8952 	/*
8953 	 * Ditto for IPv6.
8954 	 */
8955 	{
8956 		const cfg_obj_t *clistenon = NULL;
8957 		ns_listenlist_t *listenon = NULL;
8958 
8959 		if (options != NULL) {
8960 			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
8961 		}
8962 		if (clistenon != NULL) {
8963 			result = listenlist_fromconfig(
8964 				clistenon, config, named_g_aclconfctx,
8965 				named_g_mctx, AF_INET6,
8966 				server->tlsctx_server_cache, &listenon);
8967 		} else {
8968 			/*
8969 			 * Not specified, use default.
8970 			 */
8971 			result = ns_listenlist_default(named_g_mctx,
8972 						       listen_port, true,
8973 						       AF_INET6, &listenon);
8974 		}
8975 		if (result != ISC_R_SUCCESS) {
8976 			goto cleanup_v6portset;
8977 		}
8978 		if (listenon != NULL) {
8979 			ns_interfacemgr_setlistenon6(server->interfacemgr,
8980 						     listenon);
8981 			ns_listenlist_detach(&listenon);
8982 		}
8983 	}
8984 
8985 	if (first_time) {
8986 		/*
8987 		 * Rescan the interface list to pick up changes in the
8988 		 * listen-on option. This requires the loopmgr to be
8989 		 * temporarily resumed.
8990 		 */
8991 		isc_loopmgr_resume(named_g_loopmgr);
8992 		result = ns_interfacemgr_scan(server->interfacemgr, true, true);
8993 		isc_loopmgr_pause(named_g_loopmgr);
8994 
8995 		/*
8996 		 * Check that named is able to TCP listen on at least one
8997 		 * interface. Otherwise, another named process could be running
8998 		 * and we should fail.
8999 		 */
9000 		if (result == ISC_R_ADDRINUSE) {
9001 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9002 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9003 				      "unable to listen on any configured "
9004 				      "interfaces");
9005 			result = ISC_R_FAILURE;
9006 			goto cleanup_v6portset;
9007 		}
9008 	}
9009 
9010 	/*
9011 	 * Arrange for further interface scanning to occur periodically
9012 	 * as specified by the "interface-interval" option.
9013 	 */
9014 	obj = NULL;
9015 	result = named_config_get(maps, "interface-interval", &obj);
9016 	INSIST(result == ISC_R_SUCCESS);
9017 	interface_interval = cfg_obj_asduration(obj);
9018 	server->interface_interval = interface_interval;
9019 
9020 	/*
9021 	 * Enable automatic interface scans.
9022 	 */
9023 	obj = NULL;
9024 	result = named_config_get(maps, "automatic-interface-scan", &obj);
9025 	INSIST(result == ISC_R_SUCCESS);
9026 	server->sctx->interface_auto = cfg_obj_asboolean(obj);
9027 
9028 	if (server->sctx->interface_auto) {
9029 		if (ns_interfacemgr_dynamic_updates_are_reliable() &&
9030 		    server->interface_interval != 0)
9031 		{
9032 			/*
9033 			 * In some cases the user might expect a certain
9034 			 * behaviour from the rescan timer, let's try to deduce
9035 			 * that from the configuration options.
9036 			 */
9037 			isc_log_write(
9038 				named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9039 				NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9040 				"Disabling periodic interface re-scans timer");
9041 			server->interface_interval = 0;
9042 		}
9043 
9044 		ns_interfacemgr_routeconnect(server->interfacemgr);
9045 	} else {
9046 		ns_interfacemgr_routedisconnect(server->interfacemgr);
9047 	}
9048 
9049 	if (server->interface_interval == 0) {
9050 		isc_timer_stop(server->interface_timer);
9051 	} else {
9052 		isc_interval_set(&interval, interface_interval, 0);
9053 		isc_timer_start(server->interface_timer, isc_timertype_ticker,
9054 				&interval);
9055 	}
9056 
9057 	/*
9058 	 * Configure the dialup heartbeat timer.
9059 	 */
9060 	obj = NULL;
9061 	result = named_config_get(maps, "heartbeat-interval", &obj);
9062 	INSIST(result == ISC_R_SUCCESS);
9063 	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
9064 	if (heartbeat_interval == 0) {
9065 		isc_timer_stop(server->heartbeat_timer);
9066 	} else if (server->heartbeat_interval != heartbeat_interval) {
9067 		isc_interval_set(&interval, heartbeat_interval, 0);
9068 		isc_timer_start(server->heartbeat_timer, isc_timertype_ticker,
9069 				&interval);
9070 	}
9071 	server->heartbeat_interval = heartbeat_interval;
9072 
9073 	isc_interval_set(&interval, 1200, 0);
9074 	isc_timer_start(server->pps_timer, isc_timertype_ticker, &interval);
9075 
9076 	isc_interval_set(&interval, named_g_tat_interval, 0);
9077 	isc_timer_start(server->tat_timer, isc_timertype_ticker, &interval);
9078 
9079 	/*
9080 	 * Write the PID file.
9081 	 */
9082 	obj = NULL;
9083 	if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) {
9084 		if (cfg_obj_isvoid(obj)) {
9085 			named_os_writepidfile(NULL, first_time);
9086 		} else {
9087 			named_os_writepidfile(cfg_obj_asstring(obj),
9088 					      first_time);
9089 		}
9090 	} else {
9091 		named_os_writepidfile(named_g_defaultpidfile, first_time);
9092 	}
9093 
9094 	/*
9095 	 * Configure the server-wide session key.  This must be done before
9096 	 * configure views because zone configuration may need to know
9097 	 * session-keyname.
9098 	 *
9099 	 * Failure of session key generation isn't fatal at this time; if it
9100 	 * turns out that a session key is really needed but doesn't exist,
9101 	 * we'll treat it as a fatal error then.
9102 	 */
9103 	(void)configure_session_key(maps, server, named_g_mctx, first_time);
9104 
9105 	/*
9106 	 * Create the built-in key store ("key-directory").
9107 	 */
9108 	result = cfg_keystore_fromconfig(NULL, named_g_mctx, named_g_lctx,
9109 					 named_g_engine, &keystorelist, NULL);
9110 	if (result != ISC_R_SUCCESS) {
9111 		goto cleanup_keystorelist;
9112 	}
9113 
9114 	/*
9115 	 * Create the DNSSEC key stores.
9116 	 */
9117 	keystores = NULL;
9118 	(void)cfg_map_get(config, "key-store", &keystores);
9119 	for (element = cfg_list_first(keystores); element != NULL;
9120 	     element = cfg_list_next(element))
9121 	{
9122 		cfg_obj_t *kconfig = cfg_listelt_value(element);
9123 		keystore = NULL;
9124 		result = cfg_keystore_fromconfig(kconfig, named_g_mctx,
9125 						 named_g_lctx, named_g_engine,
9126 						 &keystorelist, NULL);
9127 		if (result != ISC_R_SUCCESS) {
9128 			goto cleanup_keystorelist;
9129 		}
9130 	}
9131 
9132 	/*
9133 	 * Create the built-in kasp policies ("default", "insecure").
9134 	 */
9135 	kasps = NULL;
9136 	(void)cfg_map_get(named_g_config, "dnssec-policy", &kasps);
9137 	for (element = cfg_list_first(kasps); element != NULL;
9138 	     element = cfg_list_next(element))
9139 	{
9140 		cfg_obj_t *kconfig = cfg_listelt_value(element);
9141 
9142 		kasp = NULL;
9143 		result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
9144 					     named_g_mctx, named_g_lctx,
9145 					     &keystorelist, &kasplist, &kasp);
9146 		if (result != ISC_R_SUCCESS) {
9147 			goto cleanup_kasplist;
9148 		}
9149 		INSIST(kasp != NULL);
9150 		dns_kasp_freeze(kasp);
9151 
9152 		/* Insist that the first built-in policy is the default one. */
9153 		if (default_kasp == NULL) {
9154 			INSIST(strcmp(dns_kasp_getname(kasp), "default") == 0);
9155 			dns_kasp_attach(kasp, &default_kasp);
9156 		}
9157 
9158 		dns_kasp_detach(&kasp);
9159 	}
9160 	INSIST(default_kasp != NULL);
9161 
9162 	/*
9163 	 * Create the DNSSEC key and signing policies (KASP).
9164 	 */
9165 	kasps = NULL;
9166 	(void)cfg_map_get(config, "dnssec-policy", &kasps);
9167 	for (element = cfg_list_first(kasps); element != NULL;
9168 	     element = cfg_list_next(element))
9169 	{
9170 		cfg_obj_t *kconfig = cfg_listelt_value(element);
9171 		kasp = NULL;
9172 		result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
9173 					     named_g_mctx, named_g_lctx,
9174 					     &keystorelist, &kasplist, &kasp);
9175 		if (result != ISC_R_SUCCESS) {
9176 			goto cleanup_kasplist;
9177 		}
9178 		INSIST(kasp != NULL);
9179 		dns_kasp_freeze(kasp);
9180 		dns_kasp_detach(&kasp);
9181 	}
9182 	dns_kasp_detach(&default_kasp);
9183 
9184 	/*
9185 	 * Save keystore list and kasp list.
9186 	 */
9187 	tmpkeystorelist = server->keystorelist;
9188 	server->keystorelist = keystorelist;
9189 	keystorelist = tmpkeystorelist;
9190 
9191 	tmpkasplist = server->kasplist;
9192 	server->kasplist = kasplist;
9193 	kasplist = tmpkasplist;
9194 
9195 #ifdef USE_DNSRPS
9196 	/*
9197 	 * Find the path to the DNSRPS implementation library.
9198 	 */
9199 	obj = NULL;
9200 	if (named_config_get(maps, "dnsrps-library", &obj) == ISC_R_SUCCESS) {
9201 		if (server->dnsrpslib != NULL) {
9202 			dns_dnsrps_server_destroy();
9203 			isc_mem_free(server->mctx, server->dnsrpslib);
9204 			server->dnsrpslib = NULL;
9205 		}
9206 		setstring(server, &server->dnsrpslib, cfg_obj_asstring(obj));
9207 		result = dns_dnsrps_server_create(server->dnsrpslib);
9208 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9209 			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9210 			      "initializing DNSRPS RPZ provider '%s': %s",
9211 			      server->dnsrpslib, isc_result_totext(result));
9212 		/*
9213 		 * It's okay if librpz isn't available. We'll complain
9214 		 * later if it turns out to be needed for a view with
9215 		 * "dnsrps-enable yes".
9216 		 */
9217 		if (result == ISC_R_FILENOTFOUND) {
9218 			result = ISC_R_SUCCESS;
9219 		}
9220 		CHECKFATAL(result, "initializing RPZ service interface");
9221 	}
9222 #endif /* ifdef USE_DNSRPS */
9223 
9224 	/*
9225 	 * Configure the views.
9226 	 */
9227 	views = NULL;
9228 	(void)cfg_map_get(config, "view", &views);
9229 
9230 	/*
9231 	 * Create the views.
9232 	 */
9233 	for (element = cfg_list_first(views); element != NULL;
9234 	     element = cfg_list_next(element))
9235 	{
9236 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9237 		dns_view_t *view = NULL;
9238 
9239 		result = create_view(vconfig, &viewlist, &view);
9240 		if (result != ISC_R_SUCCESS) {
9241 			goto cleanup_viewlist;
9242 		}
9243 		INSIST(view != NULL);
9244 
9245 		result = setup_newzones(view, config, vconfig, conf_parser,
9246 					named_g_aclconfctx);
9247 		dns_view_detach(&view);
9248 
9249 		if (result != ISC_R_SUCCESS) {
9250 			goto cleanup_viewlist;
9251 		}
9252 	}
9253 
9254 	/*
9255 	 * If there were no explicit views then we do the default
9256 	 * view here.
9257 	 */
9258 	if (views == NULL) {
9259 		dns_view_t *view = NULL;
9260 
9261 		result = create_view(NULL, &viewlist, &view);
9262 		if (result != ISC_R_SUCCESS) {
9263 			goto cleanup_viewlist;
9264 		}
9265 		INSIST(view != NULL);
9266 
9267 		result = setup_newzones(view, config, NULL, conf_parser,
9268 					named_g_aclconfctx);
9269 
9270 		dns_view_detach(&view);
9271 		if (result != ISC_R_SUCCESS) {
9272 			goto cleanup_viewlist;
9273 		}
9274 	}
9275 
9276 	/*
9277 	 * Configure and freeze all explicit views.  Explicit
9278 	 * views that have zones were already created at parsing
9279 	 * time, but views with no zones must be created here.
9280 	 */
9281 	for (element = cfg_list_first(views); element != NULL;
9282 	     element = cfg_list_next(element))
9283 	{
9284 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9285 		dns_view_t *view = NULL;
9286 
9287 		view = NULL;
9288 		result = find_view(vconfig, &viewlist, &view);
9289 		if (result != ISC_R_SUCCESS) {
9290 			goto cleanup_cachelist;
9291 		}
9292 
9293 		result = configure_view(view, &viewlist, config, vconfig,
9294 					&cachelist, &server->kasplist,
9295 					&server->keystorelist, bindkeys,
9296 					named_g_mctx, named_g_aclconfctx, true);
9297 		if (result != ISC_R_SUCCESS) {
9298 			dns_view_detach(&view);
9299 			goto cleanup_cachelist;
9300 		}
9301 		dns_view_freeze(view);
9302 		dns_view_detach(&view);
9303 	}
9304 
9305 	/*
9306 	 * Make sure we have a default view if and only if there
9307 	 * were no explicit views.
9308 	 */
9309 	if (views == NULL) {
9310 		dns_view_t *view = NULL;
9311 		result = find_view(NULL, &viewlist, &view);
9312 		if (result != ISC_R_SUCCESS) {
9313 			goto cleanup_cachelist;
9314 		}
9315 		result = configure_view(view, &viewlist, config, NULL,
9316 					&cachelist, &server->kasplist,
9317 					&server->keystorelist, bindkeys,
9318 					named_g_mctx, named_g_aclconfctx, true);
9319 		if (result != ISC_R_SUCCESS) {
9320 			dns_view_detach(&view);
9321 			goto cleanup_cachelist;
9322 		}
9323 		dns_view_freeze(view);
9324 		dns_view_detach(&view);
9325 	}
9326 
9327 	/*
9328 	 * Create (or recreate) the built-in views.
9329 	 */
9330 	builtin_views = NULL;
9331 	RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) ==
9332 		      ISC_R_SUCCESS);
9333 	for (element = cfg_list_first(builtin_views); element != NULL;
9334 	     element = cfg_list_next(element))
9335 	{
9336 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9337 		dns_view_t *view = NULL;
9338 
9339 		result = create_view(vconfig, &builtin_viewlist, &view);
9340 		if (result != ISC_R_SUCCESS) {
9341 			goto cleanup_cachelist;
9342 		}
9343 
9344 		result = configure_view(
9345 			view, &viewlist, config, vconfig, &cachelist,
9346 			&server->kasplist, &server->keystorelist, bindkeys,
9347 			named_g_mctx, named_g_aclconfctx, false);
9348 		if (result != ISC_R_SUCCESS) {
9349 			dns_view_detach(&view);
9350 			goto cleanup_cachelist;
9351 		}
9352 		dns_view_freeze(view);
9353 		dns_view_detach(&view);
9354 	}
9355 
9356 	/* Now combine the two viewlists into one */
9357 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9358 
9359 	/*
9360 	 * Commit any dns_zone_setview() calls on all zones in the new
9361 	 * view.
9362 	 */
9363 	for (dns_view_t *view = ISC_LIST_HEAD(viewlist); view != NULL;
9364 	     view = ISC_LIST_NEXT(view, link))
9365 	{
9366 		dns_view_setviewcommit(view);
9367 	}
9368 
9369 	/* Swap our new view list with the production one. */
9370 	tmpviewlist = server->viewlist;
9371 	server->viewlist = viewlist;
9372 	viewlist = tmpviewlist;
9373 
9374 	/* Make the view list available to each of the views */
9375 	for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9376 	     view = ISC_LIST_NEXT(view, link))
9377 	{
9378 		view->viewlist = &server->viewlist;
9379 	}
9380 
9381 	/* Swap our new cache list with the production one. */
9382 	tmpcachelist = server->cachelist;
9383 	server->cachelist = cachelist;
9384 	cachelist = tmpcachelist;
9385 
9386 	/* Load the TKEY information from the configuration. */
9387 	if (options != NULL) {
9388 		dns_tkeyctx_t *tkeyctx = NULL;
9389 
9390 		result = named_tkeyctx_fromconfig(options, named_g_mctx,
9391 						  &tkeyctx);
9392 		if (result != ISC_R_SUCCESS) {
9393 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9394 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9395 				      "configuring TKEY: %s",
9396 				      isc_result_totext(result));
9397 			goto cleanup_cachelist;
9398 		}
9399 		if (server->sctx->tkeyctx != NULL) {
9400 			dns_tkeyctx_destroy(&server->sctx->tkeyctx);
9401 		}
9402 		server->sctx->tkeyctx = tkeyctx;
9403 	}
9404 
9405 #ifdef HAVE_LMDB
9406 	/*
9407 	 * If we're using LMDB, we may have created newzones databases
9408 	 * as root, making it impossible to reopen them later after
9409 	 * switching to a new userid. We close them now, and reopen
9410 	 * after relinquishing privileges them.
9411 	 */
9412 	if (first_time) {
9413 		for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist);
9414 		     view != NULL; view = ISC_LIST_NEXT(view, link))
9415 		{
9416 			nzd_env_close(view);
9417 		}
9418 	}
9419 #endif /* HAVE_LMDB */
9420 
9421 	/*
9422 	 * Switch to the effective UID for setting up files.
9423 	 * Later, after configuring all the listening ports,
9424 	 * we'll relinquish root privileges permanently.
9425 	 */
9426 	if (first_time) {
9427 		named_os_changeuser(false);
9428 	}
9429 
9430 	/*
9431 	 * Check that the working directory is writable.
9432 	 */
9433 	if (!isc_file_isdirwritable(".")) {
9434 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9435 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9436 			      "the working directory is not writable");
9437 		result = ISC_R_NOPERM;
9438 		goto cleanup_cachelist;
9439 	}
9440 
9441 #ifdef HAVE_LMDB
9442 	/*
9443 	 * Reopen NZD databases.
9444 	 */
9445 	if (first_time) {
9446 		for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist);
9447 		     view != NULL; view = ISC_LIST_NEXT(view, link))
9448 		{
9449 			nzd_env_reopen(view);
9450 		}
9451 	}
9452 #endif /* HAVE_LMDB */
9453 
9454 	/*
9455 	 * Configure the logging system.
9456 	 *
9457 	 * Do this after changing UID to make sure that any log
9458 	 * files specified in named.conf get created by the
9459 	 * unprivileged user, not root.
9460 	 */
9461 	if (named_g_logstderr) {
9462 		const cfg_obj_t *logobj = NULL;
9463 
9464 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9465 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9466 			      "not using config file logging "
9467 			      "statement for logging due to "
9468 			      "-g option");
9469 
9470 		(void)cfg_map_get(config, "logging", &logobj);
9471 		if (logobj != NULL) {
9472 			result = named_logconfig(NULL, logobj);
9473 			if (result != ISC_R_SUCCESS) {
9474 				isc_log_write(
9475 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9476 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9477 					"checking logging configuration "
9478 					"failed: %s",
9479 					isc_result_totext(result));
9480 				goto cleanup_cachelist;
9481 			}
9482 		}
9483 	} else {
9484 		const cfg_obj_t *logobj = NULL;
9485 
9486 		isc_logconfig_create(named_g_lctx, &logc);
9487 
9488 		logobj = NULL;
9489 		(void)cfg_map_get(config, "logging", &logobj);
9490 		if (logobj != NULL) {
9491 			result = named_logconfig(logc, logobj);
9492 			if (result != ISC_R_SUCCESS) {
9493 				isc_log_write(
9494 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9495 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9496 					"configuring logging: %s",
9497 					isc_result_totext(result));
9498 				goto cleanup_logc;
9499 			}
9500 		} else {
9501 			named_log_setdefaultchannels(logc);
9502 			named_log_setdefaultsslkeylogfile(logc);
9503 			result = named_log_setunmatchedcategory(logc);
9504 			if (result != ISC_R_SUCCESS) {
9505 				isc_log_write(
9506 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9507 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9508 					"setting up default 'category "
9509 					"unmatched': %s",
9510 					isc_result_totext(result));
9511 				goto cleanup_logc;
9512 			}
9513 			result = named_log_setdefaultcategory(logc);
9514 			if (result != ISC_R_SUCCESS) {
9515 				isc_log_write(
9516 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9517 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9518 					"setting up default 'category "
9519 					"default': %s",
9520 					isc_result_totext(result));
9521 				goto cleanup_logc;
9522 			}
9523 		}
9524 
9525 		isc_logconfig_use(named_g_lctx, logc);
9526 		logc = NULL;
9527 
9528 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9529 			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9530 			      "now using logging configuration from "
9531 			      "config file");
9532 	}
9533 
9534 	/*
9535 	 * Set the default value of the query logging flag depending
9536 	 * whether a "queries" category has been defined.  This is
9537 	 * a disgusting hack, but we need to do this for BIND 8
9538 	 * compatibility.
9539 	 */
9540 	if (first_time) {
9541 		const cfg_obj_t *logobj = NULL;
9542 		const cfg_obj_t *categories = NULL;
9543 
9544 		obj = NULL;
9545 		if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
9546 			ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES,
9547 					    cfg_obj_asboolean(obj));
9548 		} else {
9549 			(void)cfg_map_get(config, "logging", &logobj);
9550 			if (logobj != NULL) {
9551 				(void)cfg_map_get(logobj, "category",
9552 						  &categories);
9553 			}
9554 			if (categories != NULL) {
9555 				for (element = cfg_list_first(categories);
9556 				     element != NULL;
9557 				     element = cfg_list_next(element))
9558 				{
9559 					const cfg_obj_t *catobj;
9560 					const char *str;
9561 
9562 					obj = cfg_listelt_value(element);
9563 					catobj = cfg_tuple_get(obj, "name");
9564 					str = cfg_obj_asstring(catobj);
9565 					if (strcasecmp(str, "queries") == 0) {
9566 						ns_server_setoption(
9567 							server->sctx,
9568 							NS_SERVER_LOGQUERIES,
9569 							true);
9570 					}
9571 				}
9572 			}
9573 		}
9574 		obj = NULL;
9575 		result = named_config_get(maps, "responselog", &obj);
9576 		if (result == ISC_R_SUCCESS) {
9577 			ns_server_setoption(server->sctx,
9578 					    NS_SERVER_LOGRESPONSES,
9579 					    cfg_obj_asboolean(obj));
9580 		}
9581 	}
9582 
9583 	obj = NULL;
9584 	if (options != NULL &&
9585 	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
9586 	{
9587 		named_g_memstatistics = cfg_obj_asboolean(obj);
9588 	} else {
9589 		named_g_memstatistics =
9590 			((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
9591 	}
9592 
9593 	obj = NULL;
9594 	if (named_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
9595 	{
9596 		named_main_setmemstats(cfg_obj_asstring(obj));
9597 	} else if (named_g_memstatistics) {
9598 		named_main_setmemstats("named.memstats");
9599 	} else {
9600 		named_main_setmemstats(NULL);
9601 	}
9602 
9603 	obj = NULL;
9604 	result = named_config_get(maps, "statistics-file", &obj);
9605 	INSIST(result == ISC_R_SUCCESS);
9606 	setstring(server, &server->statsfile, cfg_obj_asstring(obj));
9607 
9608 	obj = NULL;
9609 	result = named_config_get(maps, "dump-file", &obj);
9610 	INSIST(result == ISC_R_SUCCESS);
9611 	setstring(server, &server->dumpfile, cfg_obj_asstring(obj));
9612 
9613 	obj = NULL;
9614 	result = named_config_get(maps, "secroots-file", &obj);
9615 	INSIST(result == ISC_R_SUCCESS);
9616 	setstring(server, &server->secrootsfile, cfg_obj_asstring(obj));
9617 
9618 	obj = NULL;
9619 	result = named_config_get(maps, "recursing-file", &obj);
9620 	INSIST(result == ISC_R_SUCCESS);
9621 	setstring(server, &server->recfile, cfg_obj_asstring(obj));
9622 
9623 	obj = NULL;
9624 	result = named_config_get(maps, "version", &obj);
9625 	if (result == ISC_R_SUCCESS) {
9626 		setoptstring(server, &server->version, obj);
9627 		server->version_set = true;
9628 	} else {
9629 		server->version_set = false;
9630 	}
9631 
9632 	obj = NULL;
9633 	result = named_config_get(maps, "hostname", &obj);
9634 	if (result == ISC_R_SUCCESS) {
9635 		setoptstring(server, &server->hostname, obj);
9636 		server->hostname_set = true;
9637 	} else {
9638 		server->hostname_set = false;
9639 	}
9640 
9641 	obj = NULL;
9642 	result = named_config_get(maps, "server-id", &obj);
9643 	server->sctx->usehostname = false;
9644 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
9645 		/* The parser translates "hostname" to true */
9646 		server->sctx->usehostname = true;
9647 		result = ns_server_setserverid(server->sctx, NULL);
9648 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
9649 		/* Found a quoted string */
9650 		result = ns_server_setserverid(server->sctx,
9651 					       cfg_obj_asstring(obj));
9652 	} else {
9653 		result = ns_server_setserverid(server->sctx, NULL);
9654 	}
9655 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9656 
9657 	obj = NULL;
9658 	result = named_config_get(maps, "flush-zones-on-shutdown", &obj);
9659 	if (result == ISC_R_SUCCESS) {
9660 		server->flushonshutdown = cfg_obj_asboolean(obj);
9661 	} else {
9662 		server->flushonshutdown = false;
9663 	}
9664 
9665 	obj = NULL;
9666 	result = named_config_get(maps, "answer-cookie", &obj);
9667 	INSIST(result == ISC_R_SUCCESS);
9668 	server->sctx->answercookie = cfg_obj_asboolean(obj);
9669 
9670 	obj = NULL;
9671 	result = named_config_get(maps, "cookie-algorithm", &obj);
9672 	INSIST(result == ISC_R_SUCCESS);
9673 	if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
9674 		server->sctx->cookiealg = ns_cookiealg_siphash24;
9675 	} else {
9676 		UNREACHABLE();
9677 	}
9678 
9679 	obj = NULL;
9680 	result = named_config_get(maps, "cookie-secret", &obj);
9681 	if (result == ISC_R_SUCCESS) {
9682 		const char *str;
9683 		bool first = true;
9684 		isc_buffer_t b;
9685 		unsigned int usedlength;
9686 		unsigned int expectedlength;
9687 
9688 		for (element = cfg_list_first(obj); element != NULL;
9689 		     element = cfg_list_next(element))
9690 		{
9691 			obj = cfg_listelt_value(element);
9692 			str = cfg_obj_asstring(obj);
9693 
9694 			if (first) {
9695 				memset(server->sctx->secret, 0,
9696 				       sizeof(server->sctx->secret));
9697 				isc_buffer_init(&b, server->sctx->secret,
9698 						sizeof(server->sctx->secret));
9699 				result = isc_hex_decodestring(str, &b);
9700 				if (result != ISC_R_SUCCESS &&
9701 				    result != ISC_R_NOSPACE)
9702 				{
9703 					goto cleanup_altsecrets;
9704 				}
9705 				first = false;
9706 			} else {
9707 				altsecret = isc_mem_get(server->sctx->mctx,
9708 							sizeof(*altsecret));
9709 				isc_buffer_init(&b, altsecret->secret,
9710 						sizeof(altsecret->secret));
9711 				result = isc_hex_decodestring(str, &b);
9712 				if (result != ISC_R_SUCCESS &&
9713 				    result != ISC_R_NOSPACE)
9714 				{
9715 					isc_mem_put(server->sctx->mctx,
9716 						    altsecret,
9717 						    sizeof(*altsecret));
9718 					goto cleanup_altsecrets;
9719 				}
9720 				ISC_LIST_INITANDAPPEND(altsecrets, altsecret,
9721 						       link);
9722 			}
9723 
9724 			usedlength = isc_buffer_usedlength(&b);
9725 			switch (server->sctx->cookiealg) {
9726 			case ns_cookiealg_siphash24:
9727 				expectedlength = ISC_SIPHASH24_KEY_LENGTH;
9728 				if (usedlength != expectedlength) {
9729 					result = ISC_R_RANGE;
9730 					isc_log_write(
9731 						named_g_lctx,
9732 						NAMED_LOGCATEGORY_GENERAL,
9733 						NAMED_LOGMODULE_SERVER,
9734 						ISC_LOG_ERROR,
9735 						"SipHash-2-4 cookie-secret "
9736 						"must be 128 bits: %s",
9737 						isc_result_totext(result));
9738 					goto cleanup_altsecrets;
9739 				}
9740 				break;
9741 			}
9742 		}
9743 	} else {
9744 		isc_nonce_buf(server->sctx->secret,
9745 			      sizeof(server->sctx->secret));
9746 	}
9747 
9748 	/*
9749 	 * Swap altsecrets lists.
9750 	 */
9751 	tmpaltsecrets = server->sctx->altsecrets;
9752 	server->sctx->altsecrets = altsecrets;
9753 	altsecrets = tmpaltsecrets;
9754 
9755 	(void)named_server_loadnta(server);
9756 
9757 #ifdef USE_DNSRPS
9758 	/*
9759 	 * Start and connect to the DNS Response Policy Service
9760 	 * daemon, dnsrpzd, for each view that uses DNSRPS.
9761 	 */
9762 	for (dns_view_t *view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9763 	     view = ISC_LIST_NEXT(view, link))
9764 	{
9765 		result = dns_dnsrps_connect(view->rpzs);
9766 		if (result != ISC_R_SUCCESS) {
9767 			view = NULL;
9768 			goto cleanup_altsecrets;
9769 		}
9770 	}
9771 #endif /* ifdef USE_DNSRPS */
9772 
9773 	/*
9774 	 * Record the time of most recent configuration
9775 	 */
9776 	named_g_configtime = isc_time_now();
9777 
9778 	isc_loopmgr_resume(named_g_loopmgr);
9779 	exclusive = false;
9780 
9781 	/* Take back root privileges temporarily */
9782 	if (first_time) {
9783 		named_os_restoreuser();
9784 	}
9785 
9786 	/* Configure the statistics channel(s) */
9787 	result = named_statschannels_configure(named_g_server, config,
9788 					       named_g_aclconfctx);
9789 	if (result != ISC_R_SUCCESS) {
9790 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9791 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9792 			      "configuring statistics server(s): %s",
9793 			      isc_result_totext(result));
9794 		goto cleanup_altsecrets;
9795 	}
9796 
9797 	/*
9798 	 * Bind the control port(s).
9799 	 */
9800 	result = named_controls_configure(named_g_server->controls, config,
9801 					  named_g_aclconfctx);
9802 	if (result != ISC_R_SUCCESS) {
9803 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9804 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9805 			      "binding control channel(s): %s",
9806 			      isc_result_totext(result));
9807 		goto cleanup_altsecrets;
9808 	}
9809 
9810 	(void)ns_interfacemgr_scan(server->interfacemgr, true, true);
9811 
9812 	/*
9813 	 * Permanently drop root privileges now.
9814 	 */
9815 	if (first_time) {
9816 		named_os_changeuser(true);
9817 	}
9818 
9819 	/*
9820 	 * These cleans up either the old production view list
9821 	 * or our temporary list depending on whether they
9822 	 * were swapped above or not.
9823 	 */
9824 cleanup_altsecrets:
9825 	while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) {
9826 		ISC_LIST_UNLINK(altsecrets, altsecret, link);
9827 		isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret));
9828 	}
9829 
9830 cleanup_logc:
9831 	if (logc != NULL) {
9832 		isc_logconfig_destroy(&logc);
9833 	}
9834 
9835 cleanup_cachelist:
9836 	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
9837 		ISC_LIST_UNLINK(cachelist, nsc, link);
9838 		dns_cache_detach(&nsc->cache);
9839 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9840 	}
9841 
9842 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9843 
9844 cleanup_viewlist:
9845 	for (dns_view_t *view = ISC_LIST_HEAD(viewlist); view != NULL;
9846 	     view = view_next)
9847 	{
9848 		view_next = ISC_LIST_NEXT(view, link);
9849 		ISC_LIST_UNLINK(viewlist, view, link);
9850 		if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
9851 		{
9852 			dns_view_setviewrevert(view);
9853 			(void)dns_view_apply(view, false, NULL, removed, view);
9854 		}
9855 		dns_view_detach(&view);
9856 	}
9857 
9858 cleanup_kasplist:
9859 	for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
9860 		kasp_next = ISC_LIST_NEXT(kasp, link);
9861 		ISC_LIST_UNLINK(kasplist, kasp, link);
9862 		dns_kasp_detach(&kasp);
9863 	}
9864 
9865 cleanup_keystorelist:
9866 	for (keystore = ISC_LIST_HEAD(keystorelist); keystore != NULL;
9867 	     keystore = keystore_next)
9868 	{
9869 		keystore_next = ISC_LIST_NEXT(keystore, link);
9870 		ISC_LIST_UNLINK(keystorelist, keystore, link);
9871 		dns_keystore_detach(&keystore);
9872 	}
9873 
9874 cleanup_v6portset:
9875 	isc_portset_destroy(named_g_mctx, &v6portset);
9876 
9877 cleanup_v4portset:
9878 	isc_portset_destroy(named_g_mctx, &v4portset);
9879 
9880 cleanup_bindkeys_parser:
9881 
9882 	if (bindkeys_parser != NULL) {
9883 		if (bindkeys != NULL) {
9884 			cfg_obj_destroy(bindkeys_parser, &bindkeys);
9885 		}
9886 		cfg_parser_destroy(&bindkeys_parser);
9887 	}
9888 
9889 cleanup_config:
9890 	cfg_obj_destroy(conf_parser, &config);
9891 
9892 cleanup_conf_parser:
9893 	cfg_parser_destroy(&conf_parser);
9894 
9895 cleanup_exclusive:
9896 	if (exclusive) {
9897 		isc_loopmgr_resume(named_g_loopmgr);
9898 	}
9899 
9900 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9901 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9902 		      "load_configuration: %s", isc_result_totext(result));
9903 
9904 	return result;
9905 }
9906 
9907 static isc_result_t
9908 view_loaded(void *arg) {
9909 	isc_result_t result;
9910 	ns_zoneload_t *zl = (ns_zoneload_t *)arg;
9911 
9912 	/*
9913 	 * Force zone maintenance.  Do this after loading
9914 	 * so that we know when we need to force AXFR of
9915 	 * secondary zones whose master files are missing.
9916 	 *
9917 	 * We use the zoneload reference counter to let us
9918 	 * know when all views are finished.
9919 	 */
9920 	if (isc_refcount_decrement(&zl->refs) == 1) {
9921 		named_server_t *server = zl->server;
9922 		bool reconfig = zl->reconfig;
9923 		dns_view_t *view = NULL;
9924 
9925 		isc_refcount_destroy(&zl->refs);
9926 		isc_mem_put(server->mctx, zl, sizeof(*zl));
9927 
9928 		/*
9929 		 * To maintain compatibility with log parsing tools that might
9930 		 * be looking for this string after "rndc reconfig", we keep it
9931 		 * as it is
9932 		 */
9933 		if (reconfig) {
9934 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9935 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9936 				      "any newly configured zones are now "
9937 				      "loaded");
9938 		} else {
9939 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9940 				      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9941 				      "all zones loaded");
9942 		}
9943 
9944 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9945 		     view = ISC_LIST_NEXT(view, link))
9946 		{
9947 			if (view->managed_keys != NULL) {
9948 				result = dns_zone_synckeyzone(
9949 					view->managed_keys);
9950 				if (result != ISC_R_SUCCESS) {
9951 					isc_log_write(
9952 						named_g_lctx,
9953 						DNS_LOGCATEGORY_DNSSEC,
9954 						DNS_LOGMODULE_DNSSEC,
9955 						ISC_LOG_ERROR,
9956 						"failed to initialize "
9957 						"managed-keys for view %s "
9958 						"(%s): DNSSEC validation is "
9959 						"at risk",
9960 						view->name,
9961 						isc_result_totext(result));
9962 				}
9963 			}
9964 		}
9965 
9966 		CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
9967 			   "forcing zone maintenance");
9968 
9969 		named_os_started();
9970 
9971 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9972 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9973 			      "FIPS mode is %s",
9974 			      isc_fips_mode() ? "enabled" : "disabled");
9975 
9976 #if HAVE_LIBSYSTEMD
9977 		sd_notifyf(0,
9978 			   "READY=1\n"
9979 			   "STATUS=running\n"
9980 			   "MAINPID=%" PRId64 "\n",
9981 			   (int64_t)getpid());
9982 #endif /* HAVE_LIBSYSTEMD */
9983 
9984 		atomic_store(&server->reload_status, NAMED_RELOAD_DONE);
9985 
9986 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9987 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9988 			      "running");
9989 	}
9990 
9991 	return ISC_R_SUCCESS;
9992 }
9993 
9994 static isc_result_t
9995 load_zones(named_server_t *server, bool reconfig) {
9996 	isc_result_t result = ISC_R_SUCCESS;
9997 	ns_zoneload_t *zl = NULL;
9998 	dns_view_t *view = NULL;
9999 
10000 	zl = isc_mem_get(server->mctx, sizeof(*zl));
10001 	zl->server = server;
10002 	zl->reconfig = reconfig;
10003 
10004 	isc_loopmgr_pause(named_g_loopmgr);
10005 
10006 	isc_refcount_init(&zl->refs, 1);
10007 
10008 	/*
10009 	 * Schedule zones to be loaded from disk.
10010 	 */
10011 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
10012 	     view = ISC_LIST_NEXT(view, link))
10013 	{
10014 		if (view->managed_keys != NULL) {
10015 			result = dns_zone_load(view->managed_keys, false);
10016 			if (result != ISC_R_SUCCESS &&
10017 			    result != DNS_R_UPTODATE &&
10018 			    result != DNS_R_CONTINUE)
10019 			{
10020 				goto cleanup;
10021 			}
10022 		}
10023 		if (view->redirect != NULL) {
10024 			result = dns_zone_load(view->redirect, false);
10025 			if (result != ISC_R_SUCCESS &&
10026 			    result != DNS_R_UPTODATE &&
10027 			    result != DNS_R_CONTINUE)
10028 			{
10029 				goto cleanup;
10030 			}
10031 		}
10032 
10033 		/*
10034 		 * 'dns_view_asyncload' calls view_loaded if there are no
10035 		 * zones.
10036 		 */
10037 		isc_refcount_increment(&zl->refs);
10038 		result = dns_view_asyncload(view, reconfig, view_loaded, zl);
10039 		if (result != ISC_R_SUCCESS) {
10040 			isc_refcount_decrement1(&zl->refs);
10041 			goto cleanup;
10042 		}
10043 	}
10044 
10045 cleanup:
10046 	if (isc_refcount_decrement(&zl->refs) == 1) {
10047 		isc_refcount_destroy(&zl->refs);
10048 		isc_mem_put(server->mctx, zl, sizeof(*zl));
10049 	}
10050 
10051 	isc_loopmgr_resume(named_g_loopmgr);
10052 
10053 	return result;
10054 }
10055 
10056 static void
10057 run_server(void *arg) {
10058 	isc_result_t result;
10059 	named_server_t *server = (named_server_t *)arg;
10060 	dns_geoip_databases_t *geoip = NULL;
10061 
10062 	dns_zonemgr_create(named_g_mctx, named_g_netmgr, &server->zonemgr);
10063 
10064 	CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_loopmgr,
10065 					  named_g_netmgr, &named_g_dispatchmgr),
10066 		   "creating dispatch manager");
10067 
10068 	dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
10069 
10070 #if defined(HAVE_GEOIP2)
10071 	geoip = named_g_geoip;
10072 #else  /* if defined(HAVE_GEOIP2) */
10073 	geoip = NULL;
10074 #endif /* if defined(HAVE_GEOIP2) */
10075 
10076 	CHECKFATAL(ns_interfacemgr_create(named_g_mctx, server->sctx,
10077 					  named_g_loopmgr, named_g_netmgr,
10078 					  named_g_dispatchmgr, geoip,
10079 					  &server->interfacemgr),
10080 		   "creating interface manager");
10081 
10082 	isc_timer_create(named_g_mainloop, interface_timer_tick, server,
10083 			 &server->interface_timer);
10084 
10085 	isc_timer_create(named_g_mainloop, heartbeat_timer_tick, server,
10086 			 &server->heartbeat_timer);
10087 
10088 	isc_timer_create(named_g_mainloop, tat_timer_tick, server,
10089 			 &server->tat_timer);
10090 
10091 	isc_timer_create(named_g_mainloop, pps_timer_tick, server,
10092 			 &server->pps_timer);
10093 
10094 	CHECKFATAL(
10095 		cfg_parser_create(named_g_mctx, named_g_lctx, &named_g_parser),
10096 		"creating default configuration parser");
10097 
10098 	CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx,
10099 				     &named_g_addparser),
10100 		   "creating additional configuration parser");
10101 
10102 	CHECKFATAL(load_configuration(named_g_conffile, server, true),
10103 		   "loading configuration");
10104 
10105 	CHECKFATAL(load_zones(server, false), "loading zones");
10106 #ifdef ENABLE_AFL
10107 	named_g_run_done = true;
10108 #endif /* ifdef ENABLE_AFL */
10109 }
10110 
10111 void
10112 named_server_flushonshutdown(named_server_t *server, bool flush) {
10113 	REQUIRE(NAMED_SERVER_VALID(server));
10114 
10115 	server->flushonshutdown = flush;
10116 }
10117 
10118 static void
10119 shutdown_server(void *arg) {
10120 	named_server_t *server = (named_server_t *)arg;
10121 	dns_view_t *view = NULL, *view_next = NULL;
10122 	dns_kasp_t *kasp = NULL, *kasp_next = NULL;
10123 	dns_keystore_t *keystore = NULL, *keystore_next = NULL;
10124 	bool flush = server->flushonshutdown;
10125 	named_cache_t *nsc = NULL;
10126 
10127 #if HAVE_LIBSYSTEMD
10128 	sd_notify(0, "STOPPING=1\n");
10129 #endif /* HAVE_LIBSYSTEMD */
10130 
10131 	isc_signal_stop(server->sighup);
10132 	isc_signal_destroy(&server->sighup);
10133 
10134 	/*
10135 	 * We need to shutdown the interface before going
10136 	 * exclusive (which would pause the netmgr).
10137 	 */
10138 	ns_interfacemgr_shutdown(server->interfacemgr);
10139 
10140 	named_controls_shutdown(server->controls);
10141 
10142 	named_statschannels_shutdown(server);
10143 
10144 	isc_loopmgr_pause(named_g_loopmgr);
10145 
10146 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10147 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "shutting down%s",
10148 		      flush ? ": flushing changes" : "");
10149 
10150 	cleanup_session_key(server, server->mctx);
10151 
10152 	if (named_g_aclconfctx != NULL) {
10153 		cfg_aclconfctx_detach(&named_g_aclconfctx);
10154 	}
10155 
10156 	cfg_obj_destroy(named_g_parser, &named_g_config);
10157 	cfg_parser_destroy(&named_g_parser);
10158 	cfg_parser_destroy(&named_g_addparser);
10159 
10160 	(void)named_server_saventa(server);
10161 
10162 	for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL;
10163 	     kasp = kasp_next)
10164 	{
10165 		kasp_next = ISC_LIST_NEXT(kasp, link);
10166 		ISC_LIST_UNLINK(server->kasplist, kasp, link);
10167 		dns_kasp_detach(&kasp);
10168 	}
10169 
10170 	for (keystore = ISC_LIST_HEAD(server->keystorelist); keystore != NULL;
10171 	     keystore = keystore_next)
10172 	{
10173 		keystore_next = ISC_LIST_NEXT(keystore, link);
10174 		ISC_LIST_UNLINK(server->keystorelist, keystore, link);
10175 		dns_keystore_detach(&keystore);
10176 	}
10177 
10178 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
10179 	     view = view_next)
10180 	{
10181 		view_next = ISC_LIST_NEXT(view, link);
10182 		ISC_LIST_UNLINK(server->viewlist, view, link);
10183 		dns_view_flushonshutdown(view, flush);
10184 		dns_view_detach(&view);
10185 	}
10186 
10187 	/*
10188 	 * Shut down all dyndb instances.
10189 	 */
10190 	dns_dyndb_cleanup(true);
10191 
10192 	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
10193 		ISC_LIST_UNLINK(server->cachelist, nsc, link);
10194 		dns_cache_detach(&nsc->cache);
10195 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
10196 	}
10197 
10198 	isc_timer_destroy(&server->interface_timer);
10199 	isc_timer_destroy(&server->heartbeat_timer);
10200 	isc_timer_destroy(&server->pps_timer);
10201 	isc_timer_destroy(&server->tat_timer);
10202 
10203 	ns_interfacemgr_detach(&server->interfacemgr);
10204 
10205 	dns_dispatchmgr_detach(&named_g_dispatchmgr);
10206 
10207 	dns_zonemgr_shutdown(server->zonemgr);
10208 
10209 #if defined(HAVE_GEOIP2)
10210 	named_geoip_shutdown();
10211 #endif /* HAVE_GEOIP2 */
10212 
10213 	dns_db_detach(&server->in_roothints);
10214 
10215 	isc_loopmgr_resume(named_g_loopmgr);
10216 }
10217 
10218 static isc_result_t
10219 get_matching_view_sync(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
10220 		       dns_message_t *message, dns_aclenv_t *env,
10221 		       isc_result_t *sigresult, dns_view_t **viewp) {
10222 	dns_view_t *view;
10223 
10224 	/*
10225 	 * We should not be running synchronous view matching if signature
10226 	 * checking involves SIG(0). TSIG has priority of SIG(0), so if TSIG
10227 	 * is set then we proceed anyway.
10228 	 */
10229 	INSIST(message->tsigkey != NULL || message->tsig != NULL ||
10230 	       message->sig0 == NULL);
10231 
10232 	for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
10233 	     view = ISC_LIST_NEXT(view, link))
10234 	{
10235 		if (message->rdclass == view->rdclass ||
10236 		    message->rdclass == dns_rdataclass_any)
10237 		{
10238 			const dns_name_t *tsig = NULL;
10239 
10240 			dns_message_resetsig(message);
10241 			*sigresult = dns_message_checksig(message, view);
10242 			if (*sigresult == ISC_R_SUCCESS) {
10243 				tsig = dns_tsigkey_identity(message->tsigkey);
10244 			}
10245 
10246 			if (dns_acl_allowed(srcaddr, tsig, view->matchclients,
10247 					    env) &&
10248 			    dns_acl_allowed(destaddr, tsig,
10249 					    view->matchdestinations, env) &&
10250 			    !(view->matchrecursiveonly &&
10251 			      (message->flags & DNS_MESSAGEFLAG_RD) == 0))
10252 			{
10253 				dns_view_attach(view, viewp);
10254 				return ISC_R_SUCCESS;
10255 			}
10256 		}
10257 	}
10258 
10259 	return ISC_R_NOTFOUND;
10260 }
10261 
10262 static void
10263 get_matching_view_done(void *cbarg) {
10264 	matching_view_ctx_t *mvctx = cbarg;
10265 	dns_message_t *message = mvctx->message;
10266 
10267 	if (*mvctx->viewmatchresult == ISC_R_SUCCESS) {
10268 		INSIST(mvctx->view != NULL);
10269 		dns_view_attach(mvctx->view, mvctx->viewp);
10270 	}
10271 
10272 	mvctx->cb(mvctx->cbarg);
10273 
10274 	if (mvctx->quota_result == ISC_R_SUCCESS) {
10275 		isc_quota_release(&mvctx->sctx->sig0checksquota);
10276 	}
10277 	if (mvctx->view != NULL) {
10278 		dns_view_detach(&mvctx->view);
10279 	}
10280 	isc_loop_detach(&mvctx->loop);
10281 	ns_server_detach(&mvctx->sctx);
10282 	isc_mem_put(message->mctx, mvctx, sizeof(*mvctx));
10283 	dns_message_detach(&message);
10284 }
10285 
10286 static dns_view_t *
10287 get_matching_view_next(dns_view_t *view, dns_rdataclass_t rdclass) {
10288 	if (view == NULL) {
10289 		view = ISC_LIST_HEAD(named_g_server->viewlist);
10290 	} else {
10291 		view = ISC_LIST_NEXT(view, link);
10292 	}
10293 	while (true) {
10294 		if (view == NULL || rdclass == view->rdclass ||
10295 		    rdclass == dns_rdataclass_any)
10296 		{
10297 			return view;
10298 		}
10299 		view = ISC_LIST_NEXT(view, link);
10300 	};
10301 }
10302 
10303 static void
10304 get_matching_view_continue(void *cbarg, isc_result_t result) {
10305 	matching_view_ctx_t *mvctx = cbarg;
10306 	dns_view_t *view = NULL;
10307 	const dns_name_t *tsig = NULL;
10308 
10309 	*mvctx->sigresult = result;
10310 
10311 	if (result == ISC_R_SUCCESS) {
10312 		tsig = dns_tsigkey_identity(mvctx->message->tsigkey);
10313 	}
10314 
10315 	if (dns_acl_allowed(mvctx->srcaddr, tsig, mvctx->view->matchclients,
10316 			    mvctx->env) &&
10317 	    dns_acl_allowed(mvctx->destaddr, tsig,
10318 			    mvctx->view->matchdestinations, mvctx->env) &&
10319 	    !(mvctx->view->matchrecursiveonly &&
10320 	      (mvctx->message->flags & DNS_MESSAGEFLAG_RD) == 0))
10321 	{
10322 		/*
10323 		 * A matching view is found.
10324 		 */
10325 		*mvctx->viewmatchresult = ISC_R_SUCCESS;
10326 		get_matching_view_done(cbarg);
10327 		return;
10328 	}
10329 
10330 	dns_message_resetsig(mvctx->message);
10331 
10332 	view = get_matching_view_next(mvctx->view, mvctx->message->rdclass);
10333 	dns_view_detach(&mvctx->view);
10334 	if (view != NULL) {
10335 		/*
10336 		 * Try the next view.
10337 		 */
10338 		dns_view_attach(view, &mvctx->view);
10339 		result = dns_message_checksig_async(
10340 			mvctx->message, view, mvctx->loop,
10341 			get_matching_view_continue, mvctx);
10342 		INSIST(result == DNS_R_WAIT);
10343 		return;
10344 	}
10345 
10346 	/*
10347 	 * No matching view is found.
10348 	 */
10349 	*mvctx->viewmatchresult = ISC_R_NOTFOUND;
10350 	get_matching_view_done(cbarg);
10351 }
10352 
10353 /*%
10354  * Find a view that matches the source and destination addresses of a query.
10355  */
10356 static isc_result_t
10357 get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
10358 		  dns_message_t *message, dns_aclenv_t *env, ns_server_t *sctx,
10359 		  isc_loop_t *loop, isc_job_cb cb, void *cbarg,
10360 		  isc_result_t *sigresult, isc_result_t *viewmatchresult,
10361 		  dns_view_t **viewp) {
10362 	dns_view_t *view = NULL;
10363 	isc_result_t result;
10364 
10365 	REQUIRE(message != NULL);
10366 	REQUIRE(sctx != NULL);
10367 	REQUIRE(loop == NULL || cb != NULL);
10368 	REQUIRE(sigresult != NULL);
10369 	REQUIRE(viewmatchresult != NULL);
10370 	REQUIRE(viewp != NULL && *viewp == NULL);
10371 
10372 	/* No offloading is requested if the loop is unset. */
10373 	if (loop == NULL) {
10374 		*viewmatchresult = get_matching_view_sync(
10375 			srcaddr, destaddr, message, env, sigresult, viewp);
10376 		return *viewmatchresult;
10377 	}
10378 
10379 	/* Also no offloading when there is no view at all to match against. */
10380 	view = get_matching_view_next(NULL, message->rdclass);
10381 	if (view == NULL) {
10382 		*viewmatchresult = ISC_R_NOTFOUND;
10383 		return *viewmatchresult;
10384 	}
10385 
10386 	dns_message_resetsig(message);
10387 
10388 	matching_view_ctx_t *mvctx = isc_mem_get(message->mctx, sizeof(*mvctx));
10389 	*mvctx = (matching_view_ctx_t){
10390 		.srcaddr = srcaddr,
10391 		.destaddr = destaddr,
10392 		.env = env,
10393 		.cb = cb,
10394 		.cbarg = cbarg,
10395 		.sigresult = sigresult,
10396 		.viewmatchresult = viewmatchresult,
10397 		.quota_result = ISC_R_UNSET,
10398 		.viewp = viewp,
10399 	};
10400 	ns_server_attach(sctx, &mvctx->sctx);
10401 	isc_loop_attach(loop, &mvctx->loop);
10402 	dns_message_attach(message, &mvctx->message);
10403 
10404 	/*
10405 	 * If the message has a SIG0 signature which we are going to
10406 	 * check, and the client is not exempt from the SIG(0) quota,
10407 	 * then acquire a quota. TSIG has priority over SIG(0), so if
10408 	 * TSIG is set then we don't care.
10409 	 */
10410 	if (message->tsigkey == NULL && message->tsig == NULL &&
10411 	    message->sig0 != NULL)
10412 	{
10413 		if (sctx->sig0checksquota_exempt != NULL) {
10414 			int exempt_match;
10415 
10416 			result = dns_acl_match(srcaddr, NULL,
10417 					       sctx->sig0checksquota_exempt,
10418 					       env, &exempt_match, NULL);
10419 			if (result == ISC_R_SUCCESS && exempt_match > 0) {
10420 				mvctx->quota_result = ISC_R_EXISTS;
10421 			}
10422 		}
10423 		if (mvctx->quota_result == ISC_R_UNSET) {
10424 			mvctx->quota_result =
10425 				isc_quota_acquire(&sctx->sig0checksquota);
10426 		}
10427 		if (mvctx->quota_result == ISC_R_SOFTQUOTA) {
10428 			isc_quota_release(&sctx->sig0checksquota);
10429 		}
10430 		if (mvctx->quota_result != ISC_R_SUCCESS &&
10431 		    mvctx->quota_result != ISC_R_EXISTS)
10432 		{
10433 			*mvctx->viewmatchresult = ISC_R_QUOTA;
10434 			isc_async_run(loop, get_matching_view_done, mvctx);
10435 			return DNS_R_WAIT;
10436 		}
10437 	}
10438 
10439 	dns_view_attach(view, &mvctx->view);
10440 	result = dns_message_checksig_async(message, view, loop,
10441 					    get_matching_view_continue, mvctx);
10442 	INSIST(result == DNS_R_WAIT);
10443 
10444 	return DNS_R_WAIT;
10445 }
10446 
10447 void
10448 named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
10449 	isc_result_t result;
10450 	named_server_t *server = isc_mem_get(mctx, sizeof(*server));
10451 
10452 	*server = (named_server_t){
10453 		.mctx = mctx,
10454 		.statsfile = isc_mem_strdup(mctx, "named.stats"),
10455 		.dumpfile = isc_mem_strdup(mctx, "named_dump.db"),
10456 		.secrootsfile = isc_mem_strdup(mctx, "named.secroots"),
10457 		.recfile = isc_mem_strdup(mctx, "named.recursing"),
10458 	};
10459 
10460 	/* Initialize server data structures. */
10461 	ISC_LIST_INIT(server->kasplist);
10462 	ISC_LIST_INIT(server->keystorelist);
10463 	ISC_LIST_INIT(server->viewlist);
10464 
10465 	/* Must be first. */
10466 	CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine),
10467 		   "initializing DST");
10468 
10469 	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
10470 				     &server->in_roothints),
10471 		   "setting up root hints");
10472 
10473 	atomic_init(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10474 
10475 	ns_server_create(mctx, get_matching_view, &server->sctx);
10476 
10477 #if defined(HAVE_GEOIP2)
10478 	/*
10479 	 * GeoIP must be initialized before the interface
10480 	 * manager (which includes the ACL environment)
10481 	 * is created.
10482 	 */
10483 	named_geoip_init();
10484 #endif /* HAVE_GEOIP2 */
10485 
10486 #ifdef ENABLE_AFL
10487 	server->sctx->fuzztype = named_g_fuzz_type;
10488 	server->sctx->fuzznotify = named_fuzz_notify;
10489 #endif /* ifdef ENABLE_AFL */
10490 
10491 	named_g_mainloop = isc_loop_main(named_g_loopmgr);
10492 
10493 	isc_loop_setup(named_g_mainloop, run_server, server);
10494 	isc_loop_teardown(named_g_mainloop, shutdown_server, server);
10495 
10496 	/* Add SIGHUP reload handler  */
10497 	server->sighup = isc_signal_new(
10498 		named_g_loopmgr, named_server_reloadwanted, server, SIGHUP);
10499 
10500 	isc_stats_create(server->mctx, &server->sockstats,
10501 			 isc_sockstatscounter_max);
10502 	isc_nm_setstats(named_g_netmgr, server->sockstats);
10503 
10504 	isc_stats_create(named_g_mctx, &server->zonestats,
10505 			 dns_zonestatscounter_max);
10506 
10507 	isc_stats_create(named_g_mctx, &server->resolverstats,
10508 			 dns_resstatscounter_max);
10509 
10510 	CHECKFATAL(named_controls_create(server, &server->controls),
10511 		   "named_controls_create");
10512 
10513 	ISC_LIST_INIT(server->statschannels);
10514 
10515 	ISC_LIST_INIT(server->cachelist);
10516 
10517 	server->magic = NAMED_SERVER_MAGIC;
10518 
10519 	*serverp = server;
10520 }
10521 
10522 void
10523 named_server_destroy(named_server_t **serverp) {
10524 	named_server_t *server = *serverp;
10525 	REQUIRE(NAMED_SERVER_VALID(server));
10526 
10527 #ifdef HAVE_DNSTAP
10528 	if (server->dtenv != NULL) {
10529 		dns_dt_detach(&server->dtenv);
10530 	}
10531 #endif /* HAVE_DNSTAP */
10532 
10533 #ifdef USE_DNSRPS
10534 	dns_dnsrps_server_destroy();
10535 	isc_mem_free(server->mctx, server->dnsrpslib);
10536 #endif /* ifdef USE_DNSRPS */
10537 
10538 	named_controls_destroy(&server->controls);
10539 
10540 	isc_stats_detach(&server->zonestats);
10541 	isc_stats_detach(&server->sockstats);
10542 	isc_stats_detach(&server->resolverstats);
10543 
10544 	if (server->sctx != NULL) {
10545 		ns_server_detach(&server->sctx);
10546 	}
10547 
10548 	isc_mem_free(server->mctx, server->statsfile);
10549 	isc_mem_free(server->mctx, server->dumpfile);
10550 	isc_mem_free(server->mctx, server->secrootsfile);
10551 	isc_mem_free(server->mctx, server->recfile);
10552 
10553 	if (server->bindkeysfile != NULL) {
10554 		isc_mem_free(server->mctx, server->bindkeysfile);
10555 	}
10556 
10557 	if (server->version != NULL) {
10558 		isc_mem_free(server->mctx, server->version);
10559 	}
10560 	if (server->hostname != NULL) {
10561 		isc_mem_free(server->mctx, server->hostname);
10562 	}
10563 
10564 	if (server->zonemgr != NULL) {
10565 		dns_zonemgr_detach(&server->zonemgr);
10566 	}
10567 
10568 	dst_lib_destroy();
10569 
10570 	INSIST(ISC_LIST_EMPTY(server->kasplist));
10571 	INSIST(ISC_LIST_EMPTY(server->keystorelist));
10572 	INSIST(ISC_LIST_EMPTY(server->viewlist));
10573 	INSIST(ISC_LIST_EMPTY(server->cachelist));
10574 
10575 	if (server->tlsctx_server_cache != NULL) {
10576 		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
10577 	}
10578 
10579 	if (server->tlsctx_client_cache != NULL) {
10580 		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
10581 	}
10582 
10583 	server->magic = 0;
10584 	isc_mem_put(server->mctx, server, sizeof(*server));
10585 	*serverp = NULL;
10586 }
10587 
10588 static void
10589 fatal(const char *msg, isc_result_t result) {
10590 	if (named_g_loopmgr_running) {
10591 		isc_loopmgr_pause(named_g_loopmgr);
10592 	}
10593 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10594 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, "%s: %s", msg,
10595 		      isc_result_totext(result));
10596 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10597 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
10598 		      "exiting (due to fatal error)");
10599 	named_os_shutdown();
10600 	_exit(EXIT_FAILURE);
10601 }
10602 
10603 static isc_result_t
10604 loadconfig(named_server_t *server) {
10605 	isc_result_t result;
10606 	result = load_configuration(named_g_conffile, server, false);
10607 	if (result == ISC_R_SUCCESS) {
10608 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10609 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10610 			      "reloading configuration succeeded");
10611 	} else {
10612 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10613 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10614 			      "reloading configuration failed: %s",
10615 			      isc_result_totext(result));
10616 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10617 	}
10618 
10619 	return result;
10620 }
10621 
10622 static isc_result_t
10623 reload(named_server_t *server) {
10624 	isc_result_t result;
10625 
10626 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10627 #if HAVE_LIBSYSTEMD
10628 	char buf[512];
10629 	int n = snprintf(buf, sizeof(buf),
10630 			 "RELOADING=1\n"
10631 			 "MONOTONIC_USEC=%" PRIu64 "\n"
10632 			 "STATUS=reload command received\n",
10633 			 (uint64_t)isc_time_monotonic() / NS_PER_US);
10634 	if (n > 0 && (size_t)n < sizeof(buf)) {
10635 		sd_notify(0, buf);
10636 	}
10637 #endif /* HAVE_LIBSYSTEMD */
10638 
10639 	CHECK(loadconfig(server));
10640 
10641 	result = load_zones(server, false);
10642 	if (result == ISC_R_SUCCESS) {
10643 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10644 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10645 			      "reloading zones succeeded");
10646 	} else {
10647 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10648 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10649 			      "reloading zones failed: %s",
10650 			      isc_result_totext(result));
10651 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10652 	}
10653 cleanup:
10654 #if HAVE_LIBSYSTEMD
10655 	sd_notifyf(0,
10656 		   "READY=1\n"
10657 		   "STATUS=reload command finished: %s\n",
10658 		   isc_result_totext(result));
10659 #endif /* HAVE_LIBSYSTEMD */
10660 	return result;
10661 }
10662 
10663 /*
10664  * Handle a reload event (from SIGHUP).
10665  */
10666 static void
10667 named_server_reload(void *arg) {
10668 	named_server_t *server = (named_server_t *)arg;
10669 
10670 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10671 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10672 		      "received SIGHUP signal to reload zones");
10673 	(void)reload(server);
10674 }
10675 
10676 void
10677 named_server_reloadwanted(void *arg, int signum) {
10678 	named_server_t *server = (named_server_t *)arg;
10679 
10680 	REQUIRE(signum == SIGHUP);
10681 
10682 	isc_async_run(named_g_mainloop, named_server_reload, server);
10683 }
10684 
10685 void
10686 named_server_scan_interfaces(named_server_t *server) {
10687 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10688 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
10689 		      "automatic interface rescan");
10690 
10691 	ns_interfacemgr_scan(server->interfacemgr, true, false);
10692 }
10693 
10694 /*
10695  * Get the next token from lexer 'lex'.
10696  *
10697  * NOTE: the token value for string tokens always uses the same pointer
10698  * value.  Multiple calls to this function on the same lexer will always
10699  * return either that value (lex->data) or NULL. It is necessary to copy
10700  * the token into local storage if it needs to be referenced after the next
10701  * call to next_token().
10702  */
10703 static char *
10704 next_token(isc_lex_t *lex, isc_buffer_t **text) {
10705 	isc_result_t result;
10706 	isc_token_t token;
10707 
10708 	token.type = isc_tokentype_unknown;
10709 	result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING,
10710 				  &token);
10711 
10712 	switch (result) {
10713 	case ISC_R_NOMORE:
10714 		(void)isc_lex_close(lex);
10715 		break;
10716 	case ISC_R_SUCCESS:
10717 		if (token.type == isc_tokentype_eof) {
10718 			(void)isc_lex_close(lex);
10719 		}
10720 		break;
10721 	case ISC_R_NOSPACE:
10722 		if (text != NULL) {
10723 			(void)putstr(text, "token too large");
10724 			(void)putnull(text);
10725 		}
10726 		return NULL;
10727 	default:
10728 		if (text != NULL) {
10729 			(void)putstr(text, isc_result_totext(result));
10730 			(void)putnull(text);
10731 		}
10732 		return NULL;
10733 	}
10734 
10735 	if (token.type == isc_tokentype_string ||
10736 	    token.type == isc_tokentype_qstring)
10737 	{
10738 		return token.value.as_textregion.base;
10739 	}
10740 
10741 	return NULL;
10742 }
10743 
10744 /*
10745  * Find the zone specified in the control channel command, if any.
10746  * If a zone is specified, point '*zonep' at it, otherwise
10747  * set '*zonep' to NULL, and f 'zonename' is not NULL, copy
10748  * the zone name into it (N.B. 'zonename' must have space to hold
10749  * a full DNS name).
10750  *
10751  * If 'zonetxt' is set, the caller has already pulled a token
10752  * off the command line that is to be used as the zone name. (This
10753  * is sometimes done when it's necessary to check for an optional
10754  * argument before the zone name, as in "rndc sync [-clean] zone".)
10755  */
10756 static isc_result_t
10757 zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
10758 	       dns_zone_t **zonep, char *zonename, isc_buffer_t **text,
10759 	       bool skip) {
10760 	char *ptr;
10761 	char *classtxt;
10762 	const char *viewtxt = NULL;
10763 	dns_fixedname_t fname;
10764 	dns_name_t *name;
10765 	isc_result_t result;
10766 	dns_view_t *view = NULL;
10767 	dns_rdataclass_t rdclass;
10768 	char problem[DNS_NAME_FORMATSIZE + 500] = "";
10769 	char zonebuf[DNS_NAME_FORMATSIZE];
10770 	bool redirect = false;
10771 
10772 	REQUIRE(zonep != NULL && *zonep == NULL);
10773 
10774 	if (skip) {
10775 		/* Skip the command name. */
10776 		ptr = next_token(lex, text);
10777 		if (ptr == NULL) {
10778 			return ISC_R_UNEXPECTEDEND;
10779 		}
10780 	}
10781 
10782 	/* Look for the zone name. */
10783 	if (zonetxt == NULL) {
10784 		zonetxt = next_token(lex, text);
10785 	}
10786 	if (zonetxt == NULL) {
10787 		return ISC_R_SUCCESS;
10788 	}
10789 
10790 	/* Copy zonetxt because it'll be overwritten by next_token() */
10791 	/* To locate a zone named "-redirect" use "-redirect." */
10792 	if (strcmp(zonetxt, "-redirect") == 0) {
10793 		redirect = true;
10794 		strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE);
10795 	} else {
10796 		strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE);
10797 	}
10798 	if (zonename != NULL) {
10799 		strlcpy(zonename, redirect ? "." : zonetxt,
10800 			DNS_NAME_FORMATSIZE);
10801 	}
10802 
10803 	name = dns_fixedname_initname(&fname);
10804 	CHECK(dns_name_fromstring(name, zonebuf, dns_rootname, 0, NULL));
10805 
10806 	/* Look for the optional class name. */
10807 	classtxt = next_token(lex, text);
10808 	if (classtxt != NULL) {
10809 		isc_textregion_t r;
10810 		r.base = classtxt;
10811 		r.length = strlen(classtxt);
10812 		CHECK(dns_rdataclass_fromtext(&rdclass, &r));
10813 
10814 		/* Look for the optional view name. */
10815 		viewtxt = next_token(lex, text);
10816 	} else {
10817 		rdclass = dns_rdataclass_in;
10818 	}
10819 
10820 	if (viewtxt == NULL) {
10821 		if (redirect) {
10822 			result = dns_viewlist_find(&server->viewlist,
10823 						   "_default",
10824 						   dns_rdataclass_in, &view);
10825 			if (result != ISC_R_SUCCESS || view->redirect == NULL) {
10826 				result = ISC_R_NOTFOUND;
10827 				snprintf(problem, sizeof(problem),
10828 					 "redirect zone not found in "
10829 					 "_default view");
10830 			} else {
10831 				dns_zone_attach(view->redirect, zonep);
10832 				result = ISC_R_SUCCESS;
10833 			}
10834 		} else {
10835 			result = dns_viewlist_findzone(&server->viewlist, name,
10836 						       classtxt == NULL,
10837 						       rdclass, zonep);
10838 			if (result == ISC_R_NOTFOUND) {
10839 				snprintf(problem, sizeof(problem),
10840 					 "no matching zone '%s' in any view",
10841 					 zonebuf);
10842 			} else if (result == ISC_R_MULTIPLE) {
10843 				snprintf(problem, sizeof(problem),
10844 					 "zone '%s' was found in multiple "
10845 					 "views",
10846 					 zonebuf);
10847 			}
10848 		}
10849 	} else {
10850 		result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass,
10851 					   &view);
10852 		if (result != ISC_R_SUCCESS) {
10853 			snprintf(problem, sizeof(problem),
10854 				 "no matching view '%s'", viewtxt);
10855 			goto report;
10856 		}
10857 
10858 		if (redirect) {
10859 			if (view->redirect != NULL) {
10860 				dns_zone_attach(view->redirect, zonep);
10861 				result = ISC_R_SUCCESS;
10862 			} else {
10863 				result = ISC_R_NOTFOUND;
10864 			}
10865 		} else {
10866 			result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT,
10867 						   zonep);
10868 		}
10869 		if (result != ISC_R_SUCCESS) {
10870 			snprintf(problem, sizeof(problem),
10871 				 "no matching zone '%s' in view '%s'", zonebuf,
10872 				 viewtxt);
10873 		}
10874 	}
10875 
10876 	/* Partial match? */
10877 	if (result != ISC_R_SUCCESS && *zonep != NULL) {
10878 		dns_zone_detach(zonep);
10879 	}
10880 	if (result == DNS_R_PARTIALMATCH) {
10881 		result = ISC_R_NOTFOUND;
10882 	}
10883 report:
10884 	if (result != ISC_R_SUCCESS) {
10885 		isc_result_t tresult;
10886 
10887 		tresult = putstr(text, problem);
10888 		if (tresult == ISC_R_SUCCESS) {
10889 			(void)putnull(text);
10890 		}
10891 	}
10892 
10893 cleanup:
10894 	if (view != NULL) {
10895 		dns_view_detach(&view);
10896 	}
10897 
10898 	return result;
10899 }
10900 
10901 /*
10902  * Act on a "retransfer" command from the command channel.
10903  */
10904 isc_result_t
10905 named_server_retransfercommand(named_server_t *server, isc_lex_t *lex,
10906 			       isc_buffer_t **text) {
10907 	isc_result_t result;
10908 	const char *arg = NULL;
10909 	dns_zone_t *zone = NULL;
10910 	dns_zone_t *raw = NULL;
10911 	dns_zonetype_t type;
10912 	bool force = false;
10913 
10914 	REQUIRE(text != NULL);
10915 
10916 	/* Skip the command name. */
10917 	(void)next_token(lex, text);
10918 
10919 	arg = next_token(lex, text);
10920 	if (arg != NULL && (strcmp(arg, "-force") == 0)) {
10921 		force = true;
10922 		arg = next_token(lex, text);
10923 	}
10924 
10925 	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
10926 	if (result != ISC_R_SUCCESS) {
10927 		return result;
10928 	}
10929 	if (zone == NULL) {
10930 		return ISC_R_UNEXPECTEDEND;
10931 	}
10932 	dns_zone_getraw(zone, &raw);
10933 	if (raw != NULL) {
10934 		dns_zone_detach(&zone);
10935 		dns_zone_attach(raw, &zone);
10936 		dns_zone_detach(&raw);
10937 	}
10938 	type = dns_zone_gettype(zone);
10939 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
10940 	    type == dns_zone_stub ||
10941 	    (type == dns_zone_redirect &&
10942 	     dns_zone_getredirecttype(zone) == dns_zone_secondary))
10943 	{
10944 		if (force) {
10945 			dns_zone_stopxfr(zone);
10946 		}
10947 		dns_zone_forcexfr(zone);
10948 	} else {
10949 		(void)putstr(text, "retransfer: inappropriate zone type: ");
10950 		(void)putstr(text, dns_zonetype_name(type));
10951 		if (type == dns_zone_redirect) {
10952 			type = dns_zone_getredirecttype(zone);
10953 			(void)putstr(text, "(");
10954 			(void)putstr(text, dns_zonetype_name(type));
10955 			(void)putstr(text, ")");
10956 		}
10957 		(void)putnull(text);
10958 		result = ISC_R_FAILURE;
10959 	}
10960 	dns_zone_detach(&zone);
10961 	return result;
10962 }
10963 
10964 /*
10965  * Act on a "reload" command from the command channel.
10966  */
10967 isc_result_t
10968 named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
10969 			   isc_buffer_t **text) {
10970 	isc_result_t result;
10971 	dns_zone_t *zone = NULL;
10972 	dns_zonetype_t type;
10973 	const char *msg = NULL;
10974 
10975 	REQUIRE(text != NULL);
10976 
10977 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10978 	if (result != ISC_R_SUCCESS) {
10979 		return result;
10980 	}
10981 	if (zone == NULL) {
10982 		result = reload(server);
10983 		if (result == ISC_R_SUCCESS) {
10984 			msg = "server reload successful";
10985 		}
10986 	} else {
10987 		type = dns_zone_gettype(zone);
10988 		if (type == dns_zone_secondary || type == dns_zone_mirror ||
10989 		    type == dns_zone_stub)
10990 		{
10991 			dns_zone_refresh(zone);
10992 			dns_zone_detach(&zone);
10993 			msg = "zone refresh queued";
10994 		} else {
10995 			result = dns_zone_load(zone, false);
10996 			dns_zone_detach(&zone);
10997 			switch (result) {
10998 			case ISC_R_SUCCESS:
10999 				msg = "zone reload successful";
11000 				break;
11001 			case DNS_R_CONTINUE:
11002 				msg = "zone reload queued";
11003 				result = ISC_R_SUCCESS;
11004 				break;
11005 			case DNS_R_UPTODATE:
11006 				msg = "zone reload up-to-date";
11007 				result = ISC_R_SUCCESS;
11008 				break;
11009 			default:
11010 				/* failure message will be generated by rndc */
11011 				break;
11012 			}
11013 		}
11014 	}
11015 	if (msg != NULL) {
11016 		(void)putstr(text, msg);
11017 		(void)putnull(text);
11018 	}
11019 	return result;
11020 }
11021 
11022 /*
11023  * Act on a "reconfig" command from the command channel.
11024  */
11025 isc_result_t
11026 named_server_reconfigcommand(named_server_t *server) {
11027 	isc_result_t result;
11028 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
11029 #if HAVE_LIBSYSTEMD
11030 	char buf[512];
11031 	int n = snprintf(buf, sizeof(buf),
11032 			 "RELOADING=1\n"
11033 			 "MONOTONIC_USEC=%" PRIu64 "\n"
11034 			 "STATUS=reconfig command received\n",
11035 			 (uint64_t)isc_time_monotonic() / NS_PER_US);
11036 	if (n > 0 && (size_t)n < sizeof(buf)) {
11037 		sd_notify(0, buf);
11038 	}
11039 #endif /* HAVE_LIBSYSTEMD */
11040 
11041 	CHECK(loadconfig(server));
11042 
11043 	result = load_zones(server, true);
11044 	if (result == ISC_R_SUCCESS) {
11045 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11046 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11047 			      "scheduled loading new zones");
11048 	} else {
11049 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11050 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11051 			      "loading new zones failed: %s",
11052 			      isc_result_totext(result));
11053 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
11054 	}
11055 cleanup:
11056 #if HAVE_LIBSYSTEMD
11057 	sd_notifyf(0,
11058 		   "READY=1\n"
11059 		   "STATUS=reconfig command finished: %s\n",
11060 		   isc_result_totext(result));
11061 #endif /* HAVE_LIBSYSTEMD */
11062 	return result;
11063 }
11064 
11065 /*
11066  * Act on a "notify" command from the command channel.
11067  */
11068 isc_result_t
11069 named_server_notifycommand(named_server_t *server, isc_lex_t *lex,
11070 			   isc_buffer_t **text) {
11071 	isc_result_t result;
11072 	dns_zone_t *zone = NULL;
11073 	const char msg[] = "zone notify queued";
11074 
11075 	REQUIRE(text != NULL);
11076 
11077 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
11078 	if (result != ISC_R_SUCCESS) {
11079 		return result;
11080 	}
11081 	if (zone == NULL) {
11082 		return ISC_R_UNEXPECTEDEND;
11083 	}
11084 
11085 	dns_zone_notify(zone);
11086 	dns_zone_detach(&zone);
11087 	(void)putstr(text, msg);
11088 	(void)putnull(text);
11089 
11090 	return ISC_R_SUCCESS;
11091 }
11092 
11093 /*
11094  * Act on a "refresh" command from the command channel.
11095  */
11096 isc_result_t
11097 named_server_refreshcommand(named_server_t *server, isc_lex_t *lex,
11098 			    isc_buffer_t **text) {
11099 	isc_result_t result;
11100 	dns_zone_t *zone = NULL, *raw = NULL;
11101 	const char msg1[] = "zone refresh queued";
11102 	const char msg2[] = "not a secondary, mirror, or stub zone";
11103 	dns_zonetype_t type;
11104 
11105 	REQUIRE(text != NULL);
11106 
11107 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
11108 	if (result != ISC_R_SUCCESS) {
11109 		return result;
11110 	}
11111 	if (zone == NULL) {
11112 		return ISC_R_UNEXPECTEDEND;
11113 	}
11114 
11115 	dns_zone_getraw(zone, &raw);
11116 	if (raw != NULL) {
11117 		dns_zone_detach(&zone);
11118 		dns_zone_attach(raw, &zone);
11119 		dns_zone_detach(&raw);
11120 	}
11121 
11122 	type = dns_zone_gettype(zone);
11123 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
11124 	    type == dns_zone_stub)
11125 	{
11126 		dns_zone_refresh(zone);
11127 		dns_zone_detach(&zone);
11128 		(void)putstr(text, msg1);
11129 		(void)putnull(text);
11130 		return ISC_R_SUCCESS;
11131 	}
11132 
11133 	dns_zone_detach(&zone);
11134 	(void)putstr(text, msg2);
11135 	(void)putnull(text);
11136 	return ISC_R_FAILURE;
11137 }
11138 
11139 isc_result_t
11140 named_server_setortoggle(named_server_t *server, const char *optname,
11141 			 unsigned int option, isc_lex_t *lex) {
11142 	bool prev, value;
11143 	char *ptr = NULL;
11144 
11145 	/* Skip the command name. */
11146 	ptr = next_token(lex, NULL);
11147 	if (ptr == NULL) {
11148 		return ISC_R_UNEXPECTEDEND;
11149 	}
11150 
11151 	prev = ns_server_getoption(server->sctx, option);
11152 
11153 	ptr = next_token(lex, NULL);
11154 	if (ptr == NULL) {
11155 		value = !prev;
11156 	} else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
11157 		   !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
11158 	{
11159 		value = true;
11160 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
11161 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
11162 	{
11163 		value = false;
11164 	} else {
11165 		return DNS_R_SYNTAX;
11166 	}
11167 
11168 	if (value == prev) {
11169 		return ISC_R_SUCCESS;
11170 	}
11171 
11172 	ns_server_setoption(server->sctx, option, value);
11173 
11174 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11175 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "%s is now %s",
11176 		      optname, value ? "on" : "off");
11177 	return ISC_R_SUCCESS;
11178 }
11179 
11180 static isc_result_t
11181 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
11182 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
11183 		      isc_tlsctx_cache_t *tlsctx_cache,
11184 		      ns_listenlist_t **target) {
11185 	isc_result_t result;
11186 	const cfg_listelt_t *element;
11187 	ns_listenlist_t *dlist = NULL;
11188 
11189 	REQUIRE(target != NULL && *target == NULL);
11190 
11191 	result = ns_listenlist_create(mctx, &dlist);
11192 	if (result != ISC_R_SUCCESS) {
11193 		return result;
11194 	}
11195 
11196 	for (element = cfg_list_first(listenlist); element != NULL;
11197 	     element = cfg_list_next(element))
11198 	{
11199 		ns_listenelt_t *delt = NULL;
11200 		const cfg_obj_t *listener = cfg_listelt_value(element);
11201 		result = listenelt_fromconfig(listener, config, actx, mctx,
11202 					      family, tlsctx_cache, &delt);
11203 		if (result != ISC_R_SUCCESS) {
11204 			goto cleanup;
11205 		}
11206 		ISC_LIST_APPEND(dlist->elts, delt, link);
11207 	}
11208 	*target = dlist;
11209 	return ISC_R_SUCCESS;
11210 
11211 cleanup:
11212 	ns_listenlist_detach(&dlist);
11213 	return result;
11214 }
11215 
11216 static const cfg_obj_t *
11217 find_maplist(const cfg_obj_t *config, const char *listname, const char *name) {
11218 	isc_result_t result;
11219 	const cfg_obj_t *maplist = NULL;
11220 	const cfg_listelt_t *elt = NULL;
11221 
11222 	REQUIRE(config != NULL);
11223 	REQUIRE(name != NULL);
11224 
11225 	result = cfg_map_get(config, listname, &maplist);
11226 	if (result != ISC_R_SUCCESS) {
11227 		return NULL;
11228 	}
11229 
11230 	for (elt = cfg_list_first(maplist); elt != NULL;
11231 	     elt = cfg_list_next(elt))
11232 	{
11233 		const cfg_obj_t *map = cfg_listelt_value(elt);
11234 		if (strcasecmp(cfg_obj_asstring(cfg_map_getname(map)), name) ==
11235 		    0)
11236 		{
11237 			return map;
11238 		}
11239 	}
11240 
11241 	return NULL;
11242 }
11243 
11244 /*
11245  * Create a listen list from the corresponding configuration
11246  * data structure.
11247  */
11248 static isc_result_t
11249 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
11250 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
11251 		     isc_tlsctx_cache_t *tlsctx_cache,
11252 		     ns_listenelt_t **target) {
11253 	isc_result_t result;
11254 	const cfg_obj_t *ltup = NULL;
11255 	const cfg_obj_t *tlsobj = NULL, *httpobj = NULL;
11256 	const cfg_obj_t *portobj = NULL;
11257 	const cfg_obj_t *http_server = NULL;
11258 	const cfg_obj_t *proxyobj = NULL;
11259 	in_port_t port = 0;
11260 	const char *key = NULL, *cert = NULL, *ca_file = NULL,
11261 		   *dhparam_file = NULL, *ciphers = NULL, *cipher_suites = NULL;
11262 	bool tls_prefer_server_ciphers = false,
11263 	     tls_prefer_server_ciphers_set = false;
11264 	bool tls_session_tickets = false, tls_session_tickets_set = false;
11265 	bool do_tls = false, no_tls = false, http = false;
11266 	ns_listenelt_t *delt = NULL;
11267 	uint32_t tls_protos = 0;
11268 	ns_listen_tls_params_t tls_params = { 0 };
11269 	const char *tlsname = NULL;
11270 	isc_nm_proxy_type_t proxy = ISC_NM_PROXY_NONE;
11271 
11272 	REQUIRE(target != NULL && *target == NULL);
11273 
11274 	ltup = cfg_tuple_get(listener, "tuple");
11275 	RUNTIME_CHECK(ltup != NULL);
11276 
11277 	tlsobj = cfg_tuple_get(ltup, "tls");
11278 	if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) {
11279 		tlsname = cfg_obj_asstring(tlsobj);
11280 
11281 		if (strcasecmp(tlsname, "none") == 0) {
11282 			no_tls = true;
11283 		} else if (strcasecmp(tlsname, "ephemeral") == 0) {
11284 			do_tls = true;
11285 		} else {
11286 			const cfg_obj_t *keyobj = NULL, *certobj = NULL,
11287 					*ca_obj = NULL, *dhparam_obj = NULL;
11288 			const cfg_obj_t *tlsmap = NULL;
11289 			const cfg_obj_t *tls_proto_list = NULL;
11290 			const cfg_obj_t *ciphers_obj = NULL;
11291 			const cfg_obj_t *cipher_suites_obj = NULL;
11292 			const cfg_obj_t *prefer_server_ciphers_obj = NULL;
11293 			const cfg_obj_t *session_tickets_obj = NULL;
11294 
11295 			do_tls = true;
11296 
11297 			tlsmap = find_maplist(config, "tls", tlsname);
11298 			if (tlsmap == NULL) {
11299 				cfg_obj_log(tlsobj, named_g_lctx, ISC_LOG_ERROR,
11300 					    "tls '%s' is not defined",
11301 					    cfg_obj_asstring(tlsobj));
11302 				return ISC_R_FAILURE;
11303 			}
11304 
11305 			CHECK(cfg_map_get(tlsmap, "key-file", &keyobj));
11306 			key = cfg_obj_asstring(keyobj);
11307 
11308 			CHECK(cfg_map_get(tlsmap, "cert-file", &certobj));
11309 			cert = cfg_obj_asstring(certobj);
11310 
11311 			if (cfg_map_get(tlsmap, "ca-file", &ca_obj) ==
11312 			    ISC_R_SUCCESS)
11313 			{
11314 				ca_file = cfg_obj_asstring(ca_obj);
11315 			}
11316 
11317 			if (cfg_map_get(tlsmap, "protocols", &tls_proto_list) ==
11318 			    ISC_R_SUCCESS)
11319 			{
11320 				const cfg_listelt_t *proto = NULL;
11321 				INSIST(tls_proto_list != NULL);
11322 				for (proto = cfg_list_first(tls_proto_list);
11323 				     proto != 0; proto = cfg_list_next(proto))
11324 				{
11325 					const cfg_obj_t *tls_proto_obj =
11326 						cfg_listelt_value(proto);
11327 					const char *tls_sver =
11328 						cfg_obj_asstring(tls_proto_obj);
11329 					const isc_tls_protocol_version_t ver =
11330 						isc_tls_protocol_name_to_version(
11331 							tls_sver);
11332 
11333 					INSIST(ver !=
11334 					       ISC_TLS_PROTO_VER_UNDEFINED);
11335 					INSIST(isc_tls_protocol_supported(ver));
11336 					tls_protos |= ver;
11337 				}
11338 			}
11339 
11340 			if (cfg_map_get(tlsmap, "dhparam-file", &dhparam_obj) ==
11341 			    ISC_R_SUCCESS)
11342 			{
11343 				dhparam_file = cfg_obj_asstring(dhparam_obj);
11344 			}
11345 
11346 			if (cfg_map_get(tlsmap, "ciphers", &ciphers_obj) ==
11347 			    ISC_R_SUCCESS)
11348 			{
11349 				ciphers = cfg_obj_asstring(ciphers_obj);
11350 			}
11351 
11352 			if (cfg_map_get(tlsmap, "cipher-suites",
11353 					&cipher_suites_obj) == ISC_R_SUCCESS)
11354 			{
11355 				cipher_suites =
11356 					cfg_obj_asstring(cipher_suites_obj);
11357 			}
11358 
11359 			if (cfg_map_get(tlsmap, "prefer-server-ciphers",
11360 					&prefer_server_ciphers_obj) ==
11361 			    ISC_R_SUCCESS)
11362 			{
11363 				tls_prefer_server_ciphers = cfg_obj_asboolean(
11364 					prefer_server_ciphers_obj);
11365 				tls_prefer_server_ciphers_set = true;
11366 			}
11367 
11368 			if (cfg_map_get(tlsmap, "session-tickets",
11369 					&session_tickets_obj) == ISC_R_SUCCESS)
11370 			{
11371 				tls_session_tickets =
11372 					cfg_obj_asboolean(session_tickets_obj);
11373 				tls_session_tickets_set = true;
11374 			}
11375 		}
11376 	}
11377 
11378 	tls_params = (ns_listen_tls_params_t){
11379 		.name = tlsname,
11380 		.key = key,
11381 		.cert = cert,
11382 		.ca_file = ca_file,
11383 		.protocols = tls_protos,
11384 		.dhparam_file = dhparam_file,
11385 		.ciphers = ciphers,
11386 		.cipher_suites = cipher_suites,
11387 		.prefer_server_ciphers = tls_prefer_server_ciphers,
11388 		.prefer_server_ciphers_set = tls_prefer_server_ciphers_set,
11389 		.session_tickets = tls_session_tickets,
11390 		.session_tickets_set = tls_session_tickets_set
11391 	};
11392 
11393 	httpobj = cfg_tuple_get(ltup, "http");
11394 	if (httpobj != NULL && cfg_obj_isstring(httpobj)) {
11395 		const char *httpname = cfg_obj_asstring(httpobj);
11396 
11397 		if (!do_tls && !no_tls) {
11398 			return ISC_R_FAILURE;
11399 		}
11400 
11401 		http_server = find_maplist(config, "http", httpname);
11402 		if (http_server == NULL && strcasecmp(httpname, "default") != 0)
11403 		{
11404 			cfg_obj_log(httpobj, named_g_lctx, ISC_LOG_ERROR,
11405 				    "http '%s' is not defined",
11406 				    cfg_obj_asstring(httpobj));
11407 			return ISC_R_FAILURE;
11408 		}
11409 
11410 		http = true;
11411 	}
11412 
11413 	portobj = cfg_tuple_get(ltup, "port");
11414 	if (!cfg_obj_isuint32(portobj)) {
11415 		if (http && do_tls) {
11416 			if (named_g_httpsport != 0) {
11417 				port = named_g_httpsport;
11418 			} else {
11419 				result = named_config_getport(
11420 					config, "https-port", &port);
11421 				if (result != ISC_R_SUCCESS) {
11422 					return result;
11423 				}
11424 			}
11425 		} else if (http && !do_tls) {
11426 			if (named_g_httpport != 0) {
11427 				port = named_g_httpport;
11428 			} else {
11429 				result = named_config_getport(
11430 					config, "http-port", &port);
11431 				if (result != ISC_R_SUCCESS) {
11432 					return result;
11433 				}
11434 			}
11435 		} else if (do_tls) {
11436 			if (named_g_tlsport != 0) {
11437 				port = named_g_tlsport;
11438 			} else {
11439 				result = named_config_getport(
11440 					config, "tls-port", &port);
11441 				if (result != ISC_R_SUCCESS) {
11442 					return result;
11443 				}
11444 			}
11445 		} else {
11446 			if (named_g_port != 0) {
11447 				port = named_g_port;
11448 			} else {
11449 				result = named_config_getport(config, "port",
11450 							      &port);
11451 				if (result != ISC_R_SUCCESS) {
11452 					return result;
11453 				}
11454 			}
11455 		}
11456 	} else {
11457 		if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
11458 			return ISC_R_RANGE;
11459 		}
11460 		port = (in_port_t)cfg_obj_asuint32(portobj);
11461 	}
11462 
11463 	proxyobj = cfg_tuple_get(ltup, "proxy");
11464 	if (proxyobj != NULL && cfg_obj_isstring(proxyobj)) {
11465 		const char *proxyval = cfg_obj_asstring(proxyobj);
11466 
11467 		if (strcasecmp(proxyval, "encrypted") == 0) {
11468 			INSIST(do_tls == true);
11469 			proxy = ISC_NM_PROXY_ENCRYPTED;
11470 		} else if (strcasecmp(proxyval, "plain") == 0) {
11471 			proxy = ISC_NM_PROXY_PLAIN;
11472 		} else {
11473 			UNREACHABLE();
11474 		}
11475 	}
11476 
11477 #ifdef HAVE_LIBNGHTTP2
11478 	if (http) {
11479 		CHECK(listenelt_http(http_server, family, do_tls, &tls_params,
11480 				     tlsctx_cache, port, mctx, proxy, &delt));
11481 	}
11482 #endif /* HAVE_LIBNGHTTP2 */
11483 
11484 	if (!http) {
11485 		CHECK(ns_listenelt_create(mctx, port, NULL, family, do_tls,
11486 					  &tls_params, tlsctx_cache, proxy,
11487 					  &delt));
11488 	}
11489 
11490 	result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), config,
11491 				    named_g_lctx, actx, mctx, family,
11492 				    &delt->acl);
11493 	if (result != ISC_R_SUCCESS) {
11494 		ns_listenelt_destroy(delt);
11495 		return result;
11496 	}
11497 	*target = delt;
11498 
11499 cleanup:
11500 	return result;
11501 }
11502 
11503 #ifdef HAVE_LIBNGHTTP2
11504 static isc_result_t
11505 listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
11506 	       const ns_listen_tls_params_t *tls_params,
11507 	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
11508 	       isc_mem_t *mctx, isc_nm_proxy_type_t proxy,
11509 	       ns_listenelt_t **target) {
11510 	isc_result_t result = ISC_R_SUCCESS;
11511 	ns_listenelt_t *delt = NULL;
11512 	char **endpoints = NULL;
11513 	const cfg_obj_t *eplist = NULL;
11514 	const cfg_listelt_t *elt = NULL;
11515 	size_t len = 1, i = 0;
11516 	uint32_t max_clients = named_g_http_listener_clients;
11517 	uint32_t max_streams = named_g_http_streams_per_conn;
11518 
11519 	REQUIRE(target != NULL && *target == NULL);
11520 
11521 	if (tls) {
11522 		INSIST(tls_params != NULL);
11523 		INSIST((tls_params->key == NULL) == (tls_params->cert == NULL));
11524 	}
11525 
11526 	if (port == 0) {
11527 		port = tls ? named_g_httpsport : named_g_httpport;
11528 	}
11529 
11530 	/*
11531 	 * If "default" was used, we set up the default endpoint
11532 	 * of "/dns-query".
11533 	 */
11534 	if (http != NULL) {
11535 		const cfg_obj_t *cfg_max_clients = NULL;
11536 		const cfg_obj_t *cfg_max_streams = NULL;
11537 
11538 		if (cfg_map_get(http, "endpoints", &eplist) == ISC_R_SUCCESS) {
11539 			INSIST(eplist != NULL);
11540 			len = cfg_list_length(eplist, false);
11541 		}
11542 
11543 		if (cfg_map_get(http, "listener-clients", &cfg_max_clients) ==
11544 		    ISC_R_SUCCESS)
11545 		{
11546 			INSIST(cfg_max_clients != NULL);
11547 			max_clients = cfg_obj_asuint32(cfg_max_clients);
11548 		}
11549 
11550 		if (cfg_map_get(http, "streams-per-connection",
11551 				&cfg_max_streams) == ISC_R_SUCCESS)
11552 		{
11553 			INSIST(cfg_max_streams != NULL);
11554 			max_streams = cfg_obj_asuint32(cfg_max_streams);
11555 		}
11556 	}
11557 
11558 	endpoints = isc_mem_allocate(mctx, sizeof(endpoints[0]) * len);
11559 
11560 	if (http != NULL && eplist != NULL) {
11561 		for (elt = cfg_list_first(eplist); elt != NULL;
11562 		     elt = cfg_list_next(elt))
11563 		{
11564 			const cfg_obj_t *ep = cfg_listelt_value(elt);
11565 			const char *path = cfg_obj_asstring(ep);
11566 			endpoints[i++] = isc_mem_strdup(mctx, path);
11567 		}
11568 	} else {
11569 		endpoints[i++] = isc_mem_strdup(mctx, ISC_NM_HTTP_DEFAULT_PATH);
11570 	}
11571 
11572 	INSIST(i == len);
11573 
11574 	result = ns_listenelt_create_http(
11575 		mctx, port, NULL, family, tls, tls_params, tlsctx_cache, proxy,
11576 		endpoints, len, max_clients, max_streams, &delt);
11577 	if (result != ISC_R_SUCCESS) {
11578 		goto error;
11579 	}
11580 
11581 	*target = delt;
11582 
11583 	return result;
11584 error:
11585 	if (delt != NULL) {
11586 		ns_listenelt_destroy(delt);
11587 	}
11588 	return result;
11589 }
11590 #endif /* HAVE_LIBNGHTTP2 */
11591 
11592 isc_result_t
11593 named_server_dumpstats(named_server_t *server) {
11594 	isc_result_t result;
11595 	FILE *fp = NULL;
11596 
11597 	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
11598 		"could not open statistics dump file", server->statsfile);
11599 
11600 	result = named_stats_dump(server, fp);
11601 
11602 cleanup:
11603 	if (fp != NULL) {
11604 		(void)isc_stdio_close(fp);
11605 	}
11606 	if (result == ISC_R_SUCCESS) {
11607 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11608 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11609 			      "dumpstats complete");
11610 	} else {
11611 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11612 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11613 			      "dumpstats failed: %s",
11614 			      isc_result_totext(result));
11615 	}
11616 	return result;
11617 }
11618 
11619 static isc_result_t
11620 add_zone_tolist(dns_zone_t *zone, void *uap) {
11621 	struct dumpcontext *dctx = uap;
11622 	struct zonelistentry *zle;
11623 
11624 	zle = isc_mem_get(dctx->mctx, sizeof *zle);
11625 	zle->zone = NULL;
11626 	dns_zone_attach(zone, &zle->zone);
11627 	ISC_LINK_INIT(zle, link);
11628 	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
11629 	return ISC_R_SUCCESS;
11630 }
11631 
11632 static isc_result_t
11633 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
11634 	struct viewlistentry *vle;
11635 	isc_result_t result = ISC_R_SUCCESS;
11636 
11637 	/*
11638 	 * Prevent duplicate views.
11639 	 */
11640 	for (vle = ISC_LIST_HEAD(dctx->viewlist); vle != NULL;
11641 	     vle = ISC_LIST_NEXT(vle, link))
11642 	{
11643 		if (vle->view == view) {
11644 			return ISC_R_SUCCESS;
11645 		}
11646 	}
11647 
11648 	vle = isc_mem_get(dctx->mctx, sizeof *vle);
11649 	vle->view = NULL;
11650 	dns_view_attach(view, &vle->view);
11651 	ISC_LINK_INIT(vle, link);
11652 	ISC_LIST_INIT(vle->zonelist);
11653 	ISC_LIST_APPEND(dctx->viewlist, vle, link);
11654 	if (dctx->dumpzones) {
11655 		result = dns_view_apply(view, true, NULL, add_zone_tolist,
11656 					dctx);
11657 	}
11658 	return result;
11659 }
11660 
11661 static void
11662 dumpcontext_destroy(struct dumpcontext *dctx) {
11663 	struct viewlistentry *vle;
11664 	struct zonelistentry *zle;
11665 
11666 	vle = ISC_LIST_HEAD(dctx->viewlist);
11667 	while (vle != NULL) {
11668 		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
11669 		zle = ISC_LIST_HEAD(vle->zonelist);
11670 		while (zle != NULL) {
11671 			ISC_LIST_UNLINK(vle->zonelist, zle, link);
11672 			dns_zone_detach(&zle->zone);
11673 			isc_mem_put(dctx->mctx, zle, sizeof *zle);
11674 			zle = ISC_LIST_HEAD(vle->zonelist);
11675 		}
11676 		dns_view_detach(&vle->view);
11677 		isc_mem_put(dctx->mctx, vle, sizeof *vle);
11678 		vle = ISC_LIST_HEAD(dctx->viewlist);
11679 	}
11680 	if (dctx->version != NULL) {
11681 		dns_db_closeversion(dctx->db, &dctx->version, false);
11682 	}
11683 	if (dctx->db != NULL) {
11684 		dns_db_detach(&dctx->db);
11685 	}
11686 	if (dctx->cache != NULL) {
11687 		dns_db_detach(&dctx->cache);
11688 	}
11689 	if (dctx->fp != NULL) {
11690 		(void)isc_stdio_close(dctx->fp);
11691 	}
11692 	if (dctx->mdctx != NULL) {
11693 		dns_dumpctx_detach(&dctx->mdctx);
11694 	}
11695 	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
11696 }
11697 
11698 static void
11699 dumpdone(void *arg, isc_result_t result) {
11700 	struct dumpcontext *dctx = arg;
11701 	char buf[1024 + 32];
11702 	const dns_master_style_t *style;
11703 
11704 	if (result != ISC_R_SUCCESS) {
11705 		goto cleanup;
11706 	}
11707 	if (dctx->mdctx != NULL) {
11708 		dns_dumpctx_detach(&dctx->mdctx);
11709 	}
11710 	if (dctx->view == NULL) {
11711 		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
11712 		if (dctx->view == NULL) {
11713 			goto done;
11714 		}
11715 		INSIST(dctx->zone == NULL);
11716 	} else {
11717 		goto resume;
11718 	}
11719 nextview:
11720 	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
11721 resume:
11722 	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
11723 		fprintf(dctx->fp, ";\n; Cache of view '%s' is shared as '%s'\n",
11724 			dctx->view->view->name,
11725 			dns_cache_getname(dctx->view->view->cache));
11726 	} else if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache)
11727 	{
11728 		if (dctx->dumpexpired) {
11729 			style = &dns_master_style_cache_with_expired;
11730 		} else {
11731 			style = &dns_master_style_cache;
11732 		}
11733 		/* start cache dump */
11734 		if (dctx->view->view->cachedb != NULL) {
11735 			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11736 		}
11737 		if (dctx->cache != NULL) {
11738 			fprintf(dctx->fp,
11739 				";\n; Cache dump of view '%s' (cache %s)\n;\n",
11740 				dctx->view->view->name,
11741 				dns_cache_getname(dctx->view->view->cache));
11742 			result = dns_master_dumptostreamasync(
11743 				dctx->mctx, dctx->cache, NULL, style, dctx->fp,
11744 				named_g_mainloop, dumpdone, dctx, &dctx->mdctx);
11745 			if (result == ISC_R_SUCCESS) {
11746 				return;
11747 			}
11748 			if (result == ISC_R_NOTIMPLEMENTED) {
11749 				fprintf(dctx->fp, "; %s\n",
11750 					isc_result_totext(result));
11751 			} else if (result != ISC_R_SUCCESS) {
11752 				goto cleanup;
11753 			}
11754 		}
11755 	}
11756 
11757 	if ((dctx->dumpadb || dctx->dumpfail) && dctx->cache == NULL &&
11758 	    dctx->view->view->cachedb != NULL)
11759 	{
11760 		dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11761 	}
11762 
11763 	if (dctx->cache != NULL) {
11764 		if (dctx->dumpadb) {
11765 			dns_adb_t *adb = NULL;
11766 			dns_view_getadb(dctx->view->view, &adb);
11767 			if (adb != NULL) {
11768 				dns_adb_dump(adb, dctx->fp);
11769 				dns_adb_detach(&adb);
11770 			}
11771 		}
11772 		if (dctx->dumpfail) {
11773 			dns_badcache_print(dctx->view->view->failcache,
11774 					   "SERVFAIL cache", dctx->fp);
11775 		}
11776 		dns_db_detach(&dctx->cache);
11777 	}
11778 	if (dctx->dumpzones) {
11779 		style = &dns_master_style_full;
11780 	nextzone:
11781 		if (dctx->version != NULL) {
11782 			dns_db_closeversion(dctx->db, &dctx->version, false);
11783 		}
11784 		if (dctx->db != NULL) {
11785 			dns_db_detach(&dctx->db);
11786 		}
11787 		if (dctx->zone == NULL) {
11788 			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
11789 		} else {
11790 			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
11791 		}
11792 		if (dctx->zone != NULL) {
11793 			/* start zone dump */
11794 			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
11795 			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
11796 			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
11797 			if (result != ISC_R_SUCCESS) {
11798 				fprintf(dctx->fp, "; %s\n",
11799 					isc_result_totext(result));
11800 				goto nextzone;
11801 			}
11802 			dns_db_currentversion(dctx->db, &dctx->version);
11803 			result = dns_master_dumptostreamasync(
11804 				dctx->mctx, dctx->db, dctx->version, style,
11805 				dctx->fp, dns_zone_getloop(dctx->zone->zone),
11806 				dumpdone, dctx, &dctx->mdctx);
11807 			if (result == ISC_R_SUCCESS) {
11808 				return;
11809 			}
11810 			if (result == ISC_R_NOTIMPLEMENTED) {
11811 				fprintf(dctx->fp, "; %s\n",
11812 					isc_result_totext(result));
11813 				result = ISC_R_SUCCESS;
11814 				POST(result);
11815 				goto nextzone;
11816 			}
11817 			if (result != ISC_R_SUCCESS) {
11818 				goto cleanup;
11819 			}
11820 		}
11821 	}
11822 	if (dctx->view != NULL) {
11823 		dctx->view = ISC_LIST_NEXT(dctx->view, link);
11824 		if (dctx->view != NULL) {
11825 			goto nextview;
11826 		}
11827 	}
11828 done:
11829 	fprintf(dctx->fp, "; Dump complete\n");
11830 	result = isc_stdio_flush(dctx->fp);
11831 	if (result == ISC_R_SUCCESS) {
11832 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11833 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11834 			      "dumpdb complete");
11835 	}
11836 cleanup:
11837 	if (result != ISC_R_SUCCESS) {
11838 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11839 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11840 			      "dumpdb failed: %s", isc_result_totext(result));
11841 	}
11842 	dumpcontext_destroy(dctx);
11843 }
11844 
11845 isc_result_t
11846 named_server_dumpdb(named_server_t *server, isc_lex_t *lex,
11847 		    isc_buffer_t **text) {
11848 	struct dumpcontext *dctx = NULL;
11849 	dns_view_t *view;
11850 	isc_result_t result;
11851 	char *ptr;
11852 	const char *sep;
11853 	bool found;
11854 
11855 	REQUIRE(text != NULL);
11856 
11857 	/* Skip the command name. */
11858 	ptr = next_token(lex, NULL);
11859 	if (ptr == NULL) {
11860 		return ISC_R_UNEXPECTEDEND;
11861 	}
11862 
11863 	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
11864 	*dctx = (struct dumpcontext){
11865 		.mctx = server->mctx,
11866 		.dumpcache = true,
11867 		.dumpadb = true,
11868 		.dumpfail = true,
11869 		.viewlist = ISC_LIST_INITIALIZER,
11870 	};
11871 
11872 	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
11873 		"could not open dump file", server->dumpfile);
11874 
11875 	ptr = next_token(lex, NULL);
11876 	sep = (ptr == NULL) ? "" : ": ";
11877 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11878 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11879 		      "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : "");
11880 
11881 	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
11882 		/* also dump zones */
11883 		dctx->dumpzones = true;
11884 		ptr = next_token(lex, NULL);
11885 	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
11886 		/* this is the default */
11887 		ptr = next_token(lex, NULL);
11888 	} else if (ptr != NULL && strcmp(ptr, "-expired") == 0) {
11889 		/* this is the same as -cache but includes expired data */
11890 		dctx->dumpexpired = true;
11891 		ptr = next_token(lex, NULL);
11892 	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
11893 		/* only dump zones, suppress caches */
11894 		dctx->dumpadb = false;
11895 		dctx->dumpcache = false;
11896 		dctx->dumpfail = false;
11897 		dctx->dumpzones = true;
11898 		ptr = next_token(lex, NULL);
11899 	} else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
11900 		/* only dump adb, suppress other caches */
11901 		dctx->dumpcache = false;
11902 		dctx->dumpfail = false;
11903 		ptr = next_token(lex, NULL);
11904 	} else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
11905 		/* only dump badcache, suppress other caches */
11906 		dctx->dumpadb = false;
11907 		dctx->dumpcache = false;
11908 		dctx->dumpfail = false;
11909 		ptr = next_token(lex, NULL);
11910 	} else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
11911 		/* only dump servfail cache, suppress other caches */
11912 		dctx->dumpadb = false;
11913 		dctx->dumpcache = false;
11914 		ptr = next_token(lex, NULL);
11915 	}
11916 
11917 nextview:
11918 	found = false;
11919 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11920 	     view = ISC_LIST_NEXT(view, link))
11921 	{
11922 		if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11923 			continue;
11924 		}
11925 		found = true;
11926 		CHECK(add_view_tolist(dctx, view));
11927 	}
11928 	if (ptr != NULL) {
11929 		if (!found) {
11930 			CHECK(putstr(text, "view '"));
11931 			CHECK(putstr(text, ptr));
11932 			CHECK(putstr(text, "' not found"));
11933 			CHECK(putnull(text));
11934 			result = ISC_R_NOTFOUND;
11935 			dumpdone(dctx, result);
11936 			return result;
11937 		}
11938 		ptr = next_token(lex, NULL);
11939 		if (ptr != NULL) {
11940 			goto nextview;
11941 		}
11942 	}
11943 	dumpdone(dctx, ISC_R_SUCCESS);
11944 	return ISC_R_SUCCESS;
11945 
11946 cleanup:
11947 	dumpcontext_destroy(dctx);
11948 	return result;
11949 }
11950 
11951 isc_result_t
11952 named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex,
11953 			  isc_buffer_t **text) {
11954 	dns_view_t *view;
11955 	dns_keytable_t *secroots = NULL;
11956 	dns_ntatable_t *ntatable = NULL;
11957 	isc_result_t result;
11958 	char *ptr;
11959 	FILE *fp = NULL;
11960 	isc_time_t now;
11961 	char tbuf[64];
11962 	unsigned int used = isc_buffer_usedlength(*text);
11963 	bool first = true;
11964 
11965 	REQUIRE(text != NULL);
11966 
11967 	/* Skip the command name. */
11968 	ptr = next_token(lex, text);
11969 	if (ptr == NULL) {
11970 		return ISC_R_UNEXPECTEDEND;
11971 	}
11972 
11973 	/* "-" here means print the output instead of dumping to file */
11974 	ptr = next_token(lex, text);
11975 	if (ptr != NULL && strcmp(ptr, "-") == 0) {
11976 		ptr = next_token(lex, text);
11977 	} else {
11978 		result = isc_stdio_open(server->secrootsfile, "w", &fp);
11979 		if (result != ISC_R_SUCCESS) {
11980 			(void)putstr(text, "could not open ");
11981 			(void)putstr(text, server->secrootsfile);
11982 			CHECKMF(result, "could not open secroots dump file",
11983 				server->secrootsfile);
11984 		}
11985 	}
11986 
11987 	now = isc_time_now();
11988 	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
11989 	CHECK(putstr(text, "secure roots as of "));
11990 	CHECK(putstr(text, tbuf));
11991 	CHECK(putstr(text, ":\n"));
11992 	used = isc_buffer_usedlength(*text);
11993 
11994 	do {
11995 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11996 		     view = ISC_LIST_NEXT(view, link))
11997 		{
11998 			if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11999 				continue;
12000 			}
12001 			if (secroots != NULL) {
12002 				dns_keytable_detach(&secroots);
12003 			}
12004 			result = dns_view_getsecroots(view, &secroots);
12005 			if (result == ISC_R_NOTFOUND) {
12006 				result = ISC_R_SUCCESS;
12007 				continue;
12008 			}
12009 			if (first || used != isc_buffer_usedlength(*text)) {
12010 				CHECK(putstr(text, "\n"));
12011 				first = false;
12012 			}
12013 			CHECK(putstr(text, " Start view "));
12014 			CHECK(putstr(text, view->name));
12015 			CHECK(putstr(text, "\n   Secure roots:\n\n"));
12016 			used = isc_buffer_usedlength(*text);
12017 			CHECK(dns_keytable_totext(secroots, text));
12018 
12019 			if (ntatable != NULL) {
12020 				dns_ntatable_detach(&ntatable);
12021 			}
12022 			result = dns_view_getntatable(view, &ntatable);
12023 			if (result == ISC_R_NOTFOUND) {
12024 				result = ISC_R_SUCCESS;
12025 				continue;
12026 			}
12027 			if (used != isc_buffer_usedlength(*text)) {
12028 				CHECK(putstr(text, "\n"));
12029 			}
12030 			CHECK(putstr(text, "   Negative trust anchors:\n\n"));
12031 			used = isc_buffer_usedlength(*text);
12032 			CHECK(dns_ntatable_totext(ntatable, NULL, text));
12033 		}
12034 
12035 		if (ptr != NULL) {
12036 			ptr = next_token(lex, text);
12037 		}
12038 	} while (ptr != NULL);
12039 
12040 cleanup:
12041 	if (secroots != NULL) {
12042 		dns_keytable_detach(&secroots);
12043 	}
12044 	if (ntatable != NULL) {
12045 		dns_ntatable_detach(&ntatable);
12046 	}
12047 
12048 	if (fp != NULL) {
12049 		if (used != isc_buffer_usedlength(*text)) {
12050 			(void)putstr(text, "\n");
12051 		}
12052 		fprintf(fp, "%.*s", (int)isc_buffer_usedlength(*text),
12053 			(char *)isc_buffer_base(*text));
12054 		isc_buffer_clear(*text);
12055 		(void)isc_stdio_close(fp);
12056 	} else if (isc_buffer_usedlength(*text) > 0) {
12057 		(void)putnull(text);
12058 	}
12059 
12060 	if (result == ISC_R_SUCCESS) {
12061 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12062 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12063 			      "dumpsecroots complete");
12064 	} else {
12065 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12066 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12067 			      "dumpsecroots failed: %s",
12068 			      isc_result_totext(result));
12069 	}
12070 	return result;
12071 }
12072 
12073 isc_result_t
12074 named_server_dumprecursing(named_server_t *server) {
12075 	FILE *fp = NULL;
12076 	dns_view_t *view;
12077 	isc_result_t result;
12078 
12079 	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
12080 		"could not open dump file", server->recfile);
12081 	fprintf(fp, ";\n; Recursing Queries\n;\n");
12082 	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
12083 
12084 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12085 	     view = ISC_LIST_NEXT(view, link))
12086 	{
12087 		fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
12088 			view->name);
12089 		dns_resolver_dumpfetches(view->resolver, isc_statsformat_file,
12090 					 fp);
12091 	}
12092 
12093 	fprintf(fp, "; Dump complete\n");
12094 
12095 cleanup:
12096 	if (fp != NULL) {
12097 		result = isc_stdio_close(fp);
12098 	}
12099 	if (result == ISC_R_SUCCESS) {
12100 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12101 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12102 			      "dumprecursing complete");
12103 	} else {
12104 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12105 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12106 			      "dumprecursing failed: %s",
12107 			      isc_result_totext(result));
12108 	}
12109 	return result;
12110 }
12111 
12112 isc_result_t
12113 named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
12114 	char *ptr;
12115 	char *endp;
12116 	long newlevel;
12117 
12118 	UNUSED(server);
12119 
12120 	/* Skip the command name. */
12121 	ptr = next_token(lex, NULL);
12122 	if (ptr == NULL) {
12123 		return ISC_R_UNEXPECTEDEND;
12124 	}
12125 
12126 	/* Look for the new level name. */
12127 	ptr = next_token(lex, NULL);
12128 	if (ptr == NULL) {
12129 		if (named_g_debuglevel < 99) {
12130 			named_g_debuglevel++;
12131 		}
12132 	} else {
12133 		newlevel = strtol(ptr, &endp, 10);
12134 		if (*endp != '\0' || newlevel < 0 || newlevel > 99) {
12135 			return ISC_R_RANGE;
12136 		}
12137 		named_g_debuglevel = (unsigned int)newlevel;
12138 	}
12139 	isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel);
12140 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12141 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12142 		      "debug level is now %u", named_g_debuglevel);
12143 	return ISC_R_SUCCESS;
12144 }
12145 
12146 isc_result_t
12147 named_server_validation(named_server_t *server, isc_lex_t *lex,
12148 			isc_buffer_t **text) {
12149 	char *ptr;
12150 	dns_view_t *view;
12151 	bool changed = false;
12152 	isc_result_t result;
12153 	bool enable = true, set = true, first = true;
12154 
12155 	REQUIRE(text != NULL);
12156 
12157 	/* Skip the command name. */
12158 	ptr = next_token(lex, text);
12159 	if (ptr == NULL) {
12160 		return ISC_R_UNEXPECTEDEND;
12161 	}
12162 
12163 	/* Find out what we are to do. */
12164 	ptr = next_token(lex, text);
12165 	if (ptr == NULL) {
12166 		return ISC_R_UNEXPECTEDEND;
12167 	}
12168 
12169 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
12170 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
12171 	{
12172 		enable = true;
12173 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
12174 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
12175 	{
12176 		enable = false;
12177 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
12178 		set = false;
12179 	} else {
12180 		return DNS_R_SYNTAX;
12181 	}
12182 
12183 	/* Look for the view name. */
12184 	ptr = next_token(lex, text);
12185 
12186 	isc_loopmgr_pause(named_g_loopmgr);
12187 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12188 	     view = ISC_LIST_NEXT(view, link))
12189 	{
12190 		if ((ptr != NULL && strcasecmp(ptr, view->name) != 0) ||
12191 		    strcasecmp("_bind", view->name) == 0)
12192 		{
12193 			continue;
12194 		}
12195 
12196 		if (set) {
12197 			CHECK(dns_view_flushcache(view, false));
12198 			view->enablevalidation = enable;
12199 			changed = true;
12200 		} else {
12201 			if (!first) {
12202 				CHECK(putstr(text, "\n"));
12203 			}
12204 			CHECK(putstr(text, "DNSSEC validation is "));
12205 			CHECK(putstr(text, view->enablevalidation
12206 						   ? "enabled"
12207 						   : "disabled"));
12208 			CHECK(putstr(text, " (view "));
12209 			CHECK(putstr(text, view->name));
12210 			CHECK(putstr(text, ")"));
12211 			first = false;
12212 		}
12213 	}
12214 	CHECK(putnull(text));
12215 
12216 	if (!set) {
12217 		result = ISC_R_SUCCESS;
12218 	} else if (changed) {
12219 		result = ISC_R_SUCCESS;
12220 	} else {
12221 		result = ISC_R_FAILURE;
12222 	}
12223 cleanup:
12224 	isc_loopmgr_resume(named_g_loopmgr);
12225 	return result;
12226 }
12227 
12228 isc_result_t
12229 named_server_flushcache(named_server_t *server, isc_lex_t *lex) {
12230 	char *ptr;
12231 	dns_view_t *view;
12232 	bool flushed;
12233 	bool found;
12234 	isc_result_t result;
12235 	named_cache_t *nsc;
12236 
12237 	/* Skip the command name. */
12238 	ptr = next_token(lex, NULL);
12239 	if (ptr == NULL) {
12240 		return ISC_R_UNEXPECTEDEND;
12241 	}
12242 
12243 	/* Look for the view name. */
12244 	ptr = next_token(lex, NULL);
12245 
12246 	isc_loopmgr_pause(named_g_loopmgr);
12247 	flushed = true;
12248 	found = false;
12249 
12250 	/*
12251 	 * Flushing a cache is tricky when caches are shared by multiple views.
12252 	 * We first identify which caches should be flushed in the local cache
12253 	 * list, flush these caches, and then update other views that refer to
12254 	 * the flushed cache DB.
12255 	 */
12256 	if (ptr != NULL) {
12257 		/*
12258 		 * Mark caches that need to be flushed.  This is an O(#view^2)
12259 		 * operation in the very worst case, but should be normally
12260 		 * much more lightweight because only a few (most typically just
12261 		 * one) views will match.
12262 		 */
12263 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12264 		     view = ISC_LIST_NEXT(view, link))
12265 		{
12266 			if (strcasecmp(ptr, view->name) != 0) {
12267 				continue;
12268 			}
12269 			found = true;
12270 			for (nsc = ISC_LIST_HEAD(server->cachelist);
12271 			     nsc != NULL; nsc = ISC_LIST_NEXT(nsc, link))
12272 			{
12273 				if (nsc->cache == view->cache) {
12274 					break;
12275 				}
12276 			}
12277 			INSIST(nsc != NULL);
12278 			nsc->needflush = true;
12279 		}
12280 	} else {
12281 		found = true;
12282 	}
12283 
12284 	/* Perform flush */
12285 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12286 	     nsc = ISC_LIST_NEXT(nsc, link))
12287 	{
12288 		if (ptr != NULL && !nsc->needflush) {
12289 			continue;
12290 		}
12291 		nsc->needflush = true;
12292 		result = dns_view_flushcache(nsc->primaryview, false);
12293 		if (result != ISC_R_SUCCESS) {
12294 			flushed = false;
12295 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12296 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12297 				      "flushing cache in view '%s' failed: %s",
12298 				      nsc->primaryview->name,
12299 				      isc_result_totext(result));
12300 		}
12301 	}
12302 
12303 	/*
12304 	 * Fix up views that share a flushed cache: let the views update the
12305 	 * cache DB they're referring to.  This could also be an expensive
12306 	 * operation, but should typically be marginal: the inner loop is only
12307 	 * necessary for views that share a cache, and if there are many such
12308 	 * views the number of shared cache should normally be small.
12309 	 * A worst case is that we have n views and n/2 caches, each shared by
12310 	 * two views.  Then this will be a O(n^2/4) operation.
12311 	 */
12312 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12313 	     view = ISC_LIST_NEXT(view, link))
12314 	{
12315 		if (!dns_view_iscacheshared(view)) {
12316 			continue;
12317 		}
12318 		for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12319 		     nsc = ISC_LIST_NEXT(nsc, link))
12320 		{
12321 			if (!nsc->needflush || nsc->cache != view->cache) {
12322 				continue;
12323 			}
12324 			result = dns_view_flushcache(view, true);
12325 			if (result != ISC_R_SUCCESS) {
12326 				flushed = false;
12327 				isc_log_write(
12328 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12329 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12330 					"fixing cache in view '%s' "
12331 					"failed: %s",
12332 					view->name, isc_result_totext(result));
12333 			}
12334 		}
12335 	}
12336 
12337 	/* Cleanup the cache list. */
12338 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12339 	     nsc = ISC_LIST_NEXT(nsc, link))
12340 	{
12341 		nsc->needflush = false;
12342 	}
12343 
12344 	if (flushed && found) {
12345 		if (ptr != NULL) {
12346 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12347 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12348 				      "flushing cache in view '%s' succeeded",
12349 				      ptr);
12350 		} else {
12351 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12352 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12353 				      "flushing caches in all views succeeded");
12354 		}
12355 		result = ISC_R_SUCCESS;
12356 	} else {
12357 		if (!found) {
12358 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12359 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12360 				      "flushing cache in view '%s' failed: "
12361 				      "view not found",
12362 				      ptr);
12363 			result = ISC_R_NOTFOUND;
12364 		} else {
12365 			result = ISC_R_FAILURE;
12366 		}
12367 	}
12368 	isc_loopmgr_resume(named_g_loopmgr);
12369 	return result;
12370 }
12371 
12372 isc_result_t
12373 named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) {
12374 	char *ptr, *viewname;
12375 	char target[DNS_NAME_FORMATSIZE];
12376 	dns_view_t *view;
12377 	bool flushed;
12378 	bool found;
12379 	isc_result_t result;
12380 	isc_buffer_t b;
12381 	dns_fixedname_t fixed;
12382 	dns_name_t *name;
12383 
12384 	/* Skip the command name. */
12385 	ptr = next_token(lex, NULL);
12386 	if (ptr == NULL) {
12387 		return ISC_R_UNEXPECTEDEND;
12388 	}
12389 
12390 	/* Find the domain name to flush. */
12391 	ptr = next_token(lex, NULL);
12392 	if (ptr == NULL) {
12393 		return ISC_R_UNEXPECTEDEND;
12394 	}
12395 
12396 	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
12397 	isc_buffer_constinit(&b, target, strlen(target));
12398 	isc_buffer_add(&b, strlen(target));
12399 	name = dns_fixedname_initname(&fixed);
12400 	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
12401 	if (result != ISC_R_SUCCESS) {
12402 		return result;
12403 	}
12404 
12405 	/* Look for the view name. */
12406 	viewname = next_token(lex, NULL);
12407 
12408 	isc_loopmgr_pause(named_g_loopmgr);
12409 	flushed = true;
12410 	found = false;
12411 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12412 	     view = ISC_LIST_NEXT(view, link))
12413 	{
12414 		if (viewname != NULL && strcasecmp(viewname, view->name) != 0) {
12415 			continue;
12416 		}
12417 		found = true;
12418 		/*
12419 		 * It's a little inefficient to try flushing name for all views
12420 		 * if some of the views share a single cache.  But since the
12421 		 * operation is lightweight we prefer simplicity here.
12422 		 */
12423 		result = dns_view_flushnode(view, name, tree);
12424 		if (result != ISC_R_SUCCESS) {
12425 			flushed = false;
12426 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12427 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12428 				      "flushing %s '%s' in cache view '%s' "
12429 				      "failed: %s",
12430 				      tree ? "tree" : "name", target,
12431 				      view->name, isc_result_totext(result));
12432 		}
12433 	}
12434 	if (flushed && found) {
12435 		if (viewname != NULL) {
12436 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12437 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12438 				      "flushing %s '%s' in cache view '%s' "
12439 				      "succeeded",
12440 				      tree ? "tree" : "name", target, viewname);
12441 		} else {
12442 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12443 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12444 				      "flushing %s '%s' in all cache views "
12445 				      "succeeded",
12446 				      tree ? "tree" : "name", target);
12447 		}
12448 		result = ISC_R_SUCCESS;
12449 	} else {
12450 		if (!found) {
12451 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12452 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12453 				      "flushing %s '%s' in cache view '%s' "
12454 				      "failed: view not found",
12455 				      tree ? "tree" : "name", target, viewname);
12456 		}
12457 		result = ISC_R_FAILURE;
12458 	}
12459 	isc_loopmgr_resume(named_g_loopmgr);
12460 	return result;
12461 }
12462 
12463 isc_result_t
12464 named_server_status(named_server_t *server, isc_buffer_t **text) {
12465 	isc_result_t result;
12466 	unsigned int zonecount, xferrunning, xferdeferred, xferfirstrefresh;
12467 	unsigned int soaqueries, automatic;
12468 	const char *ob = "", *cb = "", *alt = "";
12469 	char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
12470 	char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
12471 	char line[1024], hostname[256];
12472 	named_reload_t reload_status;
12473 
12474 	REQUIRE(text != NULL);
12475 
12476 	if (named_g_server->version_set) {
12477 		ob = " (";
12478 		cb = ")";
12479 		if (named_g_server->version == NULL) {
12480 			alt = "version.bind/txt/ch disabled";
12481 		} else {
12482 			alt = named_g_server->version;
12483 		}
12484 	}
12485 	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
12486 	xferrunning = dns_zonemgr_getcount(server->zonemgr,
12487 					   DNS_ZONESTATE_XFERRUNNING);
12488 	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
12489 					    DNS_ZONESTATE_XFERDEFERRED);
12490 	xferfirstrefresh = dns_zonemgr_getcount(server->zonemgr,
12491 						DNS_ZONESTATE_XFERFIRSTREFRESH);
12492 	soaqueries = dns_zonemgr_getcount(server->zonemgr,
12493 					  DNS_ZONESTATE_SOAQUERY);
12494 	automatic = dns_zonemgr_getcount(server->zonemgr,
12495 					 DNS_ZONESTATE_AUTOMATIC);
12496 
12497 	isc_time_formathttptimestamp(&named_g_boottime, boottime,
12498 				     sizeof(boottime));
12499 	isc_time_formathttptimestamp(&named_g_configtime, configtime,
12500 				     sizeof(configtime));
12501 
12502 	snprintf(line, sizeof(line), "version: %s%s <id:%s>%s%s%s\n",
12503 		 PACKAGE_STRING, PACKAGE_DESCRIPTION, PACKAGE_SRCID, ob, alt,
12504 		 cb);
12505 	CHECK(putstr(text, line));
12506 
12507 	if (gethostname(hostname, sizeof(hostname)) == 0) {
12508 		strlcpy(hostname, "localhost", sizeof(hostname));
12509 	}
12510 	snprintf(line, sizeof(line), "running on %s: %s\n", hostname,
12511 		 named_os_uname());
12512 	CHECK(putstr(text, line));
12513 
12514 	snprintf(line, sizeof(line), "boot time: %s\n", boottime);
12515 	CHECK(putstr(text, line));
12516 
12517 	snprintf(line, sizeof(line), "last configured: %s\n", configtime);
12518 	CHECK(putstr(text, line));
12519 
12520 	if (named_g_chrootdir != NULL) {
12521 		snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n",
12522 			 named_g_conffile, named_g_chrootdir, named_g_conffile);
12523 	} else {
12524 		snprintf(line, sizeof(line), "configuration file: %s\n",
12525 			 named_g_conffile);
12526 	}
12527 	CHECK(putstr(text, line));
12528 
12529 	snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected);
12530 	CHECK(putstr(text, line));
12531 
12532 	snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
12533 	CHECK(putstr(text, line));
12534 
12535 	snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
12536 		 zonecount, automatic);
12537 	CHECK(putstr(text, line));
12538 
12539 	snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel);
12540 	CHECK(putstr(text, line));
12541 
12542 	snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
12543 	CHECK(putstr(text, line));
12544 
12545 	snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
12546 	CHECK(putstr(text, line));
12547 
12548 	snprintf(line, sizeof(line), "xfers first refresh: %u\n",
12549 		 xferfirstrefresh);
12550 	CHECK(putstr(text, line));
12551 
12552 	snprintf(line, sizeof(line), "soa queries in progress: %u\n",
12553 		 soaqueries);
12554 	CHECK(putstr(text, line));
12555 
12556 	snprintf(line, sizeof(line), "query logging is %s\n",
12557 		 ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES)
12558 			 ? "ON"
12559 			 : "OFF");
12560 	CHECK(putstr(text, line));
12561 
12562 	snprintf(line, sizeof(line), "response logging is %s\n",
12563 		 ns_server_getoption(server->sctx, NS_SERVER_LOGRESPONSES)
12564 			 ? "ON"
12565 			 : "OFF");
12566 	CHECK(putstr(text, line));
12567 
12568 	snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
12569 		 isc_quota_getused(&server->sctx->recursionquota),
12570 		 isc_quota_getsoft(&server->sctx->recursionquota),
12571 		 isc_quota_getmax(&server->sctx->recursionquota));
12572 	CHECK(putstr(text, line));
12573 
12574 	snprintf(line, sizeof(line), "recursive high-water: %u\n",
12575 		 (unsigned int)ns_stats_get_counter(
12576 			 server->sctx->nsstats,
12577 			 ns_statscounter_recurshighwater));
12578 	CHECK(putstr(text, line));
12579 
12580 	snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
12581 		 isc_quota_getused(&server->sctx->tcpquota),
12582 		 isc_quota_getmax(&server->sctx->tcpquota));
12583 	CHECK(putstr(text, line));
12584 
12585 	snprintf(line, sizeof(line), "TCP high-water: %u\n",
12586 		 (unsigned int)ns_stats_get_counter(
12587 			 server->sctx->nsstats, ns_statscounter_tcphighwater));
12588 	CHECK(putstr(text, line));
12589 
12590 	reload_status = atomic_load(&server->reload_status);
12591 	if (reload_status != NAMED_RELOAD_DONE) {
12592 		snprintf(line, sizeof(line), "reload/reconfig %s\n",
12593 			 reload_status == NAMED_RELOAD_FAILED ? "failed"
12594 							      : "in progress");
12595 		CHECK(putstr(text, line));
12596 	}
12597 
12598 	CHECK(putstr(text, "server is up and running"));
12599 	CHECK(putnull(text));
12600 
12601 	return ISC_R_SUCCESS;
12602 cleanup:
12603 	return result;
12604 }
12605 
12606 isc_result_t
12607 named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) {
12608 	isc_result_t result;
12609 	char *ptr;
12610 	unsigned long count;
12611 	unsigned long i;
12612 	const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
12613 
12614 	REQUIRE(text != NULL);
12615 
12616 	/* Skip the command name. */
12617 	ptr = next_token(lex, text);
12618 	if (ptr == NULL) {
12619 		return ISC_R_UNEXPECTEDEND;
12620 	}
12621 
12622 	ptr = next_token(lex, text);
12623 	if (ptr == NULL) {
12624 		count = 26;
12625 	} else {
12626 		count = strtoul(ptr, NULL, 10);
12627 	}
12628 
12629 	CHECK(isc_buffer_reserve(*text, count));
12630 	for (i = 0; i < count; i++) {
12631 		CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
12632 	}
12633 
12634 	CHECK(putnull(text));
12635 
12636 cleanup:
12637 	return result;
12638 }
12639 
12640 /*
12641  * Act on a "sign" or "loadkeys" command from the command channel.
12642  */
12643 isc_result_t
12644 named_server_rekey(named_server_t *server, isc_lex_t *lex,
12645 		   isc_buffer_t **text) {
12646 	isc_result_t result;
12647 	dns_zone_t *zone = NULL;
12648 	dns_zonetype_t type;
12649 	uint16_t keyopts;
12650 	bool fullsign = false;
12651 	char *ptr;
12652 
12653 	REQUIRE(text != NULL);
12654 
12655 	ptr = next_token(lex, text);
12656 	if (ptr == NULL) {
12657 		return ISC_R_UNEXPECTEDEND;
12658 	}
12659 
12660 	if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0) {
12661 		fullsign = true;
12662 	}
12663 
12664 	REQUIRE(text != NULL);
12665 
12666 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, false);
12667 	if (result != ISC_R_SUCCESS) {
12668 		return result;
12669 	}
12670 	if (zone == NULL) {
12671 		return ISC_R_UNEXPECTEDEND; /* XXX: or do all zones? */
12672 	}
12673 
12674 	type = dns_zone_gettype(zone);
12675 	if (type != dns_zone_primary) {
12676 		dns_zone_detach(&zone);
12677 		return DNS_R_NOTPRIMARY;
12678 	}
12679 
12680 	keyopts = dns_zone_getkeyopts(zone);
12681 
12682 	/*
12683 	 * "rndc loadkeys" requires a "dnssec-policy".
12684 	 */
12685 	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) {
12686 		result = ISC_R_NOPERM;
12687 	} else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) {
12688 		result = ISC_R_NOPERM;
12689 	} else {
12690 		dns_zone_rekey(zone, fullsign);
12691 	}
12692 
12693 	dns_zone_detach(&zone);
12694 	return result;
12695 }
12696 
12697 /*
12698  * Act on a "sync" command from the command channel.
12699  */
12700 static isc_result_t
12701 synczone(dns_zone_t *zone, void *uap) {
12702 	bool cleanup = *(bool *)uap;
12703 	isc_result_t result;
12704 	dns_zone_t *raw = NULL;
12705 	char *journal;
12706 
12707 	dns_zone_getraw(zone, &raw);
12708 	if (raw != NULL) {
12709 		synczone(raw, uap);
12710 		dns_zone_detach(&raw);
12711 	}
12712 
12713 	result = dns_zone_flush(zone);
12714 	if (result != ISC_R_SUCCESS) {
12715 		cleanup = false;
12716 	}
12717 	if (cleanup) {
12718 		journal = dns_zone_getjournal(zone);
12719 		if (journal != NULL) {
12720 			(void)isc_file_remove(journal);
12721 		}
12722 	}
12723 
12724 	return result;
12725 }
12726 
12727 isc_result_t
12728 named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
12729 	isc_result_t result, tresult;
12730 	dns_view_t *view = NULL;
12731 	dns_zone_t *zone = NULL;
12732 	char classstr[DNS_RDATACLASS_FORMATSIZE];
12733 	char zonename[DNS_NAME_FORMATSIZE];
12734 	const char *vname = NULL, *sep = NULL, *arg = NULL;
12735 	bool cleanup = false;
12736 
12737 	REQUIRE(text != NULL);
12738 
12739 	(void)next_token(lex, text);
12740 
12741 	arg = next_token(lex, text);
12742 	if (arg != NULL &&
12743 	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0))
12744 	{
12745 		cleanup = true;
12746 		arg = next_token(lex, text);
12747 	}
12748 
12749 	REQUIRE(text != NULL);
12750 
12751 	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
12752 	if (result != ISC_R_SUCCESS) {
12753 		return result;
12754 	}
12755 
12756 	if (zone == NULL) {
12757 		isc_loopmgr_pause(named_g_loopmgr);
12758 		tresult = ISC_R_SUCCESS;
12759 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12760 		     view = ISC_LIST_NEXT(view, link))
12761 		{
12762 			result = dns_view_apply(view, false, NULL, synczone,
12763 						&cleanup);
12764 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12765 			{
12766 				tresult = result;
12767 			}
12768 		}
12769 		isc_loopmgr_resume(named_g_loopmgr);
12770 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12771 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12772 			      "dumping all zones%s: %s",
12773 			      cleanup ? ", removing journal files" : "",
12774 			      isc_result_totext(result));
12775 		return tresult;
12776 	}
12777 
12778 	isc_loopmgr_pause(named_g_loopmgr);
12779 	result = synczone(zone, &cleanup);
12780 	isc_loopmgr_resume(named_g_loopmgr);
12781 
12782 	view = dns_zone_getview(zone);
12783 	if (strcmp(view->name, "_default") == 0 ||
12784 	    strcmp(view->name, "_bind") == 0)
12785 	{
12786 		vname = "";
12787 		sep = "";
12788 	} else {
12789 		vname = view->name;
12790 		sep = " ";
12791 	}
12792 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
12793 			      sizeof(classstr));
12794 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
12795 	isc_log_write(
12796 		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12797 		ISC_LOG_INFO, "sync: dumping zone '%s/%s'%s%s%s: %s", zonename,
12798 		classstr, sep, vname, cleanup ? ", removing journal file" : "",
12799 		isc_result_totext(result));
12800 	dns_zone_detach(&zone);
12801 	return result;
12802 }
12803 
12804 /*
12805  * Act on a "freeze" or "thaw" command from the command channel.
12806  */
12807 isc_result_t
12808 named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex,
12809 		    isc_buffer_t **text) {
12810 	isc_result_t result, tresult;
12811 	dns_zone_t *mayberaw = NULL, *raw = NULL;
12812 	dns_zonetype_t type;
12813 	char classstr[DNS_RDATACLASS_FORMATSIZE];
12814 	char zonename[DNS_NAME_FORMATSIZE];
12815 	dns_view_t *view;
12816 	const char *vname, *sep;
12817 	bool frozen;
12818 	const char *msg = NULL;
12819 
12820 	REQUIRE(text != NULL);
12821 
12822 	result = zone_from_args(server, lex, NULL, &mayberaw, NULL, text, true);
12823 	if (result != ISC_R_SUCCESS) {
12824 		return result;
12825 	}
12826 	if (mayberaw == NULL) {
12827 		isc_loopmgr_pause(named_g_loopmgr);
12828 		tresult = ISC_R_SUCCESS;
12829 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12830 		     view = ISC_LIST_NEXT(view, link))
12831 		{
12832 			result = dns_view_freezezones(view, freeze);
12833 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12834 			{
12835 				tresult = result;
12836 			}
12837 		}
12838 		isc_loopmgr_resume(named_g_loopmgr);
12839 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12840 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12841 			      "%s all zones: %s",
12842 			      freeze ? "freezing" : "thawing",
12843 			      isc_result_totext(tresult));
12844 		return tresult;
12845 	}
12846 	dns_zone_getraw(mayberaw, &raw);
12847 	if (raw != NULL) {
12848 		dns_zone_detach(&mayberaw);
12849 		dns_zone_attach(raw, &mayberaw);
12850 		dns_zone_detach(&raw);
12851 	}
12852 	type = dns_zone_gettype(mayberaw);
12853 	if (type != dns_zone_primary) {
12854 		dns_zone_detach(&mayberaw);
12855 		return DNS_R_NOTPRIMARY;
12856 	}
12857 
12858 	if (freeze && !dns_zone_isdynamic(mayberaw, true)) {
12859 		dns_zone_detach(&mayberaw);
12860 		return DNS_R_NOTDYNAMIC;
12861 	}
12862 
12863 	isc_loopmgr_pause(named_g_loopmgr);
12864 	frozen = dns_zone_getupdatedisabled(mayberaw);
12865 	if (freeze) {
12866 		if (frozen) {
12867 			msg = "WARNING: The zone was already frozen.\n"
12868 			      "Someone else may be editing it or "
12869 			      "it may still be re-loading.";
12870 			result = DNS_R_FROZEN;
12871 		}
12872 		if (result == ISC_R_SUCCESS) {
12873 			result = dns_zone_flush(mayberaw);
12874 			if (result != ISC_R_SUCCESS) {
12875 				msg = "Flushing the zone updates to "
12876 				      "disk failed.";
12877 			}
12878 		}
12879 		if (result == ISC_R_SUCCESS) {
12880 			dns_zone_setupdatedisabled(mayberaw, freeze);
12881 		}
12882 	} else {
12883 		if (frozen) {
12884 			result = dns_zone_loadandthaw(mayberaw);
12885 			switch (result) {
12886 			case ISC_R_SUCCESS:
12887 			case DNS_R_UPTODATE:
12888 				msg = "The zone reload and thaw was "
12889 				      "successful.";
12890 				result = ISC_R_SUCCESS;
12891 				break;
12892 			case DNS_R_CONTINUE:
12893 				msg = "A zone reload and thaw was started.\n"
12894 				      "Check the logs to see the result.";
12895 				result = ISC_R_SUCCESS;
12896 				break;
12897 			default:
12898 				break;
12899 			}
12900 		}
12901 	}
12902 	isc_loopmgr_resume(named_g_loopmgr);
12903 
12904 	if (msg != NULL) {
12905 		(void)putstr(text, msg);
12906 		(void)putnull(text);
12907 	}
12908 
12909 	view = dns_zone_getview(mayberaw);
12910 	if (strcmp(view->name, "_default") == 0 ||
12911 	    strcmp(view->name, "_bind") == 0)
12912 	{
12913 		vname = "";
12914 		sep = "";
12915 	} else {
12916 		vname = view->name;
12917 		sep = " ";
12918 	}
12919 	dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr,
12920 			      sizeof(classstr));
12921 	dns_name_format(dns_zone_getorigin(mayberaw), zonename,
12922 			sizeof(zonename));
12923 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12924 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12925 		      "%s zone '%s/%s'%s%s: %s",
12926 		      freeze ? "freezing" : "thawing", zonename, classstr, sep,
12927 		      vname, isc_result_totext(result));
12928 	dns_zone_detach(&mayberaw);
12929 	return result;
12930 }
12931 
12932 #ifdef HAVE_LIBSCF
12933 /*
12934  * This function adds a message for rndc to echo if named
12935  * is managed by smf and is also running chroot.
12936  */
12937 isc_result_t
12938 named_smf_add_message(isc_buffer_t **text) {
12939 	REQUIRE(text != NULL);
12940 
12941 	return putstr(text, "use svcadm(1M) to manage named");
12942 }
12943 #endif /* HAVE_LIBSCF */
12944 
12945 #ifndef HAVE_LMDB
12946 
12947 /*
12948  * Emit a comment at the top of the nzf file containing the viewname
12949  * Expects the fp to already be open for writing
12950  */
12951 #define HEADER1 "# New zone file for view: "
12952 #define HEADER2                                                     \
12953 	"\n# This file contains configuration for zones added by\n" \
12954 	"# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
12955 static isc_result_t
12956 add_comment(FILE *fp, const char *viewname) {
12957 	isc_result_t result;
12958 	CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
12959 	CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
12960 	CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
12961 cleanup:
12962 	return result;
12963 }
12964 
12965 static void
12966 dumpzone(void *arg, const char *buf, int len) {
12967 	FILE *fp = arg;
12968 
12969 	(void)isc_stdio_write(buf, len, 1, fp, NULL);
12970 }
12971 
12972 static isc_result_t
12973 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
12974 	isc_result_t result;
12975 	off_t offset;
12976 	FILE *fp = NULL;
12977 	bool offsetok = false;
12978 
12979 	LOCK(&view->new_zone_lock);
12980 
12981 	CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
12982 	CHECK(isc_stdio_seek(fp, 0, SEEK_END));
12983 
12984 	CHECK(isc_stdio_tell(fp, &offset));
12985 	offsetok = true;
12986 	if (offset == 0) {
12987 		CHECK(add_comment(fp, view->name));
12988 	}
12989 
12990 	CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
12991 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
12992 	CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
12993 	CHECK(isc_stdio_flush(fp));
12994 	result = isc_stdio_close(fp);
12995 	fp = NULL;
12996 
12997 cleanup:
12998 	if (fp != NULL) {
12999 		(void)isc_stdio_close(fp);
13000 		if (offsetok) {
13001 			isc_result_t result2;
13002 
13003 			result2 = isc_file_truncate(view->new_zone_file,
13004 						    offset);
13005 			if (result2 != ISC_R_SUCCESS) {
13006 				isc_log_write(
13007 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13008 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13009 					"Error truncating NZF file '%s' "
13010 					"during rollback from append: "
13011 					"%s",
13012 					view->new_zone_file,
13013 					isc_result_totext(result2));
13014 			}
13015 		}
13016 	}
13017 	UNLOCK(&view->new_zone_lock);
13018 	return result;
13019 }
13020 
13021 static isc_result_t
13022 nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
13023 	const cfg_obj_t *zl = NULL;
13024 	cfg_list_t *list;
13025 	const cfg_listelt_t *elt;
13026 
13027 	FILE *fp = NULL;
13028 	char tmp[1024];
13029 	isc_result_t result;
13030 
13031 	result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp,
13032 				   sizeof(tmp));
13033 	if (result == ISC_R_SUCCESS) {
13034 		result = isc_file_openunique(tmp, &fp);
13035 	}
13036 	if (result != ISC_R_SUCCESS) {
13037 		return result;
13038 	}
13039 
13040 	cfg_map_get(config, "zone", &zl);
13041 	if (!cfg_obj_islist(zl)) {
13042 		CHECK(ISC_R_FAILURE);
13043 	}
13044 
13045 	list = UNCONST(&zl->value.list);
13046 
13047 	CHECK(add_comment(fp, view->name)); /* force a comment */
13048 
13049 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13050 	     elt = ISC_LIST_NEXT(elt, link))
13051 	{
13052 		const cfg_obj_t *zconfig = cfg_listelt_value(elt);
13053 
13054 		CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
13055 		cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
13056 		CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
13057 	}
13058 
13059 	CHECK(isc_stdio_flush(fp));
13060 	result = isc_stdio_close(fp);
13061 	fp = NULL;
13062 	if (result != ISC_R_SUCCESS) {
13063 		goto cleanup;
13064 	}
13065 	CHECK(isc_file_rename(tmp, view->new_zone_file));
13066 	return result;
13067 
13068 cleanup:
13069 	if (fp != NULL) {
13070 		(void)isc_stdio_close(fp);
13071 	}
13072 	(void)isc_file_remove(tmp);
13073 	return result;
13074 }
13075 
13076 static isc_result_t
13077 load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
13078 	isc_result_t result;
13079 
13080 	/* The new zone file may not exist. That is OK. */
13081 	if (!isc_file_exists(view->new_zone_file)) {
13082 		return ISC_R_SUCCESS;
13083 	}
13084 
13085 	/*
13086 	 * Parse the configuration in the NZF file.  This may be called in
13087 	 * multiple views, so we reset the parser each time.
13088 	 */
13089 	cfg_parser_reset(named_g_addparser);
13090 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
13091 				&cfg_type_addzoneconf, &nzcfg->nzf_config);
13092 	if (result != ISC_R_SUCCESS) {
13093 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13094 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13095 			      "Error parsing NZF file '%s': %s",
13096 			      view->new_zone_file, isc_result_totext(result));
13097 	}
13098 
13099 	return result;
13100 }
13101 #else  /* HAVE_LMDB */
13102 
13103 static void
13104 nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
13105 	dns_fixedname_t fixed;
13106 
13107 	dns_fixedname_init(&fixed);
13108 	dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
13109 	dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
13110 
13111 	key->mv_data = namebuf;
13112 	key->mv_size = strlen(namebuf);
13113 }
13114 
13115 static void
13116 dumpzone(void *arg, const char *buf, int len) {
13117 	ns_dzarg_t *dzarg = arg;
13118 	isc_result_t result;
13119 
13120 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
13121 
13122 	result = putmem(dzarg->text, buf, len);
13123 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
13124 		dzarg->result = result;
13125 	}
13126 }
13127 
13128 static isc_result_t
13129 nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
13130 	 const cfg_obj_t *zconfig) {
13131 	isc_result_t result;
13132 	int status;
13133 	dns_view_t *view;
13134 	bool commit = false;
13135 	isc_buffer_t *text = NULL;
13136 	char namebuf[1024];
13137 	MDB_val key, data;
13138 	ns_dzarg_t dzarg;
13139 
13140 	view = dns_zone_getview(zone);
13141 
13142 	nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
13143 
13144 	if (zconfig == NULL) {
13145 		/* We're deleting the zone from the database */
13146 		status = mdb_del(*txnp, dbi, &key, NULL);
13147 		if (status != MDB_SUCCESS && status != MDB_NOTFOUND) {
13148 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13149 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13150 				      "Error deleting zone %s "
13151 				      "from NZD database: %s",
13152 				      namebuf, mdb_strerror(status));
13153 			result = ISC_R_FAILURE;
13154 			goto cleanup;
13155 		} else if (status != MDB_NOTFOUND) {
13156 			commit = true;
13157 		}
13158 	} else {
13159 		/* We're creating or overwriting the zone */
13160 		const cfg_obj_t *zoptions;
13161 
13162 		isc_buffer_allocate(view->mctx, &text, 256);
13163 
13164 		zoptions = cfg_tuple_get(zconfig, "options");
13165 		if (zoptions == NULL) {
13166 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13167 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13168 				      "Unable to get options from config in "
13169 				      "nzd_save()");
13170 			result = ISC_R_FAILURE;
13171 			goto cleanup;
13172 		}
13173 
13174 		dzarg.magic = DZARG_MAGIC;
13175 		dzarg.text = &text;
13176 		dzarg.result = ISC_R_SUCCESS;
13177 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13178 		if (dzarg.result != ISC_R_SUCCESS) {
13179 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13180 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13181 				      "Error writing zone config to "
13182 				      "buffer in nzd_save(): %s",
13183 				      isc_result_totext(dzarg.result));
13184 			result = dzarg.result;
13185 			goto cleanup;
13186 		}
13187 
13188 		data.mv_data = isc_buffer_base(text);
13189 		data.mv_size = isc_buffer_usedlength(text);
13190 
13191 		status = mdb_put(*txnp, dbi, &key, &data, 0);
13192 		if (status != MDB_SUCCESS) {
13193 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13194 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13195 				      "Error inserting zone in "
13196 				      "NZD database: %s",
13197 				      mdb_strerror(status));
13198 			result = ISC_R_FAILURE;
13199 			goto cleanup;
13200 		}
13201 
13202 		commit = true;
13203 	}
13204 
13205 	result = ISC_R_SUCCESS;
13206 
13207 cleanup:
13208 	if (!commit || result != ISC_R_SUCCESS) {
13209 		(void)mdb_txn_abort(*txnp);
13210 	} else {
13211 		status = mdb_txn_commit(*txnp);
13212 		if (status != MDB_SUCCESS) {
13213 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13214 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13215 				      "Error committing "
13216 				      "NZD database: %s",
13217 				      mdb_strerror(status));
13218 			result = ISC_R_FAILURE;
13219 		}
13220 	}
13221 	*txnp = NULL;
13222 
13223 	if (text != NULL) {
13224 		isc_buffer_free(&text);
13225 	}
13226 
13227 	return result;
13228 }
13229 
13230 /*
13231  * Check whether the new zone database for 'view' can be opened for writing.
13232  *
13233  * Caller must hold 'view->new_zone_lock'.
13234  */
13235 static isc_result_t
13236 nzd_writable(dns_view_t *view) {
13237 	isc_result_t result = ISC_R_SUCCESS;
13238 	int status;
13239 	MDB_dbi dbi;
13240 	MDB_txn *txn = NULL;
13241 
13242 	REQUIRE(view != NULL);
13243 
13244 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn);
13245 	if (status != MDB_SUCCESS) {
13246 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13247 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13248 			      "mdb_txn_begin: %s", mdb_strerror(status));
13249 		return ISC_R_FAILURE;
13250 	}
13251 
13252 	status = mdb_dbi_open(txn, NULL, 0, &dbi);
13253 	if (status != MDB_SUCCESS) {
13254 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13255 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13256 			      "mdb_dbi_open: %s", mdb_strerror(status));
13257 		result = ISC_R_FAILURE;
13258 	}
13259 
13260 	mdb_txn_abort(txn);
13261 	return result;
13262 }
13263 
13264 /*
13265  * Open the new zone database for 'view' and start a transaction for it.
13266  *
13267  * Caller must hold 'view->new_zone_lock'.
13268  */
13269 static isc_result_t
13270 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
13271 	int status;
13272 	MDB_txn *txn = NULL;
13273 
13274 	REQUIRE(view != NULL);
13275 	REQUIRE(txnp != NULL && *txnp == NULL);
13276 	REQUIRE(dbi != NULL);
13277 
13278 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn);
13279 	if (status != MDB_SUCCESS) {
13280 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13281 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13282 			      "mdb_txn_begin: %s", mdb_strerror(status));
13283 		goto cleanup;
13284 	}
13285 
13286 	status = mdb_dbi_open(txn, NULL, 0, dbi);
13287 	if (status != MDB_SUCCESS) {
13288 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13289 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13290 			      "mdb_dbi_open: %s", mdb_strerror(status));
13291 		goto cleanup;
13292 	}
13293 
13294 	*txnp = txn;
13295 
13296 cleanup:
13297 	if (status != MDB_SUCCESS) {
13298 		if (txn != NULL) {
13299 			mdb_txn_abort(txn);
13300 		}
13301 		return ISC_R_FAILURE;
13302 	}
13303 
13304 	return ISC_R_SUCCESS;
13305 }
13306 
13307 /*
13308  * nzd_env_close() and nzd_env_reopen are a kluge to address the
13309  * problem of an NZD file possibly being created before we drop
13310  * root privileges.
13311  */
13312 static void
13313 nzd_env_close(dns_view_t *view) {
13314 	const char *dbpath = NULL;
13315 	char dbpath_copy[PATH_MAX];
13316 	char lockpath[PATH_MAX];
13317 	int status, ret;
13318 
13319 	if (view->new_zone_dbenv == NULL) {
13320 		return;
13321 	}
13322 
13323 	status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
13324 	INSIST(status == MDB_SUCCESS);
13325 	snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
13326 	strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
13327 	mdb_env_close((MDB_env *)view->new_zone_dbenv);
13328 
13329 	/*
13330 	 * Database files must be owned by the eventual user, not by root.
13331 	 */
13332 	ret = chown(dbpath_copy, named_os_uid(), -1);
13333 	UNUSED(ret);
13334 
13335 	/*
13336 	 * Some platforms need the lockfile not to exist when we reopen the
13337 	 * environment.
13338 	 */
13339 	(void)isc_file_remove(lockpath);
13340 
13341 	view->new_zone_dbenv = NULL;
13342 }
13343 
13344 static isc_result_t
13345 nzd_env_reopen(dns_view_t *view) {
13346 	isc_result_t result;
13347 	MDB_env *env = NULL;
13348 	int status;
13349 
13350 	if (view->new_zone_db == NULL) {
13351 		return ISC_R_SUCCESS;
13352 	}
13353 
13354 	nzd_env_close(view);
13355 
13356 	status = mdb_env_create(&env);
13357 	if (status != MDB_SUCCESS) {
13358 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13359 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13360 			      "mdb_env_create failed: %s",
13361 			      mdb_strerror(status));
13362 		CHECK(ISC_R_FAILURE);
13363 	}
13364 
13365 	if (view->new_zone_mapsize != 0ULL) {
13366 		status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
13367 		if (status != MDB_SUCCESS) {
13368 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13369 				      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13370 				      "mdb_env_set_mapsize failed: %s",
13371 				      mdb_strerror(status));
13372 			CHECK(ISC_R_FAILURE);
13373 		}
13374 	}
13375 
13376 	status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
13377 	if (status != MDB_SUCCESS) {
13378 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13379 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13380 			      "mdb_env_open of '%s' failed: %s",
13381 			      view->new_zone_db, mdb_strerror(status));
13382 		CHECK(ISC_R_FAILURE);
13383 	}
13384 
13385 	view->new_zone_dbenv = env;
13386 	env = NULL;
13387 	result = ISC_R_SUCCESS;
13388 
13389 cleanup:
13390 	if (env != NULL) {
13391 		mdb_env_close(env);
13392 	}
13393 	return result;
13394 }
13395 
13396 /*
13397  * If 'commit' is true, commit the new zone database transaction pointed to by
13398  * 'txnp'; otherwise, abort that transaction.
13399  *
13400  * Caller must hold 'view->new_zone_lock' for the view that the transaction
13401  * pointed to by 'txnp' was started for.
13402  */
13403 static isc_result_t
13404 nzd_close(MDB_txn **txnp, bool commit) {
13405 	isc_result_t result = ISC_R_SUCCESS;
13406 	int status;
13407 
13408 	REQUIRE(txnp != NULL);
13409 
13410 	if (*txnp != NULL) {
13411 		if (commit) {
13412 			status = mdb_txn_commit(*txnp);
13413 			if (status != MDB_SUCCESS) {
13414 				result = ISC_R_FAILURE;
13415 			}
13416 		} else {
13417 			mdb_txn_abort(*txnp);
13418 		}
13419 		*txnp = NULL;
13420 	}
13421 
13422 	return result;
13423 }
13424 
13425 /*
13426  * If there's an existing NZF file, load it and migrate its data
13427  * to the NZD.
13428  *
13429  * Caller must hold view->new_zone_lock.
13430  */
13431 static isc_result_t
13432 load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
13433 	isc_result_t result;
13434 	cfg_obj_t *nzf_config = NULL;
13435 	int status;
13436 	isc_buffer_t *text = NULL;
13437 	bool commit = false;
13438 	const cfg_obj_t *zonelist;
13439 	const cfg_listelt_t *element;
13440 	char tempname[PATH_MAX];
13441 	MDB_txn *txn = NULL;
13442 	MDB_dbi dbi;
13443 	MDB_val key, data;
13444 	ns_dzarg_t dzarg;
13445 
13446 	UNUSED(nzcfg);
13447 
13448 	/*
13449 	 * If NZF file doesn't exist, or NZD DB exists and already
13450 	 * has data, return without attempting migration.
13451 	 */
13452 	if (!isc_file_exists(view->new_zone_file)) {
13453 		result = ISC_R_SUCCESS;
13454 		goto cleanup;
13455 	}
13456 
13457 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13458 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13459 		      "Migrating zones from NZF file '%s' to "
13460 		      "NZD database '%s'",
13461 		      view->new_zone_file, view->new_zone_db);
13462 	/*
13463 	 * Instead of blindly copying lines, we parse the NZF file using
13464 	 * the configuration parser, because it validates it against the
13465 	 * config type, giving us a guarantee that valid configuration
13466 	 * will be written to DB.
13467 	 */
13468 	cfg_parser_reset(named_g_addparser);
13469 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
13470 				&cfg_type_addzoneconf, &nzf_config);
13471 	if (result != ISC_R_SUCCESS) {
13472 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13473 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13474 			      "Error parsing NZF file '%s': %s",
13475 			      view->new_zone_file, isc_result_totext(result));
13476 		goto cleanup;
13477 	}
13478 
13479 	zonelist = NULL;
13480 	CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
13481 	if (!cfg_obj_islist(zonelist)) {
13482 		CHECK(ISC_R_FAILURE);
13483 	}
13484 
13485 	CHECK(nzd_open(view, 0, &txn, &dbi));
13486 
13487 	isc_buffer_allocate(view->mctx, &text, 256);
13488 
13489 	for (element = cfg_list_first(zonelist); element != NULL;
13490 	     element = cfg_list_next(element))
13491 	{
13492 		const cfg_obj_t *zconfig;
13493 		const cfg_obj_t *zoptions;
13494 		char zname[DNS_NAME_FORMATSIZE];
13495 		dns_fixedname_t fname;
13496 		dns_name_t *name;
13497 		const char *origin;
13498 		isc_buffer_t b;
13499 
13500 		zconfig = cfg_listelt_value(element);
13501 
13502 		origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
13503 		if (origin == NULL) {
13504 			result = ISC_R_FAILURE;
13505 			goto cleanup;
13506 		}
13507 
13508 		/* Normalize zone name */
13509 		isc_buffer_constinit(&b, origin, strlen(origin));
13510 		isc_buffer_add(&b, strlen(origin));
13511 		name = dns_fixedname_initname(&fname);
13512 		CHECK(dns_name_fromtext(name, &b, dns_rootname,
13513 					DNS_NAME_DOWNCASE, NULL));
13514 		dns_name_format(name, zname, sizeof(zname));
13515 
13516 		key.mv_data = zname;
13517 		key.mv_size = strlen(zname);
13518 
13519 		zoptions = cfg_tuple_get(zconfig, "options");
13520 		if (zoptions == NULL) {
13521 			result = ISC_R_FAILURE;
13522 			goto cleanup;
13523 		}
13524 
13525 		isc_buffer_clear(text);
13526 		dzarg.magic = DZARG_MAGIC;
13527 		dzarg.text = &text;
13528 		dzarg.result = ISC_R_SUCCESS;
13529 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13530 		if (dzarg.result != ISC_R_SUCCESS) {
13531 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13532 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13533 				      "Error writing zone config to "
13534 				      "buffer in load_nzf(): %s",
13535 				      isc_result_totext(result));
13536 			result = dzarg.result;
13537 			goto cleanup;
13538 		}
13539 
13540 		data.mv_data = isc_buffer_base(text);
13541 		data.mv_size = isc_buffer_usedlength(text);
13542 
13543 		status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
13544 		if (status != MDB_SUCCESS) {
13545 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13546 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13547 				      "Error inserting zone in "
13548 				      "NZD database: %s",
13549 				      mdb_strerror(status));
13550 			result = ISC_R_FAILURE;
13551 			goto cleanup;
13552 		}
13553 
13554 		commit = true;
13555 	}
13556 
13557 	result = ISC_R_SUCCESS;
13558 
13559 	/*
13560 	 * Leaving the NZF file in place is harmless as we won't use it
13561 	 * if an NZD database is found for the view. But we rename NZF file
13562 	 * to a backup name here.
13563 	 */
13564 	strlcpy(tempname, view->new_zone_file, sizeof(tempname));
13565 	if (strlen(tempname) < sizeof(tempname) - 1) {
13566 		strlcat(tempname, "~", sizeof(tempname));
13567 		isc_file_rename(view->new_zone_file, tempname);
13568 	}
13569 
13570 cleanup:
13571 	if (result != ISC_R_SUCCESS) {
13572 		(void)nzd_close(&txn, false);
13573 	} else {
13574 		result = nzd_close(&txn, commit);
13575 	}
13576 
13577 	if (text != NULL) {
13578 		isc_buffer_free(&text);
13579 	}
13580 
13581 	if (nzf_config != NULL) {
13582 		cfg_obj_destroy(named_g_addparser, &nzf_config);
13583 	}
13584 
13585 	return result;
13586 }
13587 #endif /* HAVE_LMDB */
13588 
13589 static isc_result_t
13590 newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
13591 	      cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
13592 	      bool *redirectp, isc_buffer_t **text) {
13593 	isc_result_t result;
13594 	isc_buffer_t argbuf;
13595 	bool redirect = false;
13596 	cfg_obj_t *zoneconf = NULL;
13597 	const cfg_obj_t *zlist = NULL;
13598 	const cfg_obj_t *zoneobj = NULL;
13599 	const cfg_obj_t *zoptions = NULL;
13600 	const cfg_obj_t *obj = NULL;
13601 	const char *viewname = NULL;
13602 	dns_rdataclass_t rdclass;
13603 	dns_view_t *view = NULL;
13604 	const char *bn = NULL;
13605 
13606 	REQUIRE(viewp != NULL && *viewp == NULL);
13607 	REQUIRE(zoneobjp != NULL && *zoneobjp == NULL);
13608 	REQUIRE(zoneconfp != NULL && *zoneconfp == NULL);
13609 	REQUIRE(redirectp != NULL);
13610 
13611 	/* Try to parse the argument string */
13612 	isc_buffer_init(&argbuf, command, (unsigned int)strlen(command));
13613 	isc_buffer_add(&argbuf, strlen(command));
13614 
13615 	if (strncasecmp(command, "add", 3) == 0) {
13616 		bn = "addzone";
13617 	} else if (strncasecmp(command, "mod", 3) == 0) {
13618 		bn = "modzone";
13619 	} else {
13620 		UNREACHABLE();
13621 	}
13622 
13623 	/*
13624 	 * Convert the "addzone" or "modzone" to just "zone", for
13625 	 * the benefit of the parser
13626 	 */
13627 	isc_buffer_forward(&argbuf, 3);
13628 
13629 	cfg_parser_reset(named_g_addparser);
13630 	CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0,
13631 			       &cfg_type_addzoneconf, 0, &zoneconf));
13632 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
13633 	if (!cfg_obj_islist(zlist)) {
13634 		CHECK(ISC_R_FAILURE);
13635 	}
13636 
13637 	/* For now we only support adding one zone at a time */
13638 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
13639 
13640 	/* Check the zone type for ones that are not supported by addzone. */
13641 	zoptions = cfg_tuple_get(zoneobj, "options");
13642 
13643 	obj = NULL;
13644 	(void)cfg_map_get(zoptions, "type", &obj);
13645 	if (obj == NULL) {
13646 		(void)cfg_map_get(zoptions, "in-view", &obj);
13647 		if (obj != NULL) {
13648 			(void)putstr(text, "'in-view' zones not supported by ");
13649 			(void)putstr(text, bn);
13650 		} else {
13651 			(void)putstr(text, "zone type not specified");
13652 		}
13653 		CHECK(ISC_R_FAILURE);
13654 	}
13655 
13656 	if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
13657 	    strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
13658 	{
13659 		(void)putstr(text, "'");
13660 		(void)putstr(text, cfg_obj_asstring(obj));
13661 		(void)putstr(text, "' zones not supported by ");
13662 		(void)putstr(text, bn);
13663 		CHECK(ISC_R_FAILURE);
13664 	}
13665 
13666 	if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0) {
13667 		redirect = true;
13668 	}
13669 
13670 	/* Make sense of optional class argument */
13671 	obj = cfg_tuple_get(zoneobj, "class");
13672 	CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass));
13673 
13674 	/* Make sense of optional view argument */
13675 	obj = cfg_tuple_get(zoneobj, "view");
13676 	if (obj && cfg_obj_isstring(obj)) {
13677 		viewname = cfg_obj_asstring(obj);
13678 	}
13679 	if (viewname == NULL || *viewname == '\0') {
13680 		viewname = "_default";
13681 	}
13682 	result = dns_viewlist_find(&server->viewlist, viewname, rdclass, &view);
13683 	if (result == ISC_R_NOTFOUND) {
13684 		(void)putstr(text, "no matching view found for '");
13685 		(void)putstr(text, viewname);
13686 		(void)putstr(text, "'");
13687 		goto cleanup;
13688 	} else if (result != ISC_R_SUCCESS) {
13689 		goto cleanup;
13690 	}
13691 
13692 	*viewp = view;
13693 	*zoneobjp = zoneobj;
13694 	*zoneconfp = zoneconf;
13695 	*redirectp = redirect;
13696 
13697 	return ISC_R_SUCCESS;
13698 
13699 cleanup:
13700 	if (zoneconf != NULL) {
13701 		cfg_obj_destroy(named_g_addparser, &zoneconf);
13702 	}
13703 	if (view != NULL) {
13704 		dns_view_detach(&view);
13705 	}
13706 
13707 	return result;
13708 }
13709 
13710 static isc_result_t
13711 delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config,
13712 		const dns_name_t *zname, nzfwriter_t nzfwriter) {
13713 	isc_result_t result = ISC_R_NOTFOUND;
13714 	const cfg_listelt_t *elt = NULL;
13715 	const cfg_obj_t *zl = NULL;
13716 	cfg_list_t *list;
13717 	dns_fixedname_t myfixed;
13718 	dns_name_t *myname;
13719 
13720 	REQUIRE(view != NULL);
13721 	REQUIRE(pctx != NULL);
13722 	REQUIRE(config != NULL);
13723 	REQUIRE(zname != NULL);
13724 
13725 	LOCK(&view->new_zone_lock);
13726 
13727 	cfg_map_get(config, "zone", &zl);
13728 
13729 	if (!cfg_obj_islist(zl)) {
13730 		CHECK(ISC_R_FAILURE);
13731 	}
13732 
13733 	list = UNCONST(&zl->value.list);
13734 
13735 	myname = dns_fixedname_initname(&myfixed);
13736 
13737 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13738 	     elt = ISC_LIST_NEXT(elt, link))
13739 	{
13740 		const cfg_obj_t *zconf = cfg_listelt_value(elt);
13741 		const char *zn;
13742 		cfg_listelt_t *e;
13743 
13744 		zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
13745 		result = dns_name_fromstring(myname, zn, dns_rootname, 0, NULL);
13746 		if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname)) {
13747 			continue;
13748 		}
13749 
13750 		e = UNCONST(elt);
13751 		ISC_LIST_UNLINK(*list, e, link);
13752 		cfg_obj_destroy(pctx, &e->obj);
13753 		isc_mem_put(pctx->mctx, e, sizeof(*e));
13754 		result = ISC_R_SUCCESS;
13755 		break;
13756 	}
13757 
13758 	/*
13759 	 * Write config to NZF file if appropriate
13760 	 */
13761 	if (nzfwriter != NULL && view->new_zone_file != NULL) {
13762 		result = nzfwriter(config, view);
13763 	}
13764 
13765 cleanup:
13766 	UNLOCK(&view->new_zone_lock);
13767 	return result;
13768 }
13769 
13770 static isc_result_t
13771 do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13772 	   dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
13773 	   bool redirect, isc_buffer_t **text) {
13774 	isc_result_t result, tresult;
13775 	dns_zone_t *zone = NULL;
13776 #ifndef HAVE_LMDB
13777 	FILE *fp = NULL;
13778 	bool cleanup_config = false;
13779 #else /* HAVE_LMDB */
13780 	MDB_txn *txn = NULL;
13781 	MDB_dbi dbi;
13782 	bool locked = false;
13783 
13784 	UNUSED(zoneconf);
13785 #endif
13786 
13787 	/* Zone shouldn't already exist */
13788 	if (redirect) {
13789 		result = (view->redirect == NULL) ? ISC_R_NOTFOUND
13790 						  : ISC_R_EXISTS;
13791 	} else {
13792 		result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
13793 		if (result == ISC_R_SUCCESS) {
13794 			result = ISC_R_EXISTS;
13795 		}
13796 	}
13797 	if (result != ISC_R_NOTFOUND) {
13798 		goto cleanup;
13799 	}
13800 
13801 	isc_loopmgr_pause(named_g_loopmgr);
13802 
13803 #ifndef HAVE_LMDB
13804 	/*
13805 	 * Make sure we can open the configuration save file
13806 	 */
13807 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
13808 	if (result != ISC_R_SUCCESS) {
13809 		isc_loopmgr_resume(named_g_loopmgr);
13810 		TCHECK(putstr(text, "unable to create '"));
13811 		TCHECK(putstr(text, view->new_zone_file));
13812 		TCHECK(putstr(text, "': "));
13813 		TCHECK(putstr(text, isc_result_totext(result)));
13814 		goto cleanup;
13815 	}
13816 
13817 	(void)isc_stdio_close(fp);
13818 	fp = NULL;
13819 #else  /* HAVE_LMDB */
13820 	LOCK(&view->new_zone_lock);
13821 	locked = true;
13822 	/* Make sure we can open the NZD database */
13823 	result = nzd_writable(view);
13824 	if (result != ISC_R_SUCCESS) {
13825 		isc_loopmgr_resume(named_g_loopmgr);
13826 		TCHECK(putstr(text, "unable to open NZD database for '"));
13827 		TCHECK(putstr(text, view->new_zone_db));
13828 		TCHECK(putstr(text, "'"));
13829 		result = ISC_R_FAILURE;
13830 		goto cleanup;
13831 	}
13832 #endif /* HAVE_LMDB */
13833 
13834 	/* Mark view unfrozen and configure zone */
13835 	dns_view_thaw(view);
13836 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
13837 				&server->viewlist, &server->kasplist,
13838 				&server->keystorelist, cfg->actx, true, false,
13839 				false, false);
13840 	dns_view_freeze(view);
13841 
13842 	isc_loopmgr_resume(named_g_loopmgr);
13843 
13844 	if (result != ISC_R_SUCCESS) {
13845 		TCHECK(putstr(text, "configure_zone failed: "));
13846 		TCHECK(putstr(text, isc_result_totext(result)));
13847 		goto cleanup;
13848 	}
13849 
13850 	/* Is it there yet? */
13851 	if (redirect) {
13852 		if (view->redirect == NULL) {
13853 			CHECK(ISC_R_NOTFOUND);
13854 		}
13855 		dns_zone_attach(view->redirect, &zone);
13856 	} else {
13857 		result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
13858 		if (result != ISC_R_SUCCESS) {
13859 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13860 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13861 				      "added new zone was not found: %s",
13862 				      isc_result_totext(result));
13863 			goto cleanup;
13864 		}
13865 	}
13866 
13867 #ifndef HAVE_LMDB
13868 	/*
13869 	 * If there wasn't a previous newzone config, just save the one
13870 	 * we've created. If there was a previous one, merge the new
13871 	 * zone into it.
13872 	 */
13873 	if (cfg->nzf_config == NULL) {
13874 		cfg_obj_attach(zoneconf, &cfg->nzf_config);
13875 	} else {
13876 		cfg_obj_t *z = UNCONST(zoneobj);
13877 		CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z,
13878 					"zone"));
13879 	}
13880 	cleanup_config = true;
13881 #endif /* HAVE_LMDB */
13882 
13883 	/*
13884 	 * Load the zone from the master file.  If this fails, we'll
13885 	 * need to undo the configuration we've done already.
13886 	 */
13887 	result = dns_zone_load(zone, true);
13888 	if (result != ISC_R_SUCCESS) {
13889 		dns_db_t *dbp = NULL;
13890 
13891 		TCHECK(putstr(text, "dns_zone_loadnew failed: "));
13892 		TCHECK(putstr(text, isc_result_totext(result)));
13893 
13894 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13895 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13896 			      "addzone failed; reverting.");
13897 
13898 		/* If the zone loaded partially, unload it */
13899 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13900 			dns_db_detach(&dbp);
13901 			dns_zone_unload(zone);
13902 		}
13903 
13904 		/* Remove the zone from the zone table */
13905 		dns_view_delzone(view, zone);
13906 		goto cleanup;
13907 	}
13908 
13909 	/* Flag the zone as having been added at runtime */
13910 	dns_zone_setadded(zone, true);
13911 
13912 #ifdef HAVE_LMDB
13913 	/* Save the new zone configuration into the NZD */
13914 	CHECK(nzd_open(view, 0, &txn, &dbi));
13915 	CHECK(nzd_save(&txn, dbi, zone, zoneobj));
13916 #else  /* ifdef HAVE_LMDB */
13917 	/* Append the zone configuration to the NZF */
13918 	result = nzf_append(view, zoneobj);
13919 #endif /* HAVE_LMDB */
13920 
13921 cleanup:
13922 
13923 #ifndef HAVE_LMDB
13924 	if (fp != NULL) {
13925 		(void)isc_stdio_close(fp);
13926 	}
13927 	if (result != ISC_R_SUCCESS && cleanup_config) {
13928 		tresult = delete_zoneconf(view, cfg->add_parser,
13929 					  cfg->nzf_config, name, NULL);
13930 		RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
13931 	}
13932 #else  /* HAVE_LMDB */
13933 	if (txn != NULL) {
13934 		(void)nzd_close(&txn, false);
13935 	}
13936 	if (locked) {
13937 		UNLOCK(&view->new_zone_lock);
13938 	}
13939 #endif /* HAVE_LMDB */
13940 
13941 	if (zone != NULL) {
13942 		dns_zone_detach(&zone);
13943 	}
13944 
13945 	return result;
13946 }
13947 
13948 static isc_result_t
13949 do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13950 	   dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
13951 	   bool redirect, isc_buffer_t **text) {
13952 	isc_result_t result, tresult;
13953 	dns_zone_t *zone = NULL;
13954 	bool added;
13955 #ifndef HAVE_LMDB
13956 	FILE *fp = NULL;
13957 	cfg_obj_t *z;
13958 #else  /* HAVE_LMDB */
13959 	MDB_txn *txn = NULL;
13960 	MDB_dbi dbi;
13961 	bool locked = false;
13962 #endif /* HAVE_LMDB */
13963 
13964 	/* Zone must already exist */
13965 	if (redirect) {
13966 		if (view->redirect != NULL) {
13967 			dns_zone_attach(view->redirect, &zone);
13968 			result = ISC_R_SUCCESS;
13969 		} else {
13970 			result = ISC_R_NOTFOUND;
13971 		}
13972 	} else {
13973 		result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
13974 	}
13975 	if (result != ISC_R_SUCCESS) {
13976 		goto cleanup;
13977 	}
13978 
13979 	added = dns_zone_getadded(zone);
13980 	dns_zone_detach(&zone);
13981 
13982 #ifndef HAVE_LMDB
13983 	cfg = (ns_cfgctx_t *)view->new_zone_config;
13984 	if (cfg == NULL) {
13985 		TCHECK(putstr(text, "new zone config is not set"));
13986 		CHECK(ISC_R_FAILURE);
13987 	}
13988 #endif /* ifndef HAVE_LMDB */
13989 
13990 	isc_loopmgr_pause(named_g_loopmgr);
13991 
13992 #ifndef HAVE_LMDB
13993 	/* Make sure we can open the configuration save file */
13994 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
13995 	if (result != ISC_R_SUCCESS) {
13996 		TCHECK(putstr(text, "unable to open '"));
13997 		TCHECK(putstr(text, view->new_zone_file));
13998 		TCHECK(putstr(text, "': "));
13999 		TCHECK(putstr(text, isc_result_totext(result)));
14000 		isc_loopmgr_resume(named_g_loopmgr);
14001 		goto cleanup;
14002 	}
14003 	(void)isc_stdio_close(fp);
14004 	fp = NULL;
14005 #else  /* HAVE_LMDB */
14006 	LOCK(&view->new_zone_lock);
14007 	locked = true;
14008 	/* Make sure we can open the NZD database */
14009 	result = nzd_writable(view);
14010 	if (result != ISC_R_SUCCESS) {
14011 		TCHECK(putstr(text, "unable to open NZD database for '"));
14012 		TCHECK(putstr(text, view->new_zone_db));
14013 		TCHECK(putstr(text, "'"));
14014 		result = ISC_R_FAILURE;
14015 		isc_loopmgr_resume(named_g_loopmgr);
14016 		goto cleanup;
14017 	}
14018 #endif /* HAVE_LMDB */
14019 
14020 	/* Reconfigure the zone */
14021 	dns_view_thaw(view);
14022 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
14023 				&server->viewlist, &server->kasplist,
14024 				&server->keystorelist, cfg->actx, true, false,
14025 				false, true);
14026 	dns_view_freeze(view);
14027 
14028 	isc_loopmgr_resume(named_g_loopmgr);
14029 
14030 	if (result != ISC_R_SUCCESS) {
14031 		TCHECK(putstr(text, "configure_zone failed: "));
14032 		TCHECK(putstr(text, isc_result_totext(result)));
14033 		goto cleanup;
14034 	}
14035 
14036 	/* Is it there yet? */
14037 	if (redirect) {
14038 		if (view->redirect == NULL) {
14039 			CHECK(ISC_R_NOTFOUND);
14040 		}
14041 		dns_zone_attach(view->redirect, &zone);
14042 	} else {
14043 		CHECK(dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone));
14044 	}
14045 
14046 #ifndef HAVE_LMDB
14047 	/* Remove old zone from configuration (and NZF file if applicable) */
14048 	if (added) {
14049 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
14050 					 dns_zone_getorigin(zone),
14051 					 nzf_writeconf);
14052 		if (result != ISC_R_SUCCESS) {
14053 			TCHECK(putstr(text, "former zone configuration "
14054 					    "not deleted: "));
14055 			TCHECK(putstr(text, isc_result_totext(result)));
14056 			goto cleanup;
14057 		}
14058 	}
14059 #endif /* HAVE_LMDB */
14060 
14061 	if (!added) {
14062 		if (cfg->vconfig == NULL) {
14063 			result = delete_zoneconf(
14064 				view, cfg->conf_parser, cfg->config,
14065 				dns_zone_getorigin(zone), NULL);
14066 		} else {
14067 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14068 								  "options");
14069 			result = delete_zoneconf(
14070 				view, cfg->conf_parser, voptions,
14071 				dns_zone_getorigin(zone), NULL);
14072 		}
14073 
14074 		if (result != ISC_R_SUCCESS) {
14075 			TCHECK(putstr(text, "former zone configuration "
14076 					    "not deleted: "));
14077 			TCHECK(putstr(text, isc_result_totext(result)));
14078 			goto cleanup;
14079 		}
14080 	}
14081 
14082 	/* Load the zone from the master file if it needs reloading. */
14083 	result = dns_zone_load(zone, true);
14084 
14085 	/*
14086 	 * Dynamic zones need no reloading, so we can pass this result.
14087 	 */
14088 	if (result == DNS_R_DYNAMIC) {
14089 		result = ISC_R_SUCCESS;
14090 	}
14091 
14092 	if (result != ISC_R_SUCCESS) {
14093 		dns_db_t *dbp = NULL;
14094 
14095 		TCHECK(putstr(text, "failed to load zone '"));
14096 		TCHECK(putstr(text, zname));
14097 		TCHECK(putstr(text, "': "));
14098 		TCHECK(putstr(text, isc_result_totext(result)));
14099 		TCHECK(putstr(text, "\nThe zone is no longer being served. "));
14100 		TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
14101 		TCHECK(putstr(text, "the problem and restore service."));
14102 
14103 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14104 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14105 			      "modzone failed; removing zone.");
14106 
14107 		/* If the zone loaded partially, unload it */
14108 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14109 			dns_db_detach(&dbp);
14110 			dns_zone_unload(zone);
14111 		}
14112 
14113 		/* Remove the zone from the zone table */
14114 		dns_view_delzone(view, zone);
14115 		goto cleanup;
14116 	}
14117 
14118 #ifndef HAVE_LMDB
14119 	/* Store the new zone configuration; also in NZF if applicable */
14120 	z = UNCONST(zoneobj);
14121 	CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone"));
14122 #endif /* HAVE_LMDB */
14123 
14124 	if (added) {
14125 #ifdef HAVE_LMDB
14126 		CHECK(nzd_open(view, 0, &txn, &dbi));
14127 		CHECK(nzd_save(&txn, dbi, zone, zoneobj));
14128 #else  /* ifdef HAVE_LMDB */
14129 		result = nzf_append(view, zoneobj);
14130 		if (result != ISC_R_SUCCESS) {
14131 			TCHECK(putstr(text, "\nNew zone config not saved: "));
14132 			TCHECK(putstr(text, isc_result_totext(result)));
14133 			goto cleanup;
14134 		}
14135 #endif /* HAVE_LMDB */
14136 
14137 		TCHECK(putstr(text, "zone '"));
14138 		TCHECK(putstr(text, zname));
14139 		TCHECK(putstr(text, "' reconfigured."));
14140 	} else {
14141 		TCHECK(putstr(text, "zone '"));
14142 		TCHECK(putstr(text, zname));
14143 		TCHECK(putstr(text, "' must also be reconfigured in\n"));
14144 		TCHECK(putstr(text, "named.conf to make changes permanent."));
14145 	}
14146 
14147 cleanup:
14148 
14149 #ifndef HAVE_LMDB
14150 	if (fp != NULL) {
14151 		(void)isc_stdio_close(fp);
14152 	}
14153 #else  /* HAVE_LMDB */
14154 	if (txn != NULL) {
14155 		(void)nzd_close(&txn, false);
14156 	}
14157 	if (locked) {
14158 		UNLOCK(&view->new_zone_lock);
14159 	}
14160 #endif /* HAVE_LMDB */
14161 
14162 	if (zone != NULL) {
14163 		dns_zone_detach(&zone);
14164 	}
14165 
14166 	return result;
14167 }
14168 
14169 /*
14170  * Act on an "addzone" or "modzone" command from the command channel.
14171  */
14172 isc_result_t
14173 named_server_changezone(named_server_t *server, char *command,
14174 			isc_buffer_t **text) {
14175 	isc_result_t result;
14176 	bool addzone;
14177 	bool redirect = false;
14178 	ns_cfgctx_t *cfg = NULL;
14179 	cfg_obj_t *zoneconf = NULL;
14180 	const cfg_obj_t *zoneobj = NULL;
14181 	const char *zonename;
14182 	dns_view_t *view = NULL;
14183 	isc_buffer_t buf;
14184 	dns_fixedname_t fname;
14185 	dns_name_t *dnsname;
14186 
14187 	REQUIRE(text != NULL);
14188 
14189 	if (strncasecmp(command, "add", 3) == 0) {
14190 		addzone = true;
14191 	} else {
14192 		INSIST(strncasecmp(command, "mod", 3) == 0);
14193 		addzone = false;
14194 	}
14195 
14196 	CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj,
14197 			    &redirect, text));
14198 
14199 	/* Are we accepting new zones in this view? */
14200 #ifdef HAVE_LMDB
14201 	if (view->new_zone_db == NULL)
14202 #else  /* ifdef HAVE_LMDB */
14203 	if (view->new_zone_file == NULL)
14204 #endif /* HAVE_LMDB */
14205 	{
14206 		(void)putstr(text, "Not allowing new zones in view '");
14207 		(void)putstr(text, view->name);
14208 		(void)putstr(text, "'");
14209 		result = ISC_R_NOPERM;
14210 		goto cleanup;
14211 	}
14212 
14213 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14214 	if (cfg == NULL) {
14215 		result = ISC_R_FAILURE;
14216 		goto cleanup;
14217 	}
14218 
14219 	zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
14220 	isc_buffer_constinit(&buf, zonename, strlen(zonename));
14221 	isc_buffer_add(&buf, strlen(zonename));
14222 
14223 	dnsname = dns_fixedname_initname(&fname);
14224 	CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL));
14225 
14226 	if (redirect) {
14227 		if (!dns_name_equal(dnsname, dns_rootname)) {
14228 			(void)putstr(text, "redirect zones must be called "
14229 					   "\".\"");
14230 			CHECK(ISC_R_FAILURE);
14231 		}
14232 	}
14233 
14234 	if (addzone) {
14235 		CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj,
14236 				 redirect, text));
14237 	} else {
14238 		CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj,
14239 				 redirect, text));
14240 	}
14241 
14242 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14243 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14244 		      "%s zone %s in view %s via %s",
14245 		      addzone ? "added" : "updated", zonename, view->name,
14246 		      addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
14247 
14248 	/* Changing a zone counts as reconfiguration */
14249 	named_g_configtime = isc_time_now();
14250 
14251 cleanup:
14252 	if (isc_buffer_usedlength(*text) > 0) {
14253 		(void)putnull(text);
14254 	}
14255 	if (zoneconf != NULL) {
14256 		cfg_obj_destroy(named_g_addparser, &zoneconf);
14257 	}
14258 	if (view != NULL) {
14259 		dns_view_detach(&view);
14260 	}
14261 
14262 	return result;
14263 }
14264 
14265 static bool
14266 inuse(const char *file, bool first, isc_buffer_t **text) {
14267 	if (file != NULL && isc_file_exists(file)) {
14268 		if (first) {
14269 			(void)putstr(text, "The following files were in use "
14270 					   "and may now be removed:\n");
14271 		} else {
14272 			(void)putstr(text, "\n");
14273 		}
14274 		(void)putstr(text, file);
14275 		(void)putnull(text);
14276 		return false;
14277 	}
14278 	return first;
14279 }
14280 
14281 typedef struct {
14282 	dns_zone_t *zone;
14283 	bool cleanup;
14284 } ns_dzctx_t;
14285 
14286 /*
14287  * Carry out a zone deletion scheduled by named_server_delzone().
14288  */
14289 static void
14290 rmzone(void *arg) {
14291 	ns_dzctx_t *dz = (ns_dzctx_t *)arg;
14292 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
14293 	dns_catz_zone_t *catz = NULL;
14294 	char zonename[DNS_NAME_FORMATSIZE];
14295 	dns_view_t *view = NULL;
14296 	ns_cfgctx_t *cfg = NULL;
14297 	dns_db_t *dbp = NULL;
14298 	bool added;
14299 	isc_result_t result;
14300 #ifdef HAVE_LMDB
14301 	MDB_txn *txn = NULL;
14302 	MDB_dbi dbi;
14303 #endif /* ifdef HAVE_LMDB */
14304 
14305 	REQUIRE(dz != NULL);
14306 
14307 	/* Dig out configuration for this zone */
14308 	zone = dz->zone;
14309 	view = dns_zone_getview(zone);
14310 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14311 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
14312 
14313 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14314 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14315 		      "deleting zone %s in view %s via delzone", zonename,
14316 		      view->name);
14317 
14318 	/*
14319 	 * Remove the zone from configuration (and NZF file if applicable)
14320 	 * (If this is a catalog zone member then nzf_config can be NULL)
14321 	 */
14322 	added = dns_zone_getadded(zone);
14323 	catz = dns_zone_get_parentcatz(zone);
14324 
14325 	if (added && catz == NULL && cfg != NULL) {
14326 #ifdef HAVE_LMDB
14327 		/* Make sure we can open the NZD database */
14328 		LOCK(&view->new_zone_lock);
14329 		result = nzd_open(view, 0, &txn, &dbi);
14330 		if (result != ISC_R_SUCCESS) {
14331 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14332 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14333 				      "unable to open NZD database for '%s'",
14334 				      view->new_zone_db);
14335 		} else {
14336 			result = nzd_save(&txn, dbi, zone, NULL);
14337 		}
14338 
14339 		if (result != ISC_R_SUCCESS) {
14340 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14341 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14342 				      "unable to delete zone configuration: %s",
14343 				      isc_result_totext(result));
14344 		}
14345 
14346 		if (txn != NULL) {
14347 			(void)nzd_close(&txn, false);
14348 		}
14349 		UNLOCK(&view->new_zone_lock);
14350 #else  /* ifdef HAVE_LMDB */
14351 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
14352 					 dns_zone_getorigin(zone),
14353 					 nzf_writeconf);
14354 		if (result != ISC_R_SUCCESS) {
14355 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14356 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14357 				      "unable to delete zone configuration: %s",
14358 				      isc_result_totext(result));
14359 		}
14360 #endif /* HAVE_LMDB */
14361 	}
14362 
14363 	if (!added && cfg != NULL) {
14364 		if (cfg->vconfig != NULL) {
14365 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14366 								  "options");
14367 			result = delete_zoneconf(
14368 				view, cfg->conf_parser, voptions,
14369 				dns_zone_getorigin(zone), NULL);
14370 		} else {
14371 			result = delete_zoneconf(
14372 				view, cfg->conf_parser, cfg->config,
14373 				dns_zone_getorigin(zone), NULL);
14374 		}
14375 		if (result != ISC_R_SUCCESS) {
14376 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14377 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14378 				      "unable to delete zone configuration: %s",
14379 				      isc_result_totext(result));
14380 		}
14381 	}
14382 
14383 	/* Unload zone database */
14384 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14385 		dns_db_detach(&dbp);
14386 		dns_zone_unload(zone);
14387 	}
14388 
14389 	/* Clean up stub/secondary zone files if requested to do so */
14390 	dns_zone_getraw(zone, &raw);
14391 	mayberaw = (raw != NULL) ? raw : zone;
14392 
14393 	if (added && dz->cleanup) {
14394 		const char *file;
14395 
14396 		file = dns_zone_getfile(mayberaw);
14397 		result = isc_file_remove(file);
14398 		if (result != ISC_R_SUCCESS) {
14399 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14400 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14401 				      "file %s not removed: %s", file,
14402 				      isc_result_totext(result));
14403 		}
14404 
14405 		file = dns_zone_getjournal(mayberaw);
14406 		result = isc_file_remove(file);
14407 		if (result != ISC_R_SUCCESS) {
14408 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14409 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14410 				      "file %s not removed: %s", file,
14411 				      isc_result_totext(result));
14412 		}
14413 
14414 		if (zone != mayberaw) {
14415 			file = dns_zone_getfile(zone);
14416 			result = isc_file_remove(file);
14417 			if (result != ISC_R_SUCCESS) {
14418 				isc_log_write(
14419 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14420 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14421 					"file %s not removed: %s", file,
14422 					isc_result_totext(result));
14423 			}
14424 
14425 			file = dns_zone_getjournal(zone);
14426 			result = isc_file_remove(file);
14427 			if (result != ISC_R_SUCCESS) {
14428 				isc_log_write(
14429 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14430 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14431 					"file %s not removed: %s", file,
14432 					isc_result_totext(result));
14433 			}
14434 		}
14435 	}
14436 
14437 	if (raw != NULL) {
14438 		dns_zone_detach(&raw);
14439 	}
14440 	dns_zone_detach(&zone);
14441 	isc_mem_put(named_g_mctx, dz, sizeof(*dz));
14442 }
14443 
14444 /*
14445  * Act on a "delzone" command from the command channel.
14446  */
14447 isc_result_t
14448 named_server_delzone(named_server_t *server, isc_lex_t *lex,
14449 		     isc_buffer_t **text) {
14450 	isc_result_t result, tresult;
14451 	dns_zone_t *zone = NULL;
14452 	dns_zone_t *raw = NULL;
14453 	dns_zone_t *mayberaw;
14454 	dns_view_t *view = NULL;
14455 	char zonename[DNS_NAME_FORMATSIZE];
14456 	bool cleanup = false;
14457 	const char *ptr;
14458 	bool added;
14459 	ns_dzctx_t *dz = NULL;
14460 
14461 	REQUIRE(text != NULL);
14462 
14463 	/* Skip the command name. */
14464 	ptr = next_token(lex, text);
14465 	if (ptr == NULL) {
14466 		return ISC_R_UNEXPECTEDEND;
14467 	}
14468 
14469 	/* Find out what we are to do. */
14470 	ptr = next_token(lex, text);
14471 	if (ptr == NULL) {
14472 		return ISC_R_UNEXPECTEDEND;
14473 	}
14474 
14475 	if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) {
14476 		cleanup = true;
14477 		ptr = next_token(lex, text);
14478 	}
14479 
14480 	CHECK(zone_from_args(server, lex, ptr, &zone, zonename, text, false));
14481 	if (zone == NULL) {
14482 		result = ISC_R_UNEXPECTEDEND;
14483 		goto cleanup;
14484 	}
14485 
14486 	INSIST(zonename != NULL);
14487 
14488 	/* Is this a policy zone? */
14489 	if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
14490 		TCHECK(putstr(text, "zone '"));
14491 		TCHECK(putstr(text, zonename));
14492 		TCHECK(putstr(text,
14493 			      "' cannot be deleted: response-policy zone."));
14494 		result = ISC_R_FAILURE;
14495 		goto cleanup;
14496 	}
14497 
14498 	view = dns_zone_getview(zone);
14499 	if (dns_zone_gettype(zone) == dns_zone_redirect) {
14500 		dns_zone_detach(&view->redirect);
14501 	} else {
14502 		CHECK(dns_view_delzone(view, zone));
14503 	}
14504 
14505 	/* Send cleanup event */
14506 	dz = isc_mem_get(named_g_mctx, sizeof(*dz));
14507 	*dz = (ns_dzctx_t){
14508 		.cleanup = cleanup,
14509 	};
14510 	dns_zone_attach(zone, &dz->zone);
14511 	isc_async_run(dns_zone_getloop(zone), rmzone, dz);
14512 
14513 	/* Inform user about cleaning up stub/secondary zone files */
14514 	dns_zone_getraw(zone, &raw);
14515 	mayberaw = (raw != NULL) ? raw : zone;
14516 
14517 	added = dns_zone_getadded(zone);
14518 	if (!added) {
14519 		TCHECK(putstr(text, "zone '"));
14520 		TCHECK(putstr(text, zonename));
14521 		TCHECK(putstr(text, "' is no longer active and will be "
14522 				    "deleted.\n"));
14523 		TCHECK(putstr(text, "To keep it from returning "));
14524 		TCHECK(putstr(text, "when the server is restarted, it\n"));
14525 		TCHECK(putstr(text, "must also be removed from named.conf."));
14526 	} else if (cleanup) {
14527 		TCHECK(putstr(text, "zone '"));
14528 		TCHECK(putstr(text, zonename));
14529 		TCHECK(putstr(text, "' and associated files will be deleted."));
14530 	} else if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
14531 		   dns_zone_gettype(mayberaw) == dns_zone_mirror ||
14532 		   dns_zone_gettype(mayberaw) == dns_zone_stub)
14533 	{
14534 		bool first;
14535 		const char *file;
14536 
14537 		TCHECK(putstr(text, "zone '"));
14538 		TCHECK(putstr(text, zonename));
14539 		TCHECK(putstr(text, "' will be deleted."));
14540 
14541 		file = dns_zone_getfile(mayberaw);
14542 		first = inuse(file, true, text);
14543 
14544 		file = dns_zone_getjournal(mayberaw);
14545 		first = inuse(file, first, text);
14546 
14547 		if (zone != mayberaw) {
14548 			file = dns_zone_getfile(zone);
14549 			first = inuse(file, first, text);
14550 
14551 			file = dns_zone_getjournal(zone);
14552 			(void)inuse(file, first, text);
14553 		}
14554 	}
14555 
14556 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14557 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14558 		      "zone %s scheduled for removal via delzone", zonename);
14559 
14560 	/* Removing a zone counts as reconfiguration */
14561 	named_g_configtime = isc_time_now();
14562 
14563 	result = ISC_R_SUCCESS;
14564 
14565 cleanup:
14566 	if (isc_buffer_usedlength(*text) > 0) {
14567 		(void)putnull(text);
14568 	}
14569 	if (raw != NULL) {
14570 		dns_zone_detach(&raw);
14571 	}
14572 	if (zone != NULL) {
14573 		dns_zone_detach(&zone);
14574 	}
14575 
14576 	return result;
14577 }
14578 
14579 static const cfg_obj_t *
14580 find_name_in_list_from_map(const cfg_obj_t *config,
14581 			   const char *map_key_for_list, const char *name,
14582 			   bool redirect) {
14583 	const cfg_obj_t *list = NULL;
14584 	const cfg_listelt_t *element;
14585 	const cfg_obj_t *obj = NULL;
14586 	dns_fixedname_t fixed1, fixed2;
14587 	dns_name_t *name1 = NULL, *name2 = NULL;
14588 	isc_result_t result;
14589 
14590 	if (strcmp(map_key_for_list, "zone") == 0) {
14591 		name1 = dns_fixedname_initname(&fixed1);
14592 		name2 = dns_fixedname_initname(&fixed2);
14593 		result = dns_name_fromstring(name1, name, dns_rootname, 0,
14594 					     NULL);
14595 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
14596 	}
14597 
14598 	cfg_map_get(config, map_key_for_list, &list);
14599 	for (element = cfg_list_first(list); element != NULL;
14600 	     element = cfg_list_next(element))
14601 	{
14602 		const char *vname;
14603 
14604 		obj = cfg_listelt_value(element);
14605 		INSIST(obj != NULL);
14606 		vname = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
14607 		if (vname == NULL) {
14608 			obj = NULL;
14609 			continue;
14610 		}
14611 
14612 		if (name1 != NULL) {
14613 			result = dns_name_fromstring(name2, vname, dns_rootname,
14614 						     0, NULL);
14615 			if (result == ISC_R_SUCCESS &&
14616 			    dns_name_equal(name1, name2))
14617 			{
14618 				const cfg_obj_t *zoptions;
14619 				const cfg_obj_t *typeobj = NULL;
14620 				zoptions = cfg_tuple_get(obj, "options");
14621 
14622 				if (zoptions != NULL) {
14623 					cfg_map_get(zoptions, "type", &typeobj);
14624 				}
14625 				if (redirect && typeobj != NULL &&
14626 				    strcasecmp(cfg_obj_asstring(typeobj),
14627 					       "redirect") == 0)
14628 				{
14629 					break;
14630 				} else if (!redirect) {
14631 					break;
14632 				}
14633 			}
14634 		} else if (strcasecmp(vname, name) == 0) {
14635 			break;
14636 		}
14637 
14638 		obj = NULL;
14639 	}
14640 
14641 	return obj;
14642 }
14643 
14644 static void
14645 emitzone(void *arg, const char *buf, int len) {
14646 	ns_dzarg_t *dzarg = arg;
14647 	isc_result_t result;
14648 
14649 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
14650 	result = putmem(dzarg->text, buf, len);
14651 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
14652 		dzarg->result = result;
14653 	}
14654 }
14655 
14656 /*
14657  * Act on a "showzone" command from the command channel.
14658  */
14659 isc_result_t
14660 named_server_showzone(named_server_t *server, isc_lex_t *lex,
14661 		      isc_buffer_t **text) {
14662 	isc_result_t result;
14663 	const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
14664 	char zonename[DNS_NAME_FORMATSIZE];
14665 	const cfg_obj_t *map;
14666 	dns_view_t *view = NULL;
14667 	dns_zone_t *zone = NULL;
14668 	ns_cfgctx_t *cfg = NULL;
14669 #ifdef HAVE_LMDB
14670 	cfg_obj_t *nzconfig = NULL;
14671 #endif /* HAVE_LMDB */
14672 	bool added, redirect;
14673 	ns_dzarg_t dzarg;
14674 
14675 	REQUIRE(text != NULL);
14676 
14677 	/* Parse parameters */
14678 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
14679 	if (zone == NULL) {
14680 		result = ISC_R_UNEXPECTEDEND;
14681 		goto cleanup;
14682 	}
14683 
14684 	redirect = dns_zone_gettype(zone) == dns_zone_redirect;
14685 	added = dns_zone_getadded(zone);
14686 	view = dns_zone_getview(zone);
14687 	dns_zone_detach(&zone);
14688 
14689 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14690 	if (cfg == NULL) {
14691 		result = ISC_R_FAILURE;
14692 		goto cleanup;
14693 	}
14694 
14695 	if (!added) {
14696 		/* Find the view statement */
14697 		vconfig = find_name_in_list_from_map(cfg->config, "view",
14698 						     view->name, false);
14699 
14700 		/* Find the zone statement */
14701 		if (vconfig != NULL) {
14702 			map = cfg_tuple_get(vconfig, "options");
14703 		} else {
14704 			map = cfg->config;
14705 		}
14706 
14707 		zconfig = find_name_in_list_from_map(map, "zone", zonename,
14708 						     redirect);
14709 	}
14710 
14711 #ifndef HAVE_LMDB
14712 	if (zconfig == NULL && cfg->nzf_config != NULL) {
14713 		zconfig = find_name_in_list_from_map(cfg->nzf_config, "zone",
14714 						     zonename, redirect);
14715 	}
14716 #else  /* HAVE_LMDB */
14717 	if (zconfig == NULL) {
14718 		const cfg_obj_t *zlist = NULL;
14719 		CHECK(get_newzone_config(view, zonename, &nzconfig));
14720 		CHECK(cfg_map_get(nzconfig, "zone", &zlist));
14721 		if (!cfg_obj_islist(zlist)) {
14722 			CHECK(ISC_R_FAILURE);
14723 		}
14724 
14725 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
14726 	}
14727 #endif /* HAVE_LMDB */
14728 
14729 	if (zconfig == NULL) {
14730 		CHECK(ISC_R_NOTFOUND);
14731 	}
14732 
14733 	CHECK(putstr(text, "zone "));
14734 	dzarg.magic = DZARG_MAGIC;
14735 	dzarg.text = text;
14736 	dzarg.result = ISC_R_SUCCESS;
14737 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
14738 	CHECK(dzarg.result);
14739 
14740 	CHECK(putstr(text, ";"));
14741 
14742 	result = ISC_R_SUCCESS;
14743 
14744 cleanup:
14745 #ifdef HAVE_LMDB
14746 	if (nzconfig != NULL) {
14747 		cfg_obj_destroy(named_g_addparser, &nzconfig);
14748 	}
14749 #endif /* HAVE_LMDB */
14750 	if (isc_buffer_usedlength(*text) > 0) {
14751 		(void)putnull(text);
14752 	}
14753 
14754 	return result;
14755 }
14756 
14757 static void
14758 newzone_cfgctx_destroy(void **cfgp) {
14759 	ns_cfgctx_t *cfg;
14760 
14761 	REQUIRE(cfgp != NULL && *cfgp != NULL);
14762 
14763 	cfg = *cfgp;
14764 
14765 	if (cfg->conf_parser != NULL) {
14766 		if (cfg->config != NULL) {
14767 			cfg_obj_destroy(cfg->conf_parser, &cfg->config);
14768 		}
14769 		if (cfg->vconfig != NULL) {
14770 			cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
14771 		}
14772 		cfg_parser_destroy(&cfg->conf_parser);
14773 	}
14774 	if (cfg->add_parser != NULL) {
14775 		if (cfg->nzf_config != NULL) {
14776 			cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
14777 		}
14778 		cfg_parser_destroy(&cfg->add_parser);
14779 	}
14780 
14781 	if (cfg->actx != NULL) {
14782 		cfg_aclconfctx_detach(&cfg->actx);
14783 	}
14784 
14785 	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
14786 	*cfgp = NULL;
14787 }
14788 
14789 isc_result_t
14790 named_server_signing(named_server_t *server, isc_lex_t *lex,
14791 		     isc_buffer_t **text) {
14792 	isc_result_t result = ISC_R_SUCCESS;
14793 	dns_zone_t *zone = NULL;
14794 	dns_name_t *origin;
14795 	dns_db_t *db = NULL;
14796 	dns_dbnode_t *node = NULL;
14797 	dns_dbversion_t *version = NULL;
14798 	dns_rdatatype_t privatetype;
14799 	dns_rdataset_t privset;
14800 	bool first = true;
14801 	bool list = false, clear = false;
14802 	bool chain = false;
14803 	bool setserial = false;
14804 	bool resalt = false;
14805 	uint32_t serial = 0;
14806 	char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
14807 	unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
14808 	unsigned char salt[255];
14809 	const char *ptr;
14810 	size_t n;
14811 	bool kasp = false;
14812 
14813 	REQUIRE(text != NULL);
14814 
14815 	dns_rdataset_init(&privset);
14816 
14817 	/* Skip the command name. */
14818 	ptr = next_token(lex, text);
14819 	if (ptr == NULL) {
14820 		return ISC_R_UNEXPECTEDEND;
14821 	}
14822 
14823 	/* Find out what we are to do. */
14824 	ptr = next_token(lex, text);
14825 	if (ptr == NULL) {
14826 		return ISC_R_UNEXPECTEDEND;
14827 	}
14828 
14829 	if (strcasecmp(ptr, "-list") == 0) {
14830 		list = true;
14831 	} else if ((strcasecmp(ptr, "-clear") == 0) ||
14832 		   (strcasecmp(ptr, "-clean") == 0))
14833 	{
14834 		clear = true;
14835 		ptr = next_token(lex, text);
14836 		if (ptr == NULL) {
14837 			return ISC_R_UNEXPECTEDEND;
14838 		}
14839 		strlcpy(keystr, ptr, sizeof(keystr));
14840 	} else if (strcasecmp(ptr, "-nsec3param") == 0) {
14841 		char hashbuf[64], flagbuf[64], iterbuf[64];
14842 		char nbuf[256];
14843 
14844 		chain = true;
14845 		ptr = next_token(lex, text);
14846 		if (ptr == NULL) {
14847 			return ISC_R_UNEXPECTEDEND;
14848 		}
14849 
14850 		if (strcasecmp(ptr, "none") == 0) {
14851 			hash = 0;
14852 		} else {
14853 			strlcpy(hashbuf, ptr, sizeof(hashbuf));
14854 
14855 			ptr = next_token(lex, text);
14856 			if (ptr == NULL) {
14857 				return ISC_R_UNEXPECTEDEND;
14858 			}
14859 			strlcpy(flagbuf, ptr, sizeof(flagbuf));
14860 
14861 			ptr = next_token(lex, text);
14862 			if (ptr == NULL) {
14863 				return ISC_R_UNEXPECTEDEND;
14864 			}
14865 			strlcpy(iterbuf, ptr, sizeof(iterbuf));
14866 			n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", hashbuf,
14867 				     flagbuf, iterbuf);
14868 			if (n == sizeof(nbuf)) {
14869 				return ISC_R_NOSPACE;
14870 			}
14871 			n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
14872 			if (n != 3U) {
14873 				return ISC_R_BADNUMBER;
14874 			}
14875 
14876 			if (hash > 0xffU || flags > 0xffU ||
14877 			    iter > dns_nsec3_maxiterations())
14878 			{
14879 				return ISC_R_RANGE;
14880 			}
14881 
14882 			ptr = next_token(lex, text);
14883 			if (ptr == NULL) {
14884 				return ISC_R_UNEXPECTEDEND;
14885 			} else if (strcasecmp(ptr, "auto") == 0) {
14886 				/* Auto-generate a random salt.
14887 				 * XXXMUKS: This currently uses the
14888 				 * minimum recommended length by RFC
14889 				 * 5155 (64 bits). It should be made
14890 				 * configurable.
14891 				 */
14892 				saltlen = 8;
14893 				resalt = true;
14894 			} else if (strcmp(ptr, "-") != 0) {
14895 				isc_buffer_t buf;
14896 
14897 				isc_buffer_init(&buf, salt, sizeof(salt));
14898 				CHECK(isc_hex_decodestring(ptr, &buf));
14899 				saltlen = isc_buffer_usedlength(&buf);
14900 			}
14901 		}
14902 	} else if (strcasecmp(ptr, "-serial") == 0) {
14903 		ptr = next_token(lex, text);
14904 		if (ptr == NULL) {
14905 			return ISC_R_UNEXPECTEDEND;
14906 		}
14907 		CHECK(isc_parse_uint32(&serial, ptr, 10));
14908 		setserial = true;
14909 	} else {
14910 		CHECK(DNS_R_SYNTAX);
14911 	}
14912 
14913 	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
14914 	if (zone == NULL) {
14915 		CHECK(ISC_R_UNEXPECTEDEND);
14916 	}
14917 
14918 	if (dns_zone_getkasp(zone) != NULL) {
14919 		kasp = true;
14920 	}
14921 
14922 	if (clear) {
14923 		CHECK(dns_zone_keydone(zone, keystr));
14924 		(void)putstr(text, "request queued");
14925 		(void)putnull(text);
14926 	} else if (chain && !kasp) {
14927 		CHECK(dns_zone_setnsec3param(
14928 			zone, (uint8_t)hash, (uint8_t)flags, iter,
14929 			(uint8_t)saltlen, salt, true, resalt));
14930 		(void)putstr(text, "nsec3param request queued");
14931 		(void)putnull(text);
14932 	} else if (setserial) {
14933 		CHECK(dns_zone_setserial(zone, serial));
14934 		(void)putstr(text, "serial request queued");
14935 		(void)putnull(text);
14936 	} else if (list) {
14937 		privatetype = dns_zone_getprivatetype(zone);
14938 		origin = dns_zone_getorigin(zone);
14939 		CHECK(dns_zone_getdb(zone, &db));
14940 		CHECK(dns_db_findnode(db, origin, false, &node));
14941 		dns_db_currentversion(db, &version);
14942 
14943 		result = dns_db_findrdataset(db, node, version, privatetype,
14944 					     dns_rdatatype_none, 0, &privset,
14945 					     NULL);
14946 		if (result == ISC_R_NOTFOUND) {
14947 			(void)putstr(text, "No signing records found");
14948 			(void)putnull(text);
14949 			result = ISC_R_SUCCESS;
14950 			goto cleanup;
14951 		}
14952 
14953 		for (result = dns_rdataset_first(&privset);
14954 		     result == ISC_R_SUCCESS;
14955 		     result = dns_rdataset_next(&privset))
14956 		{
14957 			dns_rdata_t priv = DNS_RDATA_INIT;
14958 			/*
14959 			 * In theory, the output buffer could hold a full RDATA
14960 			 * record which is 16-bit and then some text around
14961 			 * it
14962 			 */
14963 			char output[UINT16_MAX + BUFSIZ];
14964 			isc_buffer_t buf;
14965 
14966 			dns_rdataset_current(&privset, &priv);
14967 
14968 			isc_buffer_init(&buf, output, sizeof(output));
14969 			CHECK(dns_private_totext(&priv, &buf));
14970 			if (!first) {
14971 				CHECK(putstr(text, "\n"));
14972 			}
14973 			CHECK(putstr(text, output));
14974 			first = false;
14975 		}
14976 		if (!first) {
14977 			CHECK(putnull(text));
14978 		}
14979 
14980 		if (result == ISC_R_NOMORE) {
14981 			result = ISC_R_SUCCESS;
14982 		}
14983 	} else if (kasp) {
14984 		(void)putstr(text, "zone uses dnssec-policy, use rndc dnssec "
14985 				   "command instead");
14986 		(void)putnull(text);
14987 	}
14988 
14989 cleanup:
14990 	if (dns_rdataset_isassociated(&privset)) {
14991 		dns_rdataset_disassociate(&privset);
14992 	}
14993 	if (node != NULL) {
14994 		dns_db_detachnode(db, &node);
14995 	}
14996 	if (version != NULL) {
14997 		dns_db_closeversion(db, &version, false);
14998 	}
14999 	if (db != NULL) {
15000 		dns_db_detach(&db);
15001 	}
15002 	if (zone != NULL) {
15003 		dns_zone_detach(&zone);
15004 	}
15005 
15006 	return result;
15007 }
15008 
15009 static bool
15010 argcheck(char *cmd, const char *full) {
15011 	size_t l;
15012 
15013 	if (cmd == NULL || cmd[0] != '-') {
15014 		return false;
15015 	}
15016 
15017 	cmd++;
15018 	l = strlen(cmd);
15019 	if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
15020 		return false;
15021 	}
15022 
15023 	return true;
15024 }
15025 
15026 isc_result_t
15027 named_server_dnssec(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_kasp_t *kasp = NULL;
15032 	dns_dnsseckeylist_t keys;
15033 	dns_dnsseckey_t *key;
15034 	char *ptr, *zonetext = NULL;
15035 	const char *msg = NULL;
15036 	/* variables for -checkds */
15037 	bool checkds = false, dspublish = false;
15038 	/* variables for -rollover */
15039 	bool rollover = false;
15040 	/* variables for -key */
15041 	bool use_keyid = false;
15042 	dns_keytag_t keyid = 0;
15043 	uint8_t algorithm = 0;
15044 	/* variables for -status */
15045 	bool status = false;
15046 	char output[4096];
15047 	isc_stdtime_t now, when;
15048 	isc_time_t timenow, timewhen;
15049 	dns_db_t *db = NULL;
15050 	dns_dbversion_t *version = NULL;
15051 
15052 	REQUIRE(text != NULL);
15053 
15054 	/* Skip the command name. */
15055 	ptr = next_token(lex, text);
15056 	if (ptr == NULL) {
15057 		return ISC_R_UNEXPECTEDEND;
15058 	}
15059 
15060 	/* Find out what we are to do. */
15061 	ptr = next_token(lex, text);
15062 	if (ptr == NULL) {
15063 		return ISC_R_UNEXPECTEDEND;
15064 	}
15065 
15066 	/* Initialize current time and key list. */
15067 	timenow = isc_time_now();
15068 	now = isc_time_seconds(&timenow);
15069 	when = now;
15070 
15071 	ISC_LIST_INIT(keys);
15072 
15073 	if (strcasecmp(ptr, "-status") == 0) {
15074 		status = true;
15075 	} else if (strcasecmp(ptr, "-rollover") == 0) {
15076 		rollover = true;
15077 	} else if (strcasecmp(ptr, "-checkds") == 0) {
15078 		checkds = true;
15079 	} else {
15080 		CHECK(DNS_R_SYNTAX);
15081 	}
15082 
15083 	if (rollover || checkds) {
15084 		/* Check for options */
15085 		for (;;) {
15086 			ptr = next_token(lex, text);
15087 			if (ptr == NULL) {
15088 				msg = "Bad format";
15089 				CHECK(ISC_R_UNEXPECTEDEND);
15090 			} else if (argcheck(ptr, "alg")) {
15091 				isc_consttextregion_t alg;
15092 				ptr = next_token(lex, text);
15093 				if (ptr == NULL) {
15094 					msg = "No key algorithm specified";
15095 					CHECK(ISC_R_UNEXPECTEDEND);
15096 				}
15097 				alg.base = ptr;
15098 				alg.length = strlen(alg.base);
15099 				result = dns_secalg_fromtext(
15100 					&algorithm, (isc_textregion_t *)&alg);
15101 				if (result != ISC_R_SUCCESS) {
15102 					msg = "Bad algorithm";
15103 					CHECK(DNS_R_SYNTAX);
15104 				}
15105 				continue;
15106 			} else if (argcheck(ptr, "key")) {
15107 				uint16_t id;
15108 				ptr = next_token(lex, text);
15109 				if (ptr == NULL) {
15110 					msg = "No key identifier specified";
15111 					CHECK(ISC_R_UNEXPECTEDEND);
15112 				}
15113 				CHECK(isc_parse_uint16(&id, ptr, 10));
15114 				keyid = (dns_keytag_t)id;
15115 				use_keyid = true;
15116 				continue;
15117 			} else if (argcheck(ptr, "when")) {
15118 				uint32_t tw;
15119 				ptr = next_token(lex, text);
15120 				if (ptr == NULL) {
15121 					msg = "No time specified";
15122 					CHECK(ISC_R_UNEXPECTEDEND);
15123 				}
15124 				CHECK(dns_time32_fromtext(ptr, &tw));
15125 				when = (isc_stdtime_t)tw;
15126 				continue;
15127 			} else if (ptr[0] == '-') {
15128 				msg = "Unknown option";
15129 				CHECK(DNS_R_SYNTAX);
15130 			} else if (checkds) {
15131 				/*
15132 				 * No arguments provided, so we must be
15133 				 * parsing "published|withdrawn".
15134 				 */
15135 				if (strcasecmp(ptr, "published") == 0) {
15136 					dspublish = true;
15137 				} else if (strcasecmp(ptr, "withdrawn") != 0) {
15138 					CHECK(DNS_R_SYNTAX);
15139 				}
15140 			} else if (rollover) {
15141 				/*
15142 				 * No arguments provided, so we must be
15143 				 * parsing the zone.
15144 				 */
15145 				zonetext = ptr;
15146 			}
15147 			break;
15148 		}
15149 
15150 		if (rollover && !use_keyid) {
15151 			msg = "Key id is required when scheduling rollover";
15152 			CHECK(DNS_R_SYNTAX);
15153 		}
15154 
15155 		if (algorithm > 0 && !use_keyid) {
15156 			msg = "Key id is required when setting algorithm";
15157 			CHECK(DNS_R_SYNTAX);
15158 		}
15159 	}
15160 
15161 	/* Get zone. */
15162 	CHECK(zone_from_args(server, lex, zonetext, &zone, NULL, text, false));
15163 	if (zone == NULL) {
15164 		msg = "Zone not found";
15165 		CHECK(ISC_R_UNEXPECTEDEND);
15166 	}
15167 
15168 	/* Trailing garbage? */
15169 	ptr = next_token(lex, text);
15170 	if (ptr != NULL) {
15171 		msg = "Too many arguments";
15172 		CHECK(DNS_R_SYNTAX);
15173 	}
15174 
15175 	/* Get dnssec-policy. */
15176 	kasp = dns_zone_getkasp(zone);
15177 	if (kasp == NULL) {
15178 		msg = "Zone does not have dnssec-policy";
15179 		goto cleanup;
15180 	}
15181 
15182 	/* Get DNSSEC keys. */
15183 	CHECK(dns_zone_getdb(zone, &db));
15184 	dns_db_currentversion(db, &version);
15185 	LOCK(&kasp->lock);
15186 	result = dns_zone_getdnsseckeys(zone, db, version, now, &keys);
15187 	UNLOCK(&kasp->lock);
15188 	if (result != ISC_R_SUCCESS) {
15189 		if (result != ISC_R_NOTFOUND) {
15190 			goto cleanup;
15191 		}
15192 	}
15193 
15194 	if (status) {
15195 		/*
15196 		 * Output the DNSSEC status of the key and signing policy.
15197 		 */
15198 		LOCK(&kasp->lock);
15199 		dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
15200 		UNLOCK(&kasp->lock);
15201 		CHECK(putstr(text, output));
15202 	} else if (checkds) {
15203 		/*
15204 		 * Mark DS record has been seen, so it may move to the
15205 		 * rumoured state.
15206 		 */
15207 		char whenbuf[80];
15208 		isc_time_set(&timewhen, when, 0);
15209 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
15210 		isc_result_t ret;
15211 
15212 		LOCK(&kasp->lock);
15213 		if (use_keyid) {
15214 			result = dns_keymgr_checkds_id(kasp, &keys, now, when,
15215 						       dspublish, keyid,
15216 						       (unsigned int)algorithm);
15217 		} else {
15218 			result = dns_keymgr_checkds(kasp, &keys, now, when,
15219 						    dspublish);
15220 		}
15221 		UNLOCK(&kasp->lock);
15222 
15223 		switch (result) {
15224 		case ISC_R_SUCCESS:
15225 			/*
15226 			 * Rekey after checkds command because the next key
15227 			 * event may have changed.
15228 			 */
15229 			dns_zone_rekey(zone, false);
15230 
15231 			if (use_keyid) {
15232 				char tagbuf[6];
15233 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
15234 				CHECK(putstr(text, "KSK "));
15235 				CHECK(putstr(text, tagbuf));
15236 				CHECK(putstr(text, ": "));
15237 			}
15238 			CHECK(putstr(text, "Marked DS as "));
15239 			if (dspublish) {
15240 				CHECK(putstr(text, "published "));
15241 			} else {
15242 				CHECK(putstr(text, "withdrawn "));
15243 			}
15244 			CHECK(putstr(text, "since "));
15245 			CHECK(putstr(text, whenbuf));
15246 			break;
15247 		case DNS_R_TOOMANYKEYS:
15248 			CHECK(putstr(text,
15249 				     "Error: multiple possible keys found, "
15250 				     "retry command with -key id"));
15251 			break;
15252 		default:
15253 			ret = result;
15254 			CHECK(putstr(text,
15255 				     "Error executing checkds command: "));
15256 			CHECK(putstr(text, isc_result_totext(ret)));
15257 			break;
15258 		}
15259 	} else if (rollover) {
15260 		/*
15261 		 * Manually rollover a key.
15262 		 */
15263 		char whenbuf[80];
15264 		isc_time_set(&timewhen, when, 0);
15265 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
15266 		isc_result_t ret;
15267 
15268 		LOCK(&kasp->lock);
15269 		result = dns_keymgr_rollover(kasp, &keys, now, when, keyid,
15270 					     (unsigned int)algorithm);
15271 		UNLOCK(&kasp->lock);
15272 
15273 		switch (result) {
15274 		case ISC_R_SUCCESS:
15275 			/*
15276 			 * Rekey after rollover command because the next key
15277 			 * event may have changed.
15278 			 */
15279 			dns_zone_rekey(zone, false);
15280 
15281 			if (use_keyid) {
15282 				char tagbuf[6];
15283 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
15284 				CHECK(putstr(text, "Key "));
15285 				CHECK(putstr(text, tagbuf));
15286 				CHECK(putstr(text, ": "));
15287 			}
15288 			CHECK(putstr(text, "Rollover scheduled on "));
15289 			CHECK(putstr(text, whenbuf));
15290 			break;
15291 		case DNS_R_TOOMANYKEYS:
15292 			CHECK(putstr(text,
15293 				     "Error: multiple possible keys found, "
15294 				     "retry command with -alg algorithm"));
15295 			break;
15296 		default:
15297 			ret = result;
15298 			CHECK(putstr(text,
15299 				     "Error executing rollover command: "));
15300 			CHECK(putstr(text, isc_result_totext(ret)));
15301 			break;
15302 		}
15303 	}
15304 	CHECK(putnull(text));
15305 
15306 cleanup:
15307 	if (msg != NULL) {
15308 		(void)putstr(text, msg);
15309 		(void)putnull(text);
15310 	}
15311 
15312 	if (version != NULL) {
15313 		dns_db_closeversion(db, &version, false);
15314 	}
15315 	if (db != NULL) {
15316 		dns_db_detach(&db);
15317 	}
15318 
15319 	while (!ISC_LIST_EMPTY(keys)) {
15320 		key = ISC_LIST_HEAD(keys);
15321 		ISC_LIST_UNLINK(keys, key, link);
15322 		dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
15323 	}
15324 
15325 	if (zone != NULL) {
15326 		dns_zone_detach(&zone);
15327 	}
15328 
15329 	return result;
15330 }
15331 
15332 static isc_result_t
15333 putmem(isc_buffer_t **b, const char *str, size_t len) {
15334 	isc_result_t result;
15335 
15336 	result = isc_buffer_reserve(*b, (unsigned int)len);
15337 	if (result != ISC_R_SUCCESS) {
15338 		return ISC_R_NOSPACE;
15339 	}
15340 
15341 	isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
15342 	return ISC_R_SUCCESS;
15343 }
15344 
15345 static isc_result_t
15346 putstr(isc_buffer_t **b, const char *str) {
15347 	return putmem(b, str, strlen(str));
15348 }
15349 
15350 static isc_result_t
15351 putuint8(isc_buffer_t **b, uint8_t val) {
15352 	isc_result_t result;
15353 
15354 	result = isc_buffer_reserve(*b, 1);
15355 	if (result != ISC_R_SUCCESS) {
15356 		return ISC_R_NOSPACE;
15357 	}
15358 
15359 	isc_buffer_putuint8(*b, val);
15360 	return ISC_R_SUCCESS;
15361 }
15362 
15363 static isc_result_t
15364 putnull(isc_buffer_t **b) {
15365 	return putuint8(b, 0);
15366 }
15367 
15368 isc_result_t
15369 named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
15370 			isc_buffer_t **text) {
15371 	isc_result_t result = ISC_R_SUCCESS;
15372 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
15373 	const char *type, *file;
15374 	char zonename[DNS_NAME_FORMATSIZE];
15375 	uint32_t serial, signed_serial, nodes;
15376 	char serbuf[16], sserbuf[16], nodebuf[16];
15377 	char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2];
15378 	char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15379 	char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15380 	char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15381 	char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15382 	char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15383 	isc_time_t loadtime, expiretime, refreshtime;
15384 	isc_time_t refreshkeytime, resigntime;
15385 	dns_zonetype_t zonetype;
15386 	bool dynamic = false, frozen = false;
15387 	bool hasraw = false;
15388 	bool secure, maintain, allow;
15389 	dns_db_t *db = NULL, *rawdb = NULL;
15390 	char **incfiles = NULL;
15391 	int nfiles = 0;
15392 
15393 	REQUIRE(text != NULL);
15394 
15395 	isc_time_settoepoch(&loadtime);
15396 	isc_time_settoepoch(&refreshtime);
15397 	isc_time_settoepoch(&expiretime);
15398 	isc_time_settoepoch(&refreshkeytime);
15399 	isc_time_settoepoch(&resigntime);
15400 
15401 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
15402 	if (zone == NULL) {
15403 		result = ISC_R_UNEXPECTEDEND;
15404 		goto cleanup;
15405 	}
15406 
15407 	/* Inline signing? */
15408 	CHECK(dns_zone_getdb(zone, &db));
15409 	dns_zone_getraw(zone, &raw);
15410 	hasraw = (raw != NULL);
15411 	if (hasraw) {
15412 		mayberaw = raw;
15413 		zonetype = dns_zone_gettype(raw);
15414 		CHECK(dns_zone_getdb(raw, &rawdb));
15415 	} else {
15416 		mayberaw = zone;
15417 		zonetype = dns_zone_gettype(zone);
15418 	}
15419 
15420 	type = dns_zonetype_name(zonetype);
15421 
15422 	/* Serial number */
15423 	result = dns_zone_getserial(mayberaw, &serial);
15424 
15425 	/* This is to mirror old behavior with dns_zone_getserial */
15426 	if (result != ISC_R_SUCCESS) {
15427 		serial = 0;
15428 	}
15429 
15430 	snprintf(serbuf, sizeof(serbuf), "%u", serial);
15431 	if (hasraw) {
15432 		result = dns_zone_getserial(zone, &signed_serial);
15433 		if (result != ISC_R_SUCCESS) {
15434 			serial = 0;
15435 		}
15436 		snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial);
15437 	}
15438 
15439 	/* Database node count */
15440 	nodes = dns_db_nodecount(hasraw ? rawdb : db, dns_dbtree_main);
15441 	snprintf(nodebuf, sizeof(nodebuf), "%u", nodes);
15442 
15443 	/* Security */
15444 	secure = dns_db_issecure(db);
15445 	allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
15446 	maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
15447 
15448 	/* Master files */
15449 	file = dns_zone_getfile(mayberaw);
15450 	nfiles = dns_zone_getincludes(mayberaw, &incfiles);
15451 
15452 	/* Load time */
15453 	dns_zone_getloadtime(zone, &loadtime);
15454 	isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
15455 
15456 	/* Refresh/expire times */
15457 	if (zonetype == dns_zone_secondary || zonetype == dns_zone_mirror ||
15458 	    zonetype == dns_zone_stub || zonetype == dns_zone_redirect)
15459 	{
15460 		dns_zone_getexpiretime(mayberaw, &expiretime);
15461 		isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
15462 		dns_zone_getrefreshtime(mayberaw, &refreshtime);
15463 		isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
15464 	}
15465 
15466 	/* Key refresh time */
15467 	if (zonetype == dns_zone_primary ||
15468 	    (zonetype == dns_zone_secondary && hasraw))
15469 	{
15470 		dns_zone_getrefreshkeytime(zone, &refreshkeytime);
15471 		isc_time_formathttptimestamp(&refreshkeytime, kbuf,
15472 					     sizeof(kbuf));
15473 	}
15474 
15475 	/* Dynamic? */
15476 	if (zonetype == dns_zone_primary) {
15477 		dynamic = dns_zone_isdynamic(mayberaw, true);
15478 		frozen = dynamic && !dns_zone_isdynamic(mayberaw, false);
15479 	}
15480 
15481 	/* Next resign event */
15482 	if (secure && (zonetype == dns_zone_primary ||
15483 		       (zonetype == dns_zone_secondary && hasraw)))
15484 	{
15485 		dns_name_t *name;
15486 		dns_fixedname_t fixed;
15487 		isc_stdtime_t resign;
15488 		dns_typepair_t typepair;
15489 
15490 		name = dns_fixedname_initname(&fixed);
15491 
15492 		result = dns_db_getsigningtime(db, &resign, name, &typepair);
15493 		if (result == ISC_R_SUCCESS) {
15494 			char namebuf[DNS_NAME_FORMATSIZE];
15495 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
15496 
15497 			resign -= dns_zone_getsigresigninginterval(zone);
15498 
15499 			dns_name_format(name, namebuf, sizeof(namebuf));
15500 			dns_rdatatype_format(DNS_TYPEPAIR_COVERS(typepair),
15501 					     typebuf, sizeof(typebuf));
15502 			snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf,
15503 				 typebuf);
15504 			isc_time_set(&resigntime, resign, 0);
15505 			isc_time_formathttptimestamp(&resigntime, rtbuf,
15506 						     sizeof(rtbuf));
15507 		}
15508 	}
15509 
15510 	/* Create text */
15511 	CHECK(putstr(text, "name: "));
15512 	CHECK(putstr(text, zonename));
15513 
15514 	CHECK(putstr(text, "\ntype: "));
15515 	CHECK(putstr(text, type));
15516 
15517 	if (file != NULL) {
15518 		int i;
15519 		CHECK(putstr(text, "\nfiles: "));
15520 		CHECK(putstr(text, file));
15521 		for (i = 0; i < nfiles; i++) {
15522 			CHECK(putstr(text, ", "));
15523 			if (incfiles[i] != NULL) {
15524 				CHECK(putstr(text, incfiles[i]));
15525 			}
15526 		}
15527 	}
15528 
15529 	CHECK(putstr(text, "\nserial: "));
15530 	CHECK(putstr(text, serbuf));
15531 	if (hasraw) {
15532 		CHECK(putstr(text, "\nsigned serial: "));
15533 		CHECK(putstr(text, sserbuf));
15534 	}
15535 
15536 	CHECK(putstr(text, "\nnodes: "));
15537 	CHECK(putstr(text, nodebuf));
15538 
15539 	if (!isc_time_isepoch(&loadtime)) {
15540 		CHECK(putstr(text, "\nlast loaded: "));
15541 		CHECK(putstr(text, lbuf));
15542 	}
15543 
15544 	if (!isc_time_isepoch(&refreshtime)) {
15545 		CHECK(putstr(text, "\nnext refresh: "));
15546 		CHECK(putstr(text, rbuf));
15547 	}
15548 
15549 	if (!isc_time_isepoch(&expiretime)) {
15550 		CHECK(putstr(text, "\nexpires: "));
15551 		CHECK(putstr(text, xbuf));
15552 	}
15553 
15554 	if (secure) {
15555 		CHECK(putstr(text, "\nsecure: yes"));
15556 		if (hasraw) {
15557 			CHECK(putstr(text, "\ninline signing: yes"));
15558 		} else {
15559 			CHECK(putstr(text, "\ninline signing: no"));
15560 		}
15561 	} else {
15562 		CHECK(putstr(text, "\nsecure: no"));
15563 	}
15564 
15565 	if (maintain) {
15566 		CHECK(putstr(text, "\nkey maintenance: automatic"));
15567 		if (!isc_time_isepoch(&refreshkeytime)) {
15568 			CHECK(putstr(text, "\nnext key event: "));
15569 			CHECK(putstr(text, kbuf));
15570 		}
15571 	} else if (allow) {
15572 		CHECK(putstr(text, "\nkey maintenance: on command"));
15573 	} else if (secure || hasraw) {
15574 		CHECK(putstr(text, "\nkey maintenance: none"));
15575 	}
15576 
15577 	if (!isc_time_isepoch(&resigntime)) {
15578 		CHECK(putstr(text, "\nnext resign node: "));
15579 		CHECK(putstr(text, resignbuf));
15580 		CHECK(putstr(text, "\nnext resign time: "));
15581 		CHECK(putstr(text, rtbuf));
15582 	}
15583 
15584 	if (dynamic) {
15585 		CHECK(putstr(text, "\ndynamic: yes"));
15586 		if (frozen) {
15587 			CHECK(putstr(text, "\nfrozen: yes"));
15588 		} else {
15589 			CHECK(putstr(text, "\nfrozen: no"));
15590 		}
15591 	} else {
15592 		CHECK(putstr(text, "\ndynamic: no"));
15593 	}
15594 
15595 	CHECK(putstr(text, "\nreconfigurable via modzone: "));
15596 	CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
15597 
15598 cleanup:
15599 	/* Indicate truncated output if possible. */
15600 	if (result == ISC_R_NOSPACE) {
15601 		(void)putstr(text, "\n...");
15602 	}
15603 	if (result == ISC_R_SUCCESS || result == ISC_R_NOSPACE) {
15604 		(void)putnull(text);
15605 	}
15606 
15607 	if (db != NULL) {
15608 		dns_db_detach(&db);
15609 	}
15610 	if (rawdb != NULL) {
15611 		dns_db_detach(&rawdb);
15612 	}
15613 	if (incfiles != NULL && mayberaw != NULL) {
15614 		int i;
15615 		isc_mem_t *mctx = dns_zone_getmctx(mayberaw);
15616 
15617 		for (i = 0; i < nfiles; i++) {
15618 			if (incfiles[i] != NULL) {
15619 				isc_mem_free(mctx, incfiles[i]);
15620 			}
15621 		}
15622 		isc_mem_free(mctx, incfiles);
15623 	}
15624 	if (raw != NULL) {
15625 		dns_zone_detach(&raw);
15626 	}
15627 	if (zone != NULL) {
15628 		dns_zone_detach(&zone);
15629 	}
15630 	return result;
15631 }
15632 
15633 isc_result_t
15634 named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
15635 		 isc_buffer_t **text) {
15636 	dns_view_t *view;
15637 	dns_ntatable_t *ntatable = NULL;
15638 	isc_result_t result = ISC_R_SUCCESS;
15639 	char *ptr, *nametext = NULL, *viewname;
15640 	char namebuf[DNS_NAME_FORMATSIZE];
15641 	char viewbuf[DNS_NAME_FORMATSIZE];
15642 	isc_stdtime_t now, when;
15643 	isc_time_t t;
15644 	char tbuf[64];
15645 	const char *msg = NULL;
15646 	bool dump = false, force = false;
15647 	dns_fixedname_t fn;
15648 	const dns_name_t *ntaname;
15649 	dns_name_t *fname;
15650 	dns_ttl_t ntattl;
15651 	bool ttlset = false, viewfound = false;
15652 	dns_rdataclass_t rdclass = dns_rdataclass_in;
15653 	bool first = true;
15654 
15655 	REQUIRE(text != NULL);
15656 
15657 	UNUSED(force);
15658 
15659 	fname = dns_fixedname_initname(&fn);
15660 
15661 	/* Skip the command name. */
15662 	ptr = next_token(lex, text);
15663 	if (ptr == NULL) {
15664 		return ISC_R_UNEXPECTEDEND;
15665 	}
15666 
15667 	for (;;) {
15668 		/* Check for options */
15669 		ptr = next_token(lex, text);
15670 		if (ptr == NULL) {
15671 			return ISC_R_UNEXPECTEDEND;
15672 		}
15673 
15674 		if (strcmp(ptr, "--") == 0) {
15675 			break;
15676 		} else if (argcheck(ptr, "dump")) {
15677 			dump = true;
15678 		} else if (argcheck(ptr, "remove")) {
15679 			ntattl = 0;
15680 			ttlset = true;
15681 		} else if (argcheck(ptr, "force")) {
15682 			force = true;
15683 			continue;
15684 		} else if (argcheck(ptr, "lifetime")) {
15685 			isc_textregion_t tr;
15686 
15687 			ptr = next_token(lex, text);
15688 			if (ptr == NULL) {
15689 				msg = "No lifetime specified";
15690 				CHECK(ISC_R_UNEXPECTEDEND);
15691 			}
15692 
15693 			tr.base = ptr;
15694 			tr.length = strlen(ptr);
15695 			result = dns_ttl_fromtext(&tr, &ntattl);
15696 			if (result != ISC_R_SUCCESS) {
15697 				msg = "could not parse NTA lifetime";
15698 				CHECK(result);
15699 			}
15700 
15701 			if (ntattl > 604800) {
15702 				msg = "NTA lifetime cannot exceed one week";
15703 				CHECK(ISC_R_RANGE);
15704 			}
15705 
15706 			ttlset = true;
15707 			continue;
15708 		} else if (argcheck(ptr, "class")) {
15709 			isc_textregion_t tr;
15710 
15711 			ptr = next_token(lex, text);
15712 			if (ptr == NULL) {
15713 				msg = "No class specified";
15714 				CHECK(ISC_R_UNEXPECTEDEND);
15715 			}
15716 
15717 			tr.base = ptr;
15718 			tr.length = strlen(ptr);
15719 			CHECK(dns_rdataclass_fromtext(&rdclass, &tr));
15720 			continue;
15721 		} else if (ptr[0] == '-') {
15722 			msg = "Unknown option";
15723 			CHECK(DNS_R_SYNTAX);
15724 		} else {
15725 			nametext = ptr;
15726 		}
15727 
15728 		break;
15729 	}
15730 
15731 	/*
15732 	 * If -dump was specified, list NTA's and return
15733 	 */
15734 	if (dump) {
15735 		size_t last = 0;
15736 
15737 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15738 		     view = ISC_LIST_NEXT(view, link))
15739 		{
15740 			if (ntatable != NULL) {
15741 				dns_ntatable_detach(&ntatable);
15742 			}
15743 			result = dns_view_getntatable(view, &ntatable);
15744 			if (result == ISC_R_NOTFOUND) {
15745 				continue;
15746 			}
15747 
15748 			if (last != isc_buffer_usedlength(*text)) {
15749 				CHECK(putstr(text, "\n"));
15750 			}
15751 
15752 			last = isc_buffer_usedlength(*text);
15753 
15754 			CHECK(dns_ntatable_totext(ntatable, view->name, text));
15755 		}
15756 		CHECK(putnull(text));
15757 
15758 		goto cleanup;
15759 	}
15760 
15761 	if (readonly) {
15762 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15763 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
15764 			      "rejecting restricted control channel "
15765 			      "NTA command");
15766 		CHECK(ISC_R_FAILURE);
15767 	}
15768 
15769 	/* Get the NTA name if not found above. */
15770 	if (nametext == NULL) {
15771 		nametext = next_token(lex, text);
15772 	}
15773 	if (nametext == NULL) {
15774 		return ISC_R_UNEXPECTEDEND;
15775 	}
15776 
15777 	/* Copy nametext as it'll be overwritten by next_token() */
15778 	strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE);
15779 
15780 	if (strcmp(namebuf, ".") == 0) {
15781 		ntaname = dns_rootname;
15782 	} else {
15783 		isc_buffer_t b;
15784 		isc_buffer_init(&b, namebuf, strlen(namebuf));
15785 		isc_buffer_add(&b, strlen(namebuf));
15786 		CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL));
15787 		ntaname = fname;
15788 	}
15789 
15790 	/* Look for the view name. */
15791 	viewname = next_token(lex, text);
15792 	if (viewname != NULL) {
15793 		strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE);
15794 		viewname = viewbuf;
15795 	}
15796 
15797 	if (next_token(lex, text) != NULL) {
15798 		CHECK(DNS_R_SYNTAX);
15799 	}
15800 
15801 	now = isc_stdtime_now();
15802 
15803 	isc_loopmgr_pause(named_g_loopmgr);
15804 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15805 	     view = ISC_LIST_NEXT(view, link))
15806 	{
15807 		if (viewname != NULL && strcmp(view->name, viewname) != 0) {
15808 			continue;
15809 		}
15810 		viewfound = true;
15811 
15812 		if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) {
15813 			continue;
15814 		}
15815 
15816 		if (view->nta_lifetime == 0) {
15817 			continue;
15818 		}
15819 
15820 		if (!ttlset) {
15821 			ntattl = view->nta_lifetime;
15822 		}
15823 
15824 		if (ntatable != NULL) {
15825 			dns_ntatable_detach(&ntatable);
15826 		}
15827 
15828 		result = dns_view_getntatable(view, &ntatable);
15829 		if (result == ISC_R_NOTFOUND) {
15830 			result = ISC_R_SUCCESS;
15831 			continue;
15832 		}
15833 
15834 		result = dns_view_flushnode(view, ntaname, true);
15835 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15836 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15837 			      "flush tree '%s' in cache view '%s': %s", namebuf,
15838 			      view->name, isc_result_totext(result));
15839 
15840 		if (ntattl != 0) {
15841 			CHECK(dns_ntatable_add(ntatable, ntaname, force, now,
15842 					       ntattl));
15843 
15844 			when = now + ntattl;
15845 			isc_time_set(&t, when, 0);
15846 			isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
15847 
15848 			if (!first) {
15849 				CHECK(putstr(text, "\n"));
15850 			}
15851 			first = false;
15852 
15853 			CHECK(putstr(text, "Negative trust anchor added: "));
15854 			CHECK(putstr(text, namebuf));
15855 			CHECK(putstr(text, "/"));
15856 			CHECK(putstr(text, view->name));
15857 			CHECK(putstr(text, ", expires "));
15858 			CHECK(putstr(text, tbuf));
15859 
15860 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15861 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15862 				      "added NTA '%s' (%d sec) in view '%s'",
15863 				      namebuf, ntattl, view->name);
15864 		} else {
15865 			bool wasremoved;
15866 
15867 			result = dns_ntatable_delete(ntatable, ntaname);
15868 			if (result == ISC_R_SUCCESS) {
15869 				wasremoved = true;
15870 			} else if (result == ISC_R_NOTFOUND) {
15871 				wasremoved = false;
15872 			} else {
15873 				goto cleanup_exclusive;
15874 			}
15875 
15876 			if (!first) {
15877 				CHECK(putstr(text, "\n"));
15878 			}
15879 			first = false;
15880 
15881 			CHECK(putstr(text, "Negative trust anchor "));
15882 			CHECK(putstr(text,
15883 				     wasremoved ? "removed: " : "not found: "));
15884 			CHECK(putstr(text, namebuf));
15885 			CHECK(putstr(text, "/"));
15886 			CHECK(putstr(text, view->name));
15887 
15888 			if (wasremoved) {
15889 				isc_log_write(
15890 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15891 					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15892 					"removed NTA '%s' in view %s", namebuf,
15893 					view->name);
15894 			}
15895 		}
15896 
15897 		result = dns_view_saventa(view);
15898 		if (result != ISC_R_SUCCESS) {
15899 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15900 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15901 				      "error writing NTA file "
15902 				      "for view '%s': %s",
15903 				      view->name, isc_result_totext(result));
15904 		}
15905 	}
15906 
15907 	if (!viewfound) {
15908 		msg = "No such view";
15909 		result = ISC_R_NOTFOUND;
15910 	} else {
15911 		(void)putnull(text);
15912 	}
15913 
15914 cleanup_exclusive:
15915 	isc_loopmgr_resume(named_g_loopmgr);
15916 
15917 cleanup:
15918 
15919 	if (msg != NULL) {
15920 		(void)putstr(text, msg);
15921 		(void)putnull(text);
15922 	}
15923 
15924 	if (ntatable != NULL) {
15925 		dns_ntatable_detach(&ntatable);
15926 	}
15927 	return result;
15928 }
15929 
15930 isc_result_t
15931 named_server_saventa(named_server_t *server) {
15932 	dns_view_t *view;
15933 
15934 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15935 	     view = ISC_LIST_NEXT(view, link))
15936 	{
15937 		isc_result_t result = dns_view_saventa(view);
15938 
15939 		if (result != ISC_R_SUCCESS) {
15940 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15941 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15942 				      "error writing NTA file "
15943 				      "for view '%s': %s",
15944 				      view->name, isc_result_totext(result));
15945 		}
15946 	}
15947 
15948 	return ISC_R_SUCCESS;
15949 }
15950 
15951 isc_result_t
15952 named_server_loadnta(named_server_t *server) {
15953 	dns_view_t *view;
15954 
15955 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15956 	     view = ISC_LIST_NEXT(view, link))
15957 	{
15958 		isc_result_t result = dns_view_loadnta(view);
15959 
15960 		if ((result != ISC_R_SUCCESS) &&
15961 		    (result != ISC_R_FILENOTFOUND) &&
15962 		    (result != ISC_R_NOTFOUND))
15963 		{
15964 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15965 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15966 				      "error loading NTA file "
15967 				      "for view '%s': %s",
15968 				      view->name, isc_result_totext(result));
15969 		}
15970 	}
15971 
15972 	return ISC_R_SUCCESS;
15973 }
15974 
15975 static isc_result_t
15976 mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
15977 	isc_result_t result;
15978 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
15979 
15980 	snprintf(msg, sizeof(msg), "refreshing managed keys for '%s'",
15981 		 view->name);
15982 	CHECK(putstr(text, msg));
15983 	CHECK(dns_zone_synckeyzone(view->managed_keys));
15984 
15985 cleanup:
15986 	return result;
15987 }
15988 
15989 static isc_result_t
15990 mkey_destroy(dns_view_t *view, isc_buffer_t **text) {
15991 	isc_result_t result;
15992 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
15993 	const char *file = NULL;
15994 	dns_db_t *dbp = NULL;
15995 	dns_zone_t *mkzone = NULL;
15996 	bool removed_a_file = false;
15997 
15998 	if (view->managed_keys == NULL) {
15999 		CHECK(ISC_R_NOTFOUND);
16000 	}
16001 
16002 	snprintf(msg, sizeof(msg), "destroying managed-keys database for '%s'",
16003 		 view->name);
16004 	CHECK(putstr(text, msg));
16005 
16006 	isc_loopmgr_pause(named_g_loopmgr);
16007 
16008 	/* Remove and clean up managed keys zone from view */
16009 	mkzone = view->managed_keys;
16010 	view->managed_keys = NULL;
16011 	(void)dns_zone_flush(mkzone);
16012 
16013 	/* Unload zone database */
16014 	if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) {
16015 		dns_db_detach(&dbp);
16016 		dns_zone_unload(mkzone);
16017 	}
16018 
16019 	/* Delete files */
16020 	file = dns_zone_getfile(mkzone);
16021 	result = isc_file_remove(file);
16022 	if (result == ISC_R_SUCCESS) {
16023 		removed_a_file = true;
16024 	} else {
16025 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16026 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
16027 			      "file %s not removed: %s", file,
16028 			      isc_result_totext(result));
16029 	}
16030 
16031 	file = dns_zone_getjournal(mkzone);
16032 	result = isc_file_remove(file);
16033 	if (result == ISC_R_SUCCESS) {
16034 		removed_a_file = true;
16035 	} else {
16036 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16037 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
16038 			      "file %s not removed: %s", file,
16039 			      isc_result_totext(result));
16040 	}
16041 
16042 	if (!removed_a_file) {
16043 		CHECK(putstr(text, "error: no files could be removed"));
16044 		CHECK(ISC_R_FAILURE);
16045 	}
16046 
16047 	dns_zone_detach(&mkzone);
16048 	result = ISC_R_SUCCESS;
16049 
16050 cleanup:
16051 	isc_loopmgr_resume(named_g_loopmgr);
16052 	return result;
16053 }
16054 
16055 static isc_result_t
16056 mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
16057 	isc_result_t result;
16058 	dns_db_t *db = NULL;
16059 	dns_dbversion_t *ver = NULL;
16060 	dns_rriterator_t rrit;
16061 	isc_stdtime_t now = isc_stdtime_now();
16062 	dns_name_t *prevname = NULL;
16063 
16064 	CHECK(dns_zone_getdb(view->managed_keys, &db));
16065 	dns_db_currentversion(db, &ver);
16066 	dns_rriterator_init(&rrit, db, ver, 0);
16067 	for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS;
16068 	     result = dns_rriterator_nextrrset(&rrit))
16069 	{
16070 		char buf[DNS_NAME_FORMATSIZE + 500];
16071 		dns_name_t *name = NULL;
16072 		dns_rdataset_t *kdset = NULL;
16073 		dns_rdata_t rdata = DNS_RDATA_INIT;
16074 		dns_rdata_keydata_t kd;
16075 		uint32_t ttl;
16076 
16077 		dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
16078 		if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
16079 		    !dns_rdataset_isassociated(kdset))
16080 		{
16081 			continue;
16082 		}
16083 
16084 		if (name != prevname) {
16085 			char nbuf[DNS_NAME_FORMATSIZE];
16086 			dns_name_format(name, nbuf, sizeof(nbuf));
16087 			snprintf(buf, sizeof(buf), "\n\n    name: %s", nbuf);
16088 			CHECK(putstr(text, buf));
16089 		}
16090 
16091 		for (result = dns_rdataset_first(kdset);
16092 		     result == ISC_R_SUCCESS; result = dns_rdataset_next(kdset))
16093 		{
16094 			char alg[DNS_SECALG_FORMATSIZE];
16095 			char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
16096 			dns_keytag_t keyid;
16097 			isc_region_t r;
16098 			isc_time_t t;
16099 			bool revoked;
16100 
16101 			dns_rdata_reset(&rdata);
16102 			dns_rdataset_current(kdset, &rdata);
16103 			result = dns_rdata_tostruct(&rdata, &kd, NULL);
16104 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
16105 
16106 			dns_rdata_toregion(&rdata, &r);
16107 			isc_region_consume(&r, 12);
16108 			keyid = dst_region_computeid(&r);
16109 
16110 			snprintf(buf, sizeof(buf), "\n    keyid: %u", keyid);
16111 			CHECK(putstr(text, buf));
16112 
16113 			dns_secalg_format(kd.algorithm, alg, sizeof(alg));
16114 			snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
16115 			CHECK(putstr(text, buf));
16116 
16117 			revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
16118 			snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
16119 				 revoked ? " REVOKE" : "",
16120 				 ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP"
16121 								     : "",
16122 				 (kd.flags == 0) ? " (none)" : "");
16123 			CHECK(putstr(text, buf));
16124 
16125 			isc_time_set(&t, kd.refresh, 0);
16126 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
16127 			snprintf(buf, sizeof(buf), "\n\tnext refresh: %s",
16128 				 tbuf);
16129 			CHECK(putstr(text, buf));
16130 
16131 			if (kd.removehd != 0) {
16132 				isc_time_set(&t, kd.removehd, 0);
16133 				isc_time_formathttptimestamp(&t, tbuf,
16134 							     sizeof(tbuf));
16135 				snprintf(buf, sizeof(buf), "\n\tremove at: %s",
16136 					 tbuf);
16137 				CHECK(putstr(text, buf));
16138 			}
16139 
16140 			isc_time_set(&t, kd.addhd, 0);
16141 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
16142 			if (kd.addhd == 0) {
16143 				snprintf(buf, sizeof(buf), "\n\tno trust");
16144 			} else if (revoked) {
16145 				snprintf(buf, sizeof(buf), "\n\ttrust revoked");
16146 			} else if (kd.addhd <= now) {
16147 				snprintf(buf, sizeof(buf),
16148 					 "\n\ttrusted since: %s", tbuf);
16149 			} else if (kd.addhd > now) {
16150 				snprintf(buf, sizeof(buf),
16151 					 "\n\ttrust pending: %s", tbuf);
16152 			}
16153 			CHECK(putstr(text, buf));
16154 		}
16155 	}
16156 
16157 	if (result == ISC_R_NOMORE) {
16158 		result = ISC_R_SUCCESS;
16159 	}
16160 
16161 cleanup:
16162 	if (ver != NULL) {
16163 		dns_rriterator_destroy(&rrit);
16164 		dns_db_closeversion(db, &ver, false);
16165 	}
16166 	if (db != NULL) {
16167 		dns_db_detach(&db);
16168 	}
16169 
16170 	return result;
16171 }
16172 
16173 static isc_result_t
16174 mkey_status(dns_view_t *view, isc_buffer_t **text) {
16175 	isc_result_t result;
16176 	char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
16177 	isc_time_t t;
16178 
16179 	CHECK(putstr(text, "view: "));
16180 	CHECK(putstr(text, view->name));
16181 
16182 	CHECK(putstr(text, "\nnext scheduled event: "));
16183 
16184 	dns_zone_getrefreshkeytime(view->managed_keys, &t);
16185 	if (isc_time_isepoch(&t)) {
16186 		CHECK(putstr(text, "never"));
16187 	} else {
16188 		isc_time_formathttptimestamp(&t, msg, sizeof(msg));
16189 		CHECK(putstr(text, msg));
16190 	}
16191 
16192 	CHECK(mkey_dumpzone(view, text));
16193 
16194 cleanup:
16195 	return result;
16196 }
16197 
16198 isc_result_t
16199 named_server_mkeys(named_server_t *server, isc_lex_t *lex,
16200 		   isc_buffer_t **text) {
16201 	char *cmd, *classtxt, *viewtxt = NULL;
16202 	isc_result_t result = ISC_R_SUCCESS;
16203 	dns_view_t *view = NULL;
16204 	dns_rdataclass_t rdclass;
16205 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
16206 	enum { NONE, STAT, REFRESH, SYNC, DESTROY } opt = NONE;
16207 	bool found = false;
16208 	bool first = true;
16209 
16210 	REQUIRE(text != NULL);
16211 
16212 	/* Skip rndc command name */
16213 	cmd = next_token(lex, text);
16214 	if (cmd == NULL) {
16215 		return ISC_R_UNEXPECTEDEND;
16216 	}
16217 
16218 	/* Get managed-keys subcommand */
16219 	cmd = next_token(lex, text);
16220 	if (cmd == NULL) {
16221 		return ISC_R_UNEXPECTEDEND;
16222 	}
16223 
16224 	if (strcasecmp(cmd, "status") == 0) {
16225 		opt = STAT;
16226 	} else if (strcasecmp(cmd, "refresh") == 0) {
16227 		opt = REFRESH;
16228 	} else if (strcasecmp(cmd, "sync") == 0) {
16229 		opt = SYNC;
16230 	} else if (strcasecmp(cmd, "destroy") == 0) {
16231 		opt = DESTROY;
16232 	} else {
16233 		snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
16234 		(void)putstr(text, msg);
16235 		result = ISC_R_UNEXPECTED;
16236 		goto cleanup;
16237 	}
16238 
16239 	/* Look for the optional class name. */
16240 	classtxt = next_token(lex, text);
16241 	if (classtxt != NULL) {
16242 		isc_textregion_t r;
16243 		r.base = classtxt;
16244 		r.length = strlen(classtxt);
16245 		result = dns_rdataclass_fromtext(&rdclass, &r);
16246 		if (result != ISC_R_SUCCESS) {
16247 			snprintf(msg, sizeof(msg), "unknown class '%s'",
16248 				 classtxt);
16249 			(void)putstr(text, msg);
16250 			goto cleanup;
16251 		}
16252 		viewtxt = next_token(lex, text);
16253 	}
16254 
16255 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16256 	     view = ISC_LIST_NEXT(view, link))
16257 	{
16258 		if (viewtxt != NULL && (rdclass != view->rdclass ||
16259 					strcmp(view->name, viewtxt) != 0))
16260 		{
16261 			continue;
16262 		}
16263 
16264 		if (view->managed_keys == NULL) {
16265 			if (viewtxt != NULL) {
16266 				snprintf(msg, sizeof(msg),
16267 					 "view '%s': no managed keys", viewtxt);
16268 				CHECK(putstr(text, msg));
16269 				goto cleanup;
16270 			} else {
16271 				continue;
16272 			}
16273 		}
16274 
16275 		found = true;
16276 
16277 		switch (opt) {
16278 		case REFRESH:
16279 			if (!first) {
16280 				CHECK(putstr(text, "\n"));
16281 			}
16282 			CHECK(mkey_refresh(view, text));
16283 			break;
16284 		case STAT:
16285 			if (!first) {
16286 				CHECK(putstr(text, "\n\n"));
16287 			}
16288 			CHECK(mkey_status(view, text));
16289 			break;
16290 		case SYNC:
16291 			CHECK(dns_zone_flush(view->managed_keys));
16292 			break;
16293 		case DESTROY:
16294 			if (!first) {
16295 				CHECK(putstr(text, "\n"));
16296 			}
16297 			CHECK(mkey_destroy(view, text));
16298 			break;
16299 		default:
16300 			UNREACHABLE();
16301 		}
16302 
16303 		if (viewtxt != NULL) {
16304 			break;
16305 		}
16306 		first = false;
16307 	}
16308 
16309 	if (!found) {
16310 		CHECK(putstr(text, "no views with managed keys"));
16311 	}
16312 
16313 cleanup:
16314 	if (isc_buffer_usedlength(*text) > 0) {
16315 		(void)putnull(text);
16316 	}
16317 
16318 	return result;
16319 }
16320 
16321 isc_result_t
16322 named_server_dnstap(named_server_t *server, isc_lex_t *lex,
16323 		    isc_buffer_t **text) {
16324 #ifdef HAVE_DNSTAP
16325 	char *ptr;
16326 	isc_result_t result;
16327 	bool reopen = false;
16328 	int backups = 0;
16329 
16330 	REQUIRE(text != NULL);
16331 
16332 	if (server->dtenv == NULL) {
16333 		return ISC_R_NOTFOUND;
16334 	}
16335 
16336 	/* Check the command name. */
16337 	ptr = next_token(lex, text);
16338 	if (ptr == NULL) {
16339 		return ISC_R_UNEXPECTEDEND;
16340 	}
16341 
16342 	/* "dnstap-reopen" was used in 9.11.0b1 */
16343 	if (strcasecmp(ptr, "dnstap-reopen") == 0) {
16344 		reopen = true;
16345 	} else {
16346 		ptr = next_token(lex, text);
16347 		if (ptr == NULL) {
16348 			return ISC_R_UNEXPECTEDEND;
16349 		}
16350 	}
16351 
16352 	if (reopen || strcasecmp(ptr, "-reopen") == 0) {
16353 		backups = ISC_LOG_ROLLNEVER;
16354 	} else if (strcasecmp(ptr, "-roll") == 0) {
16355 		unsigned int n;
16356 		ptr = next_token(lex, text);
16357 		if (ptr != NULL) {
16358 			unsigned int u;
16359 			n = sscanf(ptr, "%u", &u);
16360 			if (n != 1U || u > INT_MAX) {
16361 				return ISC_R_BADNUMBER;
16362 			}
16363 			backups = u;
16364 		} else {
16365 			backups = ISC_LOG_ROLLINFINITE;
16366 		}
16367 	} else {
16368 		return DNS_R_SYNTAX;
16369 	}
16370 
16371 	result = dns_dt_reopen(server->dtenv, backups);
16372 	return result;
16373 #else  /* ifdef HAVE_DNSTAP */
16374 	UNUSED(server);
16375 	UNUSED(lex);
16376 	UNUSED(text);
16377 	return ISC_R_NOTIMPLEMENTED;
16378 #endif /* ifdef HAVE_DNSTAP */
16379 }
16380 
16381 isc_result_t
16382 named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) {
16383 	char *ptr;
16384 	isc_result_t result = ISC_R_SUCCESS;
16385 	uint32_t initial, idle, keepalive, advertised;
16386 	char msg[128];
16387 
16388 	/* Skip the command name. */
16389 	ptr = next_token(lex, text);
16390 	if (ptr == NULL) {
16391 		return ISC_R_UNEXPECTEDEND;
16392 	}
16393 
16394 	isc_nm_gettimeouts(named_g_netmgr, &initial, &idle, &keepalive,
16395 			   &advertised);
16396 
16397 	/* Look for optional arguments. */
16398 	ptr = next_token(lex, NULL);
16399 	if (ptr != NULL) {
16400 		CHECK(isc_parse_uint32(&initial, ptr, 10));
16401 		initial *= 100;
16402 		if (initial > MAX_INITIAL_TIMEOUT) {
16403 			CHECK(ISC_R_RANGE);
16404 		}
16405 		if (initial < MIN_INITIAL_TIMEOUT) {
16406 			CHECK(ISC_R_RANGE);
16407 		}
16408 
16409 		ptr = next_token(lex, text);
16410 		if (ptr == NULL) {
16411 			return ISC_R_UNEXPECTEDEND;
16412 		}
16413 		CHECK(isc_parse_uint32(&idle, ptr, 10));
16414 		idle *= 100;
16415 		if (idle > MAX_IDLE_TIMEOUT) {
16416 			CHECK(ISC_R_RANGE);
16417 		}
16418 		if (idle < MIN_IDLE_TIMEOUT) {
16419 			CHECK(ISC_R_RANGE);
16420 		}
16421 
16422 		ptr = next_token(lex, text);
16423 		if (ptr == NULL) {
16424 			return ISC_R_UNEXPECTEDEND;
16425 		}
16426 		CHECK(isc_parse_uint32(&keepalive, ptr, 10));
16427 		keepalive *= 100;
16428 		if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
16429 			CHECK(ISC_R_RANGE);
16430 		}
16431 		if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
16432 			CHECK(ISC_R_RANGE);
16433 		}
16434 
16435 		ptr = next_token(lex, text);
16436 		if (ptr == NULL) {
16437 			return ISC_R_UNEXPECTEDEND;
16438 		}
16439 		CHECK(isc_parse_uint32(&advertised, ptr, 10));
16440 		advertised *= 100;
16441 		if (advertised > MAX_ADVERTISED_TIMEOUT) {
16442 			CHECK(ISC_R_RANGE);
16443 		}
16444 
16445 		isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
16446 				   advertised);
16447 	}
16448 
16449 	snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100);
16450 	CHECK(putstr(text, msg));
16451 	snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100);
16452 	CHECK(putstr(text, msg));
16453 	snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n",
16454 		 keepalive / 100);
16455 	CHECK(putstr(text, msg));
16456 	snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u",
16457 		 advertised / 100);
16458 	CHECK(putstr(text, msg));
16459 
16460 cleanup:
16461 	if (isc_buffer_usedlength(*text) > 0) {
16462 		(void)putnull(text);
16463 	}
16464 
16465 	return result;
16466 }
16467 
16468 isc_result_t
16469 named_server_servestale(named_server_t *server, isc_lex_t *lex,
16470 			isc_buffer_t **text) {
16471 	char *ptr, *classtxt, *viewtxt = NULL;
16472 	char msg[128];
16473 	dns_rdataclass_t rdclass = dns_rdataclass_in;
16474 	dns_view_t *view;
16475 	bool found = false;
16476 	dns_stale_answer_t staleanswersok = dns_stale_answer_conf;
16477 	bool wantstatus = false;
16478 	isc_result_t result = ISC_R_SUCCESS;
16479 
16480 	REQUIRE(text != NULL);
16481 
16482 	/* Skip the command name. */
16483 	ptr = next_token(lex, text);
16484 	if (ptr == NULL) {
16485 		return ISC_R_UNEXPECTEDEND;
16486 	}
16487 
16488 	ptr = next_token(lex, NULL);
16489 	if (ptr == NULL) {
16490 		return ISC_R_UNEXPECTEDEND;
16491 	}
16492 
16493 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
16494 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
16495 	{
16496 		staleanswersok = dns_stale_answer_yes;
16497 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
16498 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
16499 	{
16500 		staleanswersok = dns_stale_answer_no;
16501 	} else if (strcasecmp(ptr, "reset") == 0) {
16502 		staleanswersok = dns_stale_answer_conf;
16503 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
16504 		wantstatus = true;
16505 	} else {
16506 		return DNS_R_SYNTAX;
16507 	}
16508 
16509 	/* Look for the optional class name. */
16510 	classtxt = next_token(lex, text);
16511 	if (classtxt != NULL) {
16512 		isc_textregion_t r;
16513 
16514 		/* Look for the optional view name. */
16515 		viewtxt = next_token(lex, text);
16516 
16517 		/*
16518 		 * If 'classtext' is not a valid class then it us a view name.
16519 		 */
16520 		r.base = classtxt;
16521 		r.length = strlen(classtxt);
16522 		result = dns_rdataclass_fromtext(&rdclass, &r);
16523 		if (result != ISC_R_SUCCESS) {
16524 			if (viewtxt != NULL) {
16525 				snprintf(msg, sizeof(msg), "unknown class '%s'",
16526 					 classtxt);
16527 				(void)putstr(text, msg);
16528 				goto cleanup;
16529 			}
16530 
16531 			viewtxt = classtxt;
16532 			classtxt = NULL;
16533 		}
16534 	}
16535 
16536 	isc_loopmgr_pause(named_g_loopmgr);
16537 
16538 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16539 	     view = ISC_LIST_NEXT(view, link))
16540 	{
16541 		dns_ttl_t stale_ttl = 0;
16542 		uint32_t stale_refresh = 0;
16543 		dns_db_t *db = NULL;
16544 
16545 		if (classtxt != NULL && rdclass != view->rdclass) {
16546 			continue;
16547 		}
16548 
16549 		if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0) {
16550 			continue;
16551 		}
16552 
16553 		if (!wantstatus) {
16554 			view->staleanswersok = staleanswersok;
16555 			found = true;
16556 			continue;
16557 		}
16558 
16559 		db = NULL;
16560 		dns_db_attach(view->cachedb, &db);
16561 		(void)dns_db_getservestalettl(db, &stale_ttl);
16562 		(void)dns_db_getservestalerefresh(db, &stale_refresh);
16563 		dns_db_detach(&db);
16564 		if (found) {
16565 			CHECK(putstr(text, "\n"));
16566 		}
16567 		CHECK(putstr(text, view->name));
16568 		CHECK(putstr(text, ": "));
16569 		switch (view->staleanswersok) {
16570 		case dns_stale_answer_yes:
16571 			if (stale_ttl > 0) {
16572 				CHECK(putstr(text, "stale cache "
16573 						   "enabled; stale "
16574 						   "answers enabled"));
16575 			} else {
16576 				CHECK(putstr(text, "stale cache disabled; "
16577 						   "stale "
16578 						   "answers unavailable"));
16579 			}
16580 			break;
16581 		case dns_stale_answer_no:
16582 			if (stale_ttl > 0) {
16583 				CHECK(putstr(text, "stale cache "
16584 						   "enabled; stale "
16585 						   "answers disabled"));
16586 			} else {
16587 				CHECK(putstr(text, "stale cache disabled; "
16588 						   "stale "
16589 						   "answers unavailable"));
16590 			}
16591 			break;
16592 		case dns_stale_answer_conf:
16593 			if (view->staleanswersenable && stale_ttl > 0) {
16594 				CHECK(putstr(text, "stale cache "
16595 						   "enabled; stale "
16596 						   "answers enabled"));
16597 			} else if (stale_ttl > 0) {
16598 				CHECK(putstr(text, "stale cache "
16599 						   "enabled; stale "
16600 						   "answers disabled"));
16601 			} else {
16602 				CHECK(putstr(text, "stale cache disabled; "
16603 						   "stale "
16604 						   "answers unavailable"));
16605 			}
16606 			break;
16607 		}
16608 		if (stale_ttl > 0) {
16609 			snprintf(msg, sizeof(msg),
16610 				 " (stale-answer-ttl=%u "
16611 				 "max-stale-ttl=%u "
16612 				 "stale-refresh-time=%u)",
16613 				 view->staleanswerttl, stale_ttl,
16614 				 stale_refresh);
16615 			CHECK(putstr(text, msg));
16616 		}
16617 		found = true;
16618 	}
16619 
16620 	if (!found) {
16621 		result = ISC_R_NOTFOUND;
16622 	}
16623 
16624 cleanup:
16625 	isc_loopmgr_resume(named_g_loopmgr);
16626 
16627 	if (isc_buffer_usedlength(*text) > 0) {
16628 		(void)putnull(text);
16629 	}
16630 
16631 	return result;
16632 }
16633 
16634 isc_result_t
16635 named_server_fetchlimit(named_server_t *server, isc_lex_t *lex,
16636 			isc_buffer_t **text) {
16637 	isc_result_t result = ISC_R_SUCCESS;
16638 	dns_view_t *view = NULL;
16639 	char *ptr = NULL, *viewname = NULL;
16640 	bool first = true;
16641 	dns_adb_t *adb = NULL;
16642 
16643 	REQUIRE(text != NULL);
16644 
16645 	/* Skip the command name. */
16646 	ptr = next_token(lex, text);
16647 	if (ptr == NULL) {
16648 		return ISC_R_UNEXPECTEDEND;
16649 	}
16650 
16651 	/* Look for the view name. */
16652 	viewname = next_token(lex, text);
16653 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16654 	     view = ISC_LIST_NEXT(view, link))
16655 	{
16656 		char tbuf[100];
16657 		unsigned int used;
16658 		uint32_t val;
16659 		int s;
16660 
16661 		if (view->rdclass != dns_rdataclass_in) {
16662 			continue;
16663 		}
16664 
16665 		if (viewname != NULL && strcasecmp(view->name, viewname) != 0) {
16666 			continue;
16667 		}
16668 
16669 		dns_view_getadb(view, &adb);
16670 		if (adb == NULL) {
16671 			continue;
16672 		}
16673 
16674 		if (!first) {
16675 			CHECK(putstr(text, "\n"));
16676 		}
16677 		CHECK(putstr(text, "Rate limited servers, view "));
16678 		CHECK(putstr(text, view->name));
16679 
16680 		dns_adb_getquota(adb, &val, NULL, NULL, NULL, NULL);
16681 		s = snprintf(tbuf, sizeof(tbuf),
16682 			     " (fetches-per-server %u):", val);
16683 		if (s < 0 || (unsigned int)s > sizeof(tbuf)) {
16684 			CHECK(ISC_R_NOSPACE);
16685 		}
16686 		first = false;
16687 		CHECK(putstr(text, tbuf));
16688 		used = isc_buffer_usedlength(*text);
16689 		CHECK(dns_adb_dumpquota(adb, text));
16690 		if (used == isc_buffer_usedlength(*text)) {
16691 			CHECK(putstr(text, "\n  None."));
16692 		}
16693 
16694 		CHECK(putstr(text, "\nRate limited servers, view "));
16695 		CHECK(putstr(text, view->name));
16696 		val = dns_resolver_getfetchesperzone(view->resolver);
16697 		s = snprintf(tbuf, sizeof(tbuf),
16698 			     " (fetches-per-zone %u):", val);
16699 		if (s < 0 || (unsigned int)s > sizeof(tbuf)) {
16700 			CHECK(ISC_R_NOSPACE);
16701 		}
16702 		CHECK(putstr(text, tbuf));
16703 		used = isc_buffer_usedlength(*text);
16704 		CHECK(dns_resolver_dumpquota(view->resolver, text));
16705 		if (used == isc_buffer_usedlength(*text)) {
16706 			CHECK(putstr(text, "\n  None."));
16707 		}
16708 		dns_adb_detach(&adb);
16709 	}
16710 cleanup:
16711 	if (adb != NULL) {
16712 		dns_adb_detach(&adb);
16713 	}
16714 	if (isc_buffer_usedlength(*text) > 0) {
16715 		(void)putnull(text);
16716 	}
16717 
16718 	return result;
16719 }
16720 
16721 isc_result_t
16722 named_server_skr(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
16723 	isc_result_t result = ISC_R_SUCCESS;
16724 	dns_zone_t *zone = NULL;
16725 	dns_kasp_t *kasp = NULL;
16726 	const char *ptr;
16727 	char skrfile[PATH_MAX];
16728 
16729 	/* Skip the command name. */
16730 	ptr = next_token(lex, text);
16731 	if (ptr == NULL) {
16732 		return ISC_R_UNEXPECTEDEND;
16733 	}
16734 
16735 	/* Find out what we are to do. */
16736 	ptr = next_token(lex, text);
16737 	if (ptr == NULL) {
16738 		return ISC_R_UNEXPECTEDEND;
16739 	}
16740 
16741 	if (strcasecmp(ptr, "-import") != 0) {
16742 		CHECK(DNS_R_SYNTAX);
16743 	}
16744 
16745 	ptr = next_token(lex, NULL);
16746 	if (ptr == NULL) {
16747 		return ISC_R_UNEXPECTEDEND;
16748 	}
16749 	(void)snprintf(skrfile, sizeof(skrfile), "%s", ptr);
16750 
16751 	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
16752 	if (zone == NULL) {
16753 		CHECK(ISC_R_UNEXPECTEDEND);
16754 	}
16755 	kasp = dns_zone_getkasp(zone);
16756 	if (kasp == NULL) {
16757 		CHECK(putstr(text, "zone does not have a dnssec-policy"));
16758 		CHECK(putnull(text));
16759 		goto cleanup;
16760 	}
16761 
16762 	if (!dns_kasp_offlineksk(kasp)) {
16763 		CHECK(putstr(text, "zone does not have offline-ksk enabled"));
16764 		CHECK(putnull(text));
16765 		goto cleanup;
16766 	}
16767 
16768 	result = dns_zone_import_skr(zone, skrfile);
16769 	if (result != ISC_R_SUCCESS) {
16770 		CHECK(putstr(text, "import failed: "));
16771 		CHECK(putstr(text, isc_result_totext(result)));
16772 		CHECK(putnull(text));
16773 	} else {
16774 		/* Schedule a rekey */
16775 		dns_zone_rekey(zone, false);
16776 	}
16777 
16778 cleanup:
16779 	if (zone != NULL) {
16780 		dns_zone_detach(&zone);
16781 	}
16782 
16783 	return result;
16784 }
16785