1/*	$NetBSD: server.c,v 1.21 2024/02/21 22:51:05 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16/*! \file */
17
18#include <ctype.h>
19#include <inttypes.h>
20#include <limits.h>
21#include <stdbool.h>
22#include <stdlib.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <unistd.h>
26
27#ifdef HAVE_DNSTAP
28#include <fstrm.h>
29#endif
30
31#include <isc/aes.h>
32#include <isc/app.h>
33#include <isc/attributes.h>
34#include <isc/base64.h>
35#include <isc/commandline.h>
36#include <isc/dir.h>
37#include <isc/file.h>
38#include <isc/hash.h>
39#include <isc/hex.h>
40#include <isc/hmac.h>
41#include <isc/httpd.h>
42#include <isc/lex.h>
43#include <isc/meminfo.h>
44#include <isc/netmgr.h>
45#include <isc/nonce.h>
46#include <isc/parseint.h>
47#include <isc/portset.h>
48#include <isc/print.h>
49#include <isc/refcount.h>
50#include <isc/resource.h>
51#include <isc/result.h>
52#include <isc/siphash.h>
53#include <isc/stat.h>
54#include <isc/stats.h>
55#include <isc/stdio.h>
56#include <isc/string.h>
57#include <isc/task.h>
58#include <isc/timer.h>
59#include <isc/util.h>
60
61#include <dns/adb.h>
62#include <dns/badcache.h>
63#include <dns/cache.h>
64#include <dns/catz.h>
65#include <dns/db.h>
66#include <dns/dispatch.h>
67#include <dns/dlz.h>
68#include <dns/dns64.h>
69#include <dns/dnsrps.h>
70#include <dns/dnssec.h>
71#include <dns/dyndb.h>
72#include <dns/events.h>
73#include <dns/fixedname.h>
74#include <dns/forward.h>
75#include <dns/geoip.h>
76#include <dns/journal.h>
77#include <dns/kasp.h>
78#include <dns/keymgr.h>
79#include <dns/keytable.h>
80#include <dns/keyvalues.h>
81#include <dns/master.h>
82#include <dns/masterdump.h>
83#include <dns/nsec3.h>
84#include <dns/nta.h>
85#include <dns/order.h>
86#include <dns/peer.h>
87#include <dns/private.h>
88#include <dns/rbt.h>
89#include <dns/rdataclass.h>
90#include <dns/rdatalist.h>
91#include <dns/rdataset.h>
92#include <dns/rdatastruct.h>
93#include <dns/resolver.h>
94#include <dns/rootns.h>
95#include <dns/rriterator.h>
96#include <dns/secalg.h>
97#include <dns/soa.h>
98#include <dns/stats.h>
99#include <dns/time.h>
100#include <dns/tkey.h>
101#include <dns/tsig.h>
102#include <dns/ttl.h>
103#include <dns/view.h>
104#include <dns/zone.h>
105#include <dns/zt.h>
106
107#include <dst/dst.h>
108
109#include <isccfg/grammar.h>
110#include <isccfg/kaspconf.h>
111#include <isccfg/namedconf.h>
112
113#include <ns/client.h>
114#include <ns/hooks.h>
115#include <ns/interfacemgr.h>
116#include <ns/listenlist.h>
117
118#include <bind9/check.h>
119
120#include <named/config.h>
121#include <named/control.h>
122#if defined(HAVE_GEOIP2)
123#include <named/geoip.h>
124#endif /* HAVE_GEOIP2 */
125#include <named/log.h>
126#include <named/logconf.h>
127#include <named/main.h>
128#include <named/os.h>
129#include <named/server.h>
130#include <named/statschannel.h>
131#include <named/tkeyconf.h>
132#include <named/transportconf.h>
133#include <named/tsigconf.h>
134#include <named/zoneconf.h>
135#ifdef HAVE_LIBSCF
136#include <stdlib.h>
137
138#include <named/smf_globals.h>
139#endif /* ifdef HAVE_LIBSCF */
140
141#ifdef HAVE_LMDB
142#include <lmdb.h>
143#define count_newzones	   count_newzones_db
144#define configure_newzones configure_newzones_db
145#define dumpzone	   dumpzone_db
146#else /* HAVE_LMDB */
147#define count_newzones	   count_newzones_file
148#define configure_newzones configure_newzones_file
149#define dumpzone	   dumpzone_file
150#endif /* HAVE_LMDB */
151
152#ifndef SIZE_MAX
153#define SIZE_MAX ((size_t)-1)
154#endif /* ifndef SIZE_MAX */
155
156#ifndef SIZE_AS_PERCENT
157#define SIZE_AS_PERCENT ((size_t)-2)
158#endif /* ifndef SIZE_AS_PERCENT */
159
160#ifdef TUNE_LARGE
161#define RESOLVER_NTASKS_PERCPU 32
162#else
163#define RESOLVER_NTASKS_PERCPU 8
164#endif /* TUNE_LARGE */
165
166/* RFC7828 defines timeout as 16-bit value specified in units of 100
167 * milliseconds, so the maximum and minimum advertised and keepalive
168 * timeouts are capped by the data type (it's ~109 minutes)
169 */
170#define MIN_INITIAL_TIMEOUT    UINT32_C(2500)	/* 2.5 seconds */
171#define MAX_INITIAL_TIMEOUT    UINT32_C(120000) /* 2 minutes */
172#define MIN_IDLE_TIMEOUT       UINT32_C(100)	/* 0.1 seconds */
173#define MAX_IDLE_TIMEOUT       UINT32_C(120000) /* 2 minutes */
174#define MIN_KEEPALIVE_TIMEOUT  UINT32_C(100)	/* 0.1 seconds */
175#define MAX_KEEPALIVE_TIMEOUT  UINT32_C(UINT16_MAX * 100)
176#define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */
177#define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100)
178
179/*%
180 * Check an operation for failure.  Assumes that the function
181 * using it has a 'result' variable and a 'cleanup' label.
182 */
183#define CHECK(op)                            \
184	do {                                 \
185		result = (op);               \
186		if (result != ISC_R_SUCCESS) \
187			goto cleanup;        \
188	} while (0)
189
190#define TCHECK(op)                               \
191	do {                                     \
192		tresult = (op);                  \
193		if (tresult != ISC_R_SUCCESS) {  \
194			isc_buffer_clear(*text); \
195			goto cleanup;            \
196		}                                \
197	} while (0)
198
199#define CHECKM(op, msg)                                                        \
200	do {                                                                   \
201		result = (op);                                                 \
202		if (result != ISC_R_SUCCESS) {                                 \
203			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
204				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
205				      "%s: %s", msg,                           \
206				      isc_result_totext(result));              \
207			goto cleanup;                                          \
208		}                                                              \
209	} while (0)
210
211#define CHECKMF(op, msg, file)                                                 \
212	do {                                                                   \
213		result = (op);                                                 \
214		if (result != ISC_R_SUCCESS) {                                 \
215			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
216				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
217				      "%s '%s': %s", msg, file,                \
218				      isc_result_totext(result));              \
219			goto cleanup;                                          \
220		}                                                              \
221	} while (0)
222
223#define CHECKFATAL(op, msg)                         \
224	do {                                        \
225		result = (op);                      \
226		if (result != ISC_R_SUCCESS)        \
227			fatal(server, msg, result); \
228	} while (0)
229
230/*%
231 * Maximum ADB size for views that share a cache.  Use this limit to suppress
232 * the total of memory footprint, which should be the main reason for sharing
233 * a cache.  Only effective when a finite max-cache-size is specified.
234 * This is currently defined to be 8MB.
235 */
236#define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
237
238struct named_dispatch {
239	isc_sockaddr_t addr;
240	unsigned int dispatchgen;
241	dns_dispatch_t *dispatch;
242	ISC_LINK(struct named_dispatch) link;
243};
244
245struct named_cache {
246	dns_cache_t *cache;
247	dns_view_t *primaryview;
248	bool needflush;
249	bool adbsizeadjusted;
250	dns_rdataclass_t rdclass;
251	ISC_LINK(named_cache_t) link;
252};
253
254struct dumpcontext {
255	isc_mem_t *mctx;
256	bool dumpcache;
257	bool dumpzones;
258	bool dumpadb;
259	bool dumpbad;
260	bool dumpexpired;
261	bool dumpfail;
262	FILE *fp;
263	ISC_LIST(struct viewlistentry) viewlist;
264	struct viewlistentry *view;
265	struct zonelistentry *zone;
266	dns_dumpctx_t *mdctx;
267	dns_db_t *db;
268	dns_db_t *cache;
269	isc_task_t *task;
270	dns_dbversion_t *version;
271};
272
273struct viewlistentry {
274	dns_view_t *view;
275	ISC_LINK(struct viewlistentry) link;
276	ISC_LIST(struct zonelistentry) zonelist;
277};
278
279struct zonelistentry {
280	dns_zone_t *zone;
281	ISC_LINK(struct zonelistentry) link;
282};
283
284/*%
285 * Configuration context to retain for each view that allows
286 * new zones to be added at runtime.
287 */
288typedef struct ns_cfgctx {
289	isc_mem_t *mctx;
290	cfg_parser_t *conf_parser;
291	cfg_parser_t *add_parser;
292	cfg_obj_t *config;
293	cfg_obj_t *vconfig;
294	cfg_obj_t *nzf_config;
295	cfg_aclconfctx_t *actx;
296} ns_cfgctx_t;
297
298/*%
299 * A function to write out added-zone configuration to the new_zone_file
300 * specified in 'view'. Maybe called by delete_zoneconf().
301 */
302typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
303
304/*%
305 * Holds state information for the initial zone loading process.
306 * Uses the isc_refcount structure to count the number of views
307 * with pending zone loads, dereferencing as each view finishes.
308 */
309typedef struct {
310	named_server_t *server;
311	bool reconfig;
312	isc_refcount_t refs;
313} ns_zoneload_t;
314
315typedef struct {
316	named_server_t *server;
317} catz_cb_data_t;
318
319typedef struct catz_chgzone_event {
320	ISC_EVENT_COMMON(struct catz_chgzone_event);
321	dns_catz_entry_t *entry;
322	dns_catz_zone_t *origin;
323	dns_view_t *view;
324	catz_cb_data_t *cbd;
325	bool mod;
326} catz_chgzone_event_t;
327
328typedef struct {
329	unsigned int magic;
330#define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
331	isc_buffer_t **text;
332	isc_result_t result;
333} ns_dzarg_t;
334
335/*
336 * These zones should not leak onto the Internet.
337 */
338const char *empty_zones[] = {
339	/* RFC 1918 */
340	"10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
341	"18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
342	"21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
343	"24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
344	"27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
345	"30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
346
347	/* RFC 6598 */
348	"64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
349	"67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
350	"70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
351	"73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
352	"76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
353	"79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
354	"82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
355	"85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
356	"88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
357	"91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
358	"94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
359	"97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
360	"100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA", "102.100.IN-ADDR.ARPA",
361	"103.100.IN-ADDR.ARPA", "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
362	"106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA", "108.100.IN-ADDR.ARPA",
363	"109.100.IN-ADDR.ARPA", "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
364	"112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA", "114.100.IN-ADDR.ARPA",
365	"115.100.IN-ADDR.ARPA", "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
366	"118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA", "120.100.IN-ADDR.ARPA",
367	"121.100.IN-ADDR.ARPA", "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
368	"124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA", "126.100.IN-ADDR.ARPA",
369	"127.100.IN-ADDR.ARPA",
370
371	/* RFC 5735 and RFC 5737 */
372	"0.IN-ADDR.ARPA",		/* THIS NETWORK */
373	"127.IN-ADDR.ARPA",		/* LOOPBACK */
374	"254.169.IN-ADDR.ARPA",		/* LINK LOCAL */
375	"2.0.192.IN-ADDR.ARPA",		/* TEST NET */
376	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
377	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
378	"255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
379
380	/* Local IPv6 Unicast Addresses */
381	"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."
382	"ARPA",
383	"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."
384	"ARPA",
385	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
386	"D.F.IP6.ARPA", "8.E.F.IP6.ARPA", /* LINK LOCAL */
387	"9.E.F.IP6.ARPA",		  /* LINK LOCAL */
388	"A.E.F.IP6.ARPA",		  /* LINK LOCAL */
389	"B.E.F.IP6.ARPA",		  /* LINK LOCAL */
390
391	/* Example Prefix, RFC 3849. */
392	"8.B.D.0.1.0.0.2.IP6.ARPA",
393
394	/* RFC 7534 */
395	"EMPTY.AS112.ARPA",
396
397	/* RFC 8375 */
398	"HOME.ARPA",
399
400	NULL
401};
402
403noreturn static void
404fatal(named_server_t *server, const char *msg, isc_result_t result);
405
406static void
407named_server_reload(isc_task_t *task, isc_event_t *event);
408
409#ifdef HAVE_LIBNGHTTP2
410static isc_result_t
411listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
412	       const ns_listen_tls_params_t *tls_params,
413	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
414	       isc_mem_t *mctx, ns_listenelt_t **target);
415#endif
416
417static isc_result_t
418listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
419		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
420		     isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target);
421
422static isc_result_t
423listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
424		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
425		      isc_tlsctx_cache_t *tlsctx_cache,
426		      ns_listenlist_t **target);
427
428static isc_result_t
429configure_forward(const cfg_obj_t *config, dns_view_t *view,
430		  const dns_name_t *origin, const cfg_obj_t *forwarders,
431		  const cfg_obj_t *forwardtype);
432
433static isc_result_t
434configure_alternates(const cfg_obj_t *config, dns_view_t *view,
435		     const cfg_obj_t *alternates);
436
437static isc_result_t
438configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
439	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
440	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
441	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
442	       bool modify);
443
444static void
445configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
446			     dns_view_t *view);
447
448static isc_result_t
449configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
450		   isc_mem_t *mctx, cfg_aclconfctx_t *actx);
451
452static isc_result_t
453add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
454
455static void
456end_reserved_dispatches(named_server_t *server, bool all);
457
458static void
459newzone_cfgctx_destroy(void **cfgp);
460
461static isc_result_t
462putstr(isc_buffer_t **b, const char *str);
463
464static isc_result_t
465putmem(isc_buffer_t **b, const char *str, size_t len);
466
467static isc_result_t
468putuint8(isc_buffer_t **b, uint8_t val);
469
470static isc_result_t
471putnull(isc_buffer_t **b);
472
473static int
474count_zones(const cfg_obj_t *conf);
475
476#ifdef HAVE_LMDB
477static isc_result_t
478migrate_nzf(dns_view_t *view);
479
480static isc_result_t
481nzd_writable(dns_view_t *view);
482
483static isc_result_t
484nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
485
486static isc_result_t
487nzd_env_reopen(dns_view_t *view);
488
489static void
490nzd_env_close(dns_view_t *view);
491
492static isc_result_t
493nzd_close(MDB_txn **txnp, bool commit);
494
495static isc_result_t
496nzd_count(dns_view_t *view, int *countp);
497#else  /* ifdef HAVE_LMDB */
498static isc_result_t
499nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
500#endif /* ifdef HAVE_LMDB */
501
502/*%
503 * Configure a single view ACL at '*aclp'.  Get its configuration from
504 * 'vconfig' (for per-view configuration) and maybe from 'config'
505 */
506static isc_result_t
507configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
508		   const cfg_obj_t *gconfig, const char *aclname,
509		   const char *acltuplename, cfg_aclconfctx_t *actx,
510		   isc_mem_t *mctx, dns_acl_t **aclp) {
511	isc_result_t result;
512	const cfg_obj_t *maps[4];
513	const cfg_obj_t *aclobj = NULL;
514	int i = 0;
515
516	if (*aclp != NULL) {
517		dns_acl_detach(aclp);
518	}
519	if (vconfig != NULL) {
520		maps[i++] = cfg_tuple_get(vconfig, "options");
521	}
522	if (config != NULL) {
523		const cfg_obj_t *options = NULL;
524		(void)cfg_map_get(config, "options", &options);
525		if (options != NULL) {
526			maps[i++] = options;
527		}
528	}
529	if (gconfig != NULL) {
530		const cfg_obj_t *options = NULL;
531		(void)cfg_map_get(gconfig, "options", &options);
532		if (options != NULL) {
533			maps[i++] = options;
534		}
535	}
536	maps[i] = NULL;
537
538	(void)named_config_get(maps, aclname, &aclobj);
539	if (aclobj == NULL) {
540		/*
541		 * No value available.	*aclp == NULL.
542		 */
543		return (ISC_R_SUCCESS);
544	}
545
546	if (acltuplename != NULL) {
547		/*
548		 * If the ACL is given in an optional tuple, retrieve it.
549		 * The parser should have ensured that a valid object be
550		 * returned.
551		 */
552		aclobj = cfg_tuple_get(aclobj, acltuplename);
553	}
554
555	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
556				    aclp);
557
558	return (result);
559}
560
561/*%
562 * Configure a sortlist at '*aclp'.  Essentially the same as
563 * configure_view_acl() except it calls cfg_acl_fromconfig with a
564 * nest_level value of 2.
565 */
566static isc_result_t
567configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
568			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
569			dns_acl_t **aclp) {
570	isc_result_t result;
571	const cfg_obj_t *maps[3];
572	const cfg_obj_t *aclobj = NULL;
573	int i = 0;
574
575	if (*aclp != NULL) {
576		dns_acl_detach(aclp);
577	}
578	if (vconfig != NULL) {
579		maps[i++] = cfg_tuple_get(vconfig, "options");
580	}
581	if (config != NULL) {
582		const cfg_obj_t *options = NULL;
583		(void)cfg_map_get(config, "options", &options);
584		if (options != NULL) {
585			maps[i++] = options;
586		}
587	}
588	maps[i] = NULL;
589
590	(void)named_config_get(maps, "sortlist", &aclobj);
591	if (aclobj == NULL) {
592		return (ISC_R_SUCCESS);
593	}
594
595	/*
596	 * Use a nest level of 3 for the "top level" of the sortlist;
597	 * this means each entry in the top three levels will be stored
598	 * as lists of separate, nested ACLs, rather than merged together
599	 * into IP tables as is usually done with ACLs.
600	 */
601	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
602				    aclp);
603
604	return (result);
605}
606
607static isc_result_t
608configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
609			 const char *confname, const char *conftuplename,
610			 isc_mem_t *mctx, dns_rbt_t **rbtp) {
611	isc_result_t result;
612	const cfg_obj_t *maps[3];
613	const cfg_obj_t *obj = NULL;
614	const cfg_listelt_t *element;
615	int i = 0;
616	dns_fixedname_t fixed;
617	dns_name_t *name;
618	isc_buffer_t b;
619	const char *str;
620	const cfg_obj_t *nameobj;
621
622	if (*rbtp != NULL) {
623		dns_rbt_destroy(rbtp);
624	}
625	if (vconfig != NULL) {
626		maps[i++] = cfg_tuple_get(vconfig, "options");
627	}
628	if (config != NULL) {
629		const cfg_obj_t *options = NULL;
630		(void)cfg_map_get(config, "options", &options);
631		if (options != NULL) {
632			maps[i++] = options;
633		}
634	}
635	maps[i] = NULL;
636
637	(void)named_config_get(maps, confname, &obj);
638	if (obj == NULL) {
639		/*
640		 * No value available.	*rbtp == NULL.
641		 */
642		return (ISC_R_SUCCESS);
643	}
644
645	if (conftuplename != NULL) {
646		obj = cfg_tuple_get(obj, conftuplename);
647		if (cfg_obj_isvoid(obj)) {
648			return (ISC_R_SUCCESS);
649		}
650	}
651
652	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
653	if (result != ISC_R_SUCCESS) {
654		return (result);
655	}
656
657	name = dns_fixedname_initname(&fixed);
658	for (element = cfg_list_first(obj); element != NULL;
659	     element = cfg_list_next(element))
660	{
661		nameobj = cfg_listelt_value(element);
662		str = cfg_obj_asstring(nameobj);
663		isc_buffer_constinit(&b, str, strlen(str));
664		isc_buffer_add(&b, strlen(str));
665		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
666		/*
667		 * We don't need the node data, but need to set dummy data to
668		 * avoid a partial match with an empty node.  For example, if
669		 * we have foo.example.com and bar.example.com, we'd get a match
670		 * for baz.example.com, which is not the expected result.
671		 * We simply use (void *)1 as the dummy data.
672		 */
673		result = dns_rbt_addname(*rbtp, name, (void *)1);
674		if (result != ISC_R_SUCCESS) {
675			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
676				    "failed to add %s for %s: %s", str,
677				    confname, isc_result_totext(result));
678			goto cleanup;
679		}
680	}
681
682	return (result);
683
684cleanup:
685	dns_rbt_destroy(rbtp);
686	return (result);
687}
688
689static isc_result_t
690ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
691	      unsigned char *digest, dns_rdata_ds_t *ds) {
692	isc_result_t result;
693	dns_rdata_dnskey_t keystruct;
694	dns_rdata_t rdata = DNS_RDATA_INIT;
695	uint32_t rdata1, rdata2, rdata3;
696	const char *datastr = NULL, *namestr = NULL;
697	unsigned char data[4096];
698	isc_buffer_t databuf;
699	unsigned char rrdata[4096];
700	isc_buffer_t rrdatabuf;
701	isc_region_t r;
702	dns_fixedname_t fname;
703	dns_name_t *name = NULL;
704	isc_buffer_t namebuf;
705	const char *atstr = NULL;
706	enum {
707		INIT_DNSKEY,
708		STATIC_DNSKEY,
709		INIT_DS,
710		STATIC_DS,
711		TRUSTED
712	} anchortype;
713
714	REQUIRE(namestrp != NULL && *namestrp == NULL);
715	REQUIRE(ds != NULL);
716
717	/* if DNSKEY, flags; if DS, key tag */
718	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
719
720	/* if DNSKEY, protocol; if DS, algorithm */
721	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
722
723	/* if DNSKEY, algorithm; if DS, digest type */
724	rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3"));
725
726	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
727	*namestrp = namestr;
728
729	name = dns_fixedname_initname(&fname);
730	isc_buffer_constinit(&namebuf, namestr, strlen(namestr));
731	isc_buffer_add(&namebuf, strlen(namestr));
732	CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL));
733
734	if (*initialp) {
735		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
736
737		if (strcasecmp(atstr, "static-key") == 0) {
738			*initialp = false;
739			anchortype = STATIC_DNSKEY;
740		} else if (strcasecmp(atstr, "static-ds") == 0) {
741			*initialp = false;
742			anchortype = STATIC_DS;
743		} else if (strcasecmp(atstr, "initial-key") == 0) {
744			anchortype = INIT_DNSKEY;
745		} else if (strcasecmp(atstr, "initial-ds") == 0) {
746			anchortype = INIT_DS;
747		} else {
748			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
749				    "key '%s': "
750				    "invalid initialization method '%s'",
751				    namestr, atstr);
752			result = ISC_R_FAILURE;
753			goto cleanup;
754		}
755	} else {
756		anchortype = TRUSTED;
757	}
758
759	isc_buffer_init(&databuf, data, sizeof(data));
760	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
761
762	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
763				.common.rdtype = dns_rdatatype_ds };
764
765	ISC_LINK_INIT(&ds->common, link);
766
767	switch (anchortype) {
768	case INIT_DNSKEY:
769	case STATIC_DNSKEY:
770	case TRUSTED:
771		/*
772		 * This function should never be reached for view
773		 * class other than IN
774		 */
775		keystruct.common.rdclass = dns_rdataclass_in;
776		keystruct.common.rdtype = dns_rdatatype_dnskey;
777
778		/*
779		 * The key data in keystruct is not dynamically allocated.
780		 */
781		keystruct.mctx = NULL;
782
783		ISC_LINK_INIT(&keystruct.common, link);
784
785		if (rdata1 > 0xffff) {
786			CHECKM(ISC_R_RANGE, "key flags");
787		}
788		if (rdata1 & DNS_KEYFLAG_REVOKE) {
789			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
790		}
791		if (rdata2 > 0xff) {
792			CHECKM(ISC_R_RANGE, "key protocol");
793		}
794		if (rdata3 > 0xff) {
795			CHECKM(ISC_R_RANGE, "key algorithm");
796		}
797
798		keystruct.flags = (uint16_t)rdata1;
799		keystruct.protocol = (uint8_t)rdata2;
800		keystruct.algorithm = (uint8_t)rdata3;
801
802		if (!dst_algorithm_supported(keystruct.algorithm)) {
803			CHECK(DST_R_UNSUPPORTEDALG);
804		}
805
806		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
807		CHECK(isc_base64_decodestring(datastr, &databuf));
808		isc_buffer_usedregion(&databuf, &r);
809		keystruct.datalen = r.length;
810		keystruct.data = r.base;
811
812		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
813					   keystruct.common.rdtype, &keystruct,
814					   &rrdatabuf));
815		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
816					  digest, ds));
817		break;
818
819	case INIT_DS:
820	case STATIC_DS:
821		if (rdata1 > 0xffff) {
822			CHECKM(ISC_R_RANGE, "key tag");
823		}
824		if (rdata2 > 0xff) {
825			CHECKM(ISC_R_RANGE, "key algorithm");
826		}
827		if (rdata3 > 0xff) {
828			CHECKM(ISC_R_RANGE, "digest type");
829		}
830
831		ds->key_tag = (uint16_t)rdata1;
832		ds->algorithm = (uint8_t)rdata2;
833		ds->digest_type = (uint8_t)rdata3;
834
835		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
836		CHECK(isc_hex_decodestring(datastr, &databuf));
837		isc_buffer_usedregion(&databuf, &r);
838
839		switch (ds->digest_type) {
840		case DNS_DSDIGEST_SHA1:
841			if (r.length != ISC_SHA1_DIGESTLENGTH) {
842				CHECK(ISC_R_UNEXPECTEDEND);
843			}
844			break;
845		case DNS_DSDIGEST_SHA256:
846			if (r.length != ISC_SHA256_DIGESTLENGTH) {
847				CHECK(ISC_R_UNEXPECTEDEND);
848			}
849			break;
850		case DNS_DSDIGEST_SHA384:
851			if (r.length != ISC_SHA384_DIGESTLENGTH) {
852				CHECK(ISC_R_UNEXPECTEDEND);
853			}
854			break;
855		default:
856			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
857				    "key '%s': "
858				    "unknown ds digest type %u",
859				    namestr, ds->digest_type);
860			result = ISC_R_FAILURE;
861			goto cleanup;
862			break;
863		}
864
865		ds->length = r.length;
866		ds->digest = digest;
867		memmove(ds->digest, r.base, r.length);
868
869		break;
870
871	default:
872		UNREACHABLE();
873	}
874
875	return (ISC_R_SUCCESS);
876
877cleanup:
878	return (result);
879}
880
881static void
882sfd_add(const dns_name_t *name, void *arg) {
883	if (arg != NULL) {
884		dns_view_sfd_add(arg, name);
885	}
886}
887
888/*%
889 * Parse 'key' in the context of view configuration 'vconfig'.  If successful,
890 * add the key to 'secroots' if both of the following conditions are true:
891 *
892 *   - 'keyname_match' is NULL or it matches the owner name of 'key',
893 *   - support for the algorithm used by 'key' is not disabled by 'resolver'
894 *     for the owner name of 'key'.
895 *
896 * 'managed' is true for managed keys and false for trusted keys.  'mctx' is
897 * the memory context to use for allocating memory.
898 */
899static isc_result_t
900process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
901	    const dns_name_t *keyname_match, dns_view_t *view, bool managed) {
902	dns_fixedname_t fkeyname;
903	dns_name_t *keyname = NULL;
904	const char *namestr = NULL;
905	dns_rdata_ds_t ds;
906	isc_result_t result;
907	bool initializing = managed;
908	unsigned char digest[ISC_MAX_MD_SIZE];
909	isc_buffer_t b;
910
911	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
912
913	switch (result) {
914	case ISC_R_SUCCESS:
915		/*
916		 * Trust anchor was parsed correctly.
917		 */
918		isc_buffer_constinit(&b, namestr, strlen(namestr));
919		isc_buffer_add(&b, strlen(namestr));
920		keyname = dns_fixedname_initname(&fkeyname);
921		result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
922		if (result != ISC_R_SUCCESS) {
923			return (result);
924		}
925		break;
926	case DST_R_UNSUPPORTEDALG:
927	case DST_R_BADKEYTYPE:
928		/*
929		 * Key was parsed correctly, but it cannot be used; this is not
930		 * a fatal error - log a warning about this key being ignored,
931		 * but do not prevent any further ones from being processed.
932		 */
933		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
934			    "ignoring %s for '%s': %s",
935			    initializing ? "initial-key" : "static-key",
936			    namestr, isc_result_totext(result));
937		return (ISC_R_SUCCESS);
938	case DST_R_NOCRYPTO:
939		/*
940		 * Crypto support is not available.
941		 */
942		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
943			    "ignoring %s for '%s': no crypto support",
944			    initializing ? "initial-key" : "static-key",
945			    namestr);
946		return (result);
947	default:
948		/*
949		 * Something unexpected happened; we have no choice but to
950		 * indicate an error so that the configuration loading process
951		 * is interrupted.
952		 */
953		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
954			    "configuring %s for '%s': %s",
955			    initializing ? "initial-key" : "static-key",
956			    namestr, isc_result_totext(result));
957		return (ISC_R_FAILURE);
958	}
959
960	/*
961	 * If the caller requested to only load keys for a specific name and
962	 * the owner name of this key does not match the requested name, do not
963	 * load it.
964	 */
965	if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) {
966		goto done;
967	}
968
969	/*
970	 * Ensure that 'resolver' allows using the algorithm of this key for
971	 * its owner name.  If it does not, do not load the key and log a
972	 * warning, but do not prevent further keys from being processed.
973	 */
974	if (!dns_resolver_algorithm_supported(view->resolver, keyname,
975					      ds.algorithm))
976	{
977		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
978			    "ignoring %s for '%s': algorithm is disabled",
979			    initializing ? "initial-key" : "static-key",
980			    namestr);
981		goto done;
982	}
983
984	/*
985	 * Add the key to 'secroots'.  Keys from a "trust-anchors" or
986	 * "managed-keys" statement may be either static or initializing
987	 * keys. If it's not initializing, we don't want to treat it as
988	 * managed, so we use 'initializing' twice here, for both the
989	 * 'managed' and 'initializing' arguments to dns_keytable_add().
990	 */
991	result = dns_keytable_add(secroots, initializing, initializing, keyname,
992				  &ds, sfd_add, view);
993
994done:
995	return (result);
996}
997
998/*
999 * Load keys from configuration into key table. If 'keyname' is specified,
1000 * only load keys matching that name. If 'managed' is true, load the key as
1001 * an initializing key.
1002 */
1003static isc_result_t
1004load_view_keys(const cfg_obj_t *keys, dns_view_t *view, bool managed,
1005	       const dns_name_t *keyname) {
1006	const cfg_listelt_t *elt, *elt2;
1007	const cfg_obj_t *keylist;
1008	isc_result_t result;
1009	dns_keytable_t *secroots = NULL;
1010
1011	CHECK(dns_view_getsecroots(view, &secroots));
1012
1013	for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt))
1014	{
1015		keylist = cfg_listelt_value(elt);
1016
1017		for (elt2 = cfg_list_first(keylist); elt2 != NULL;
1018		     elt2 = cfg_list_next(elt2))
1019		{
1020			CHECK(process_key(cfg_listelt_value(elt2), secroots,
1021					  keyname, view, managed));
1022		}
1023	}
1024
1025cleanup:
1026	if (secroots != NULL) {
1027		dns_keytable_detach(&secroots);
1028	}
1029	if (result == DST_R_NOCRYPTO) {
1030		result = ISC_R_SUCCESS;
1031	}
1032	return (result);
1033}
1034
1035/*%
1036 * Check whether a key has been successfully loaded.
1037 */
1038static bool
1039keyloaded(dns_view_t *view, const dns_name_t *name) {
1040	isc_result_t result;
1041	dns_keytable_t *secroots = NULL;
1042	dns_keynode_t *keynode = NULL;
1043
1044	result = dns_view_getsecroots(view, &secroots);
1045	if (result != ISC_R_SUCCESS) {
1046		return (false);
1047	}
1048
1049	result = dns_keytable_find(secroots, name, &keynode);
1050
1051	if (keynode != NULL) {
1052		dns_keytable_detachkeynode(secroots, &keynode);
1053	}
1054	if (secroots != NULL) {
1055		dns_keytable_detach(&secroots);
1056	}
1057
1058	return (result == ISC_R_SUCCESS);
1059}
1060
1061/*%
1062 * Configure DNSSEC keys for a view.
1063 *
1064 * The per-view configuration values and the server-global defaults are read
1065 * from 'vconfig' and 'config'.
1066 */
1067static isc_result_t
1068configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
1069			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
1070			  bool auto_root, isc_mem_t *mctx) {
1071	isc_result_t result = ISC_R_SUCCESS;
1072	const cfg_obj_t *view_keys = NULL;
1073	const cfg_obj_t *global_keys = NULL;
1074	const cfg_obj_t *view_managed_keys = NULL;
1075	const cfg_obj_t *view_trust_anchors = NULL;
1076	const cfg_obj_t *global_managed_keys = NULL;
1077	const cfg_obj_t *global_trust_anchors = NULL;
1078	const cfg_obj_t *maps[4];
1079	const cfg_obj_t *voptions = NULL;
1080	const cfg_obj_t *options = NULL;
1081	const cfg_obj_t *obj = NULL;
1082	const char *directory;
1083	int i = 0;
1084
1085	/* We don't need trust anchors for the _bind view */
1086	if (strcmp(view->name, "_bind") == 0 &&
1087	    view->rdclass == dns_rdataclass_chaos)
1088	{
1089		return (ISC_R_SUCCESS);
1090	}
1091
1092	if (vconfig != NULL) {
1093		voptions = cfg_tuple_get(vconfig, "options");
1094		if (voptions != NULL) {
1095			(void)cfg_map_get(voptions, "trusted-keys", &view_keys);
1096
1097			/* managed-keys and trust-anchors are synonyms. */
1098			(void)cfg_map_get(voptions, "managed-keys",
1099					  &view_managed_keys);
1100			(void)cfg_map_get(voptions, "trust-anchors",
1101					  &view_trust_anchors);
1102
1103			maps[i++] = voptions;
1104		}
1105	}
1106
1107	if (config != NULL) {
1108		(void)cfg_map_get(config, "trusted-keys", &global_keys);
1109
1110		/* managed-keys and trust-anchors are synonyms. */
1111		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
1112		(void)cfg_map_get(config, "trust-anchors",
1113				  &global_trust_anchors);
1114
1115		(void)cfg_map_get(config, "options", &options);
1116		if (options != NULL) {
1117			maps[i++] = options;
1118		}
1119	}
1120
1121	maps[i++] = named_g_defaults;
1122	maps[i] = NULL;
1123
1124	result = dns_view_initsecroots(view, mctx);
1125	if (result != ISC_R_SUCCESS) {
1126		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1127			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1128			      "couldn't create keytable");
1129		return (ISC_R_UNEXPECTED);
1130	}
1131
1132	result = dns_view_initntatable(view, named_g_taskmgr, named_g_timermgr);
1133	if (result != ISC_R_SUCCESS) {
1134		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1135			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1136			      "couldn't create NTA table");
1137		return (ISC_R_UNEXPECTED);
1138	}
1139
1140	if (auto_root && view->rdclass == dns_rdataclass_in) {
1141		const cfg_obj_t *builtin_keys = NULL;
1142
1143		/*
1144		 * If bind.keys exists and is populated, it overrides
1145		 * the trust-anchors clause hard-coded in named_g_config.
1146		 */
1147		if (bindkeys != NULL) {
1148			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1149				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1150				      "obtaining root key for view %s "
1151				      "from '%s'",
1152				      view->name, named_g_server->bindkeysfile);
1153
1154			(void)cfg_map_get(bindkeys, "trust-anchors",
1155					  &builtin_keys);
1156
1157			if (builtin_keys == NULL) {
1158				isc_log_write(
1159					named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1160					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
1161					"dnssec-validation auto: "
1162					"WARNING: root zone key "
1163					"not found");
1164			}
1165		}
1166
1167		if (builtin_keys == NULL) {
1168			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1169				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1170				      "using built-in root key for view %s",
1171				      view->name);
1172
1173			(void)cfg_map_get(named_g_config, "trust-anchors",
1174					  &builtin_keys);
1175		}
1176
1177		if (builtin_keys != NULL) {
1178			CHECK(load_view_keys(builtin_keys, view, true,
1179					     dns_rootname));
1180		}
1181
1182		if (!keyloaded(view, dns_rootname)) {
1183			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1184				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1185				      "root key not loaded");
1186			result = ISC_R_FAILURE;
1187			goto cleanup;
1188		}
1189	}
1190
1191	if (view->rdclass == dns_rdataclass_in) {
1192		CHECK(load_view_keys(view_keys, view, false, NULL));
1193		CHECK(load_view_keys(view_trust_anchors, view, true, NULL));
1194		CHECK(load_view_keys(view_managed_keys, view, true, NULL));
1195
1196		CHECK(load_view_keys(global_keys, view, false, NULL));
1197		CHECK(load_view_keys(global_trust_anchors, view, true, NULL));
1198		CHECK(load_view_keys(global_managed_keys, view, true, NULL));
1199	}
1200
1201	/*
1202	 * Add key zone for managed keys.
1203	 */
1204	obj = NULL;
1205	(void)named_config_get(maps, "managed-keys-directory", &obj);
1206	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
1207	if (directory != NULL) {
1208		result = isc_file_isdirectory(directory);
1209	}
1210	if (result != ISC_R_SUCCESS) {
1211		isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1212			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1213			      "invalid managed-keys-directory %s: %s",
1214			      directory, isc_result_totext(result));
1215		goto cleanup;
1216	} else if (directory != NULL) {
1217		if (!isc_file_isdirwritable(directory)) {
1218			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1219				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1220				      "managed-keys-directory '%s' "
1221				      "is not writable",
1222				      directory);
1223			result = ISC_R_NOPERM;
1224			goto cleanup;
1225		}
1226	}
1227
1228	CHECK(add_keydata_zone(view, directory, named_g_mctx));
1229
1230cleanup:
1231	return (result);
1232}
1233
1234static isc_result_t
1235mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
1236	const cfg_listelt_t *element;
1237	const cfg_obj_t *obj;
1238	const char *str;
1239	dns_fixedname_t fixed;
1240	dns_name_t *name;
1241	bool value;
1242	isc_result_t result;
1243	isc_buffer_t b;
1244
1245	name = dns_fixedname_initname(&fixed);
1246	for (element = cfg_list_first(mbs); element != NULL;
1247	     element = cfg_list_next(element))
1248	{
1249		obj = cfg_listelt_value(element);
1250		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
1251		isc_buffer_constinit(&b, str, strlen(str));
1252		isc_buffer_add(&b, strlen(str));
1253		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1254		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
1255		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
1256	}
1257
1258	result = ISC_R_SUCCESS;
1259
1260cleanup:
1261	return (result);
1262}
1263
1264/*%
1265 * Get a dispatch appropriate for the resolver of a given view.
1266 */
1267static isc_result_t
1268get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
1269			      dns_dispatch_t **dispatchp, bool is_firstview) {
1270	isc_result_t result = ISC_R_FAILURE;
1271	dns_dispatch_t *disp = NULL;
1272	isc_sockaddr_t sa;
1273	const cfg_obj_t *obj = NULL;
1274
1275	switch (af) {
1276	case AF_INET:
1277		result = named_config_get(maps, "query-source", &obj);
1278		INSIST(result == ISC_R_SUCCESS);
1279		break;
1280	case AF_INET6:
1281		result = named_config_get(maps, "query-source-v6", &obj);
1282		INSIST(result == ISC_R_SUCCESS);
1283		break;
1284	default:
1285		UNREACHABLE();
1286	}
1287
1288	sa = *(cfg_obj_assockaddr(obj));
1289	INSIST(isc_sockaddr_pf(&sa) == af);
1290
1291	/*
1292	 * If we don't support this address family, we're done!
1293	 */
1294	switch (af) {
1295	case AF_INET:
1296		result = isc_net_probeipv4();
1297		break;
1298	case AF_INET6:
1299		result = isc_net_probeipv6();
1300		break;
1301	default:
1302		UNREACHABLE();
1303	}
1304	if (result != ISC_R_SUCCESS) {
1305		return (ISC_R_SUCCESS);
1306	}
1307
1308	/*
1309	 * Try to find a dispatcher that we can share.
1310	 */
1311	if (isc_sockaddr_getport(&sa) != 0) {
1312		INSIST(obj != NULL);
1313		if (is_firstview) {
1314			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
1315				    "using specific query-source port "
1316				    "suppresses port randomization and can be "
1317				    "insecure.");
1318		}
1319	}
1320
1321	result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, &disp);
1322	if (result != ISC_R_SUCCESS) {
1323		isc_sockaddr_t any;
1324		char buf[ISC_SOCKADDR_FORMATSIZE];
1325
1326		switch (af) {
1327		case AF_INET:
1328			isc_sockaddr_any(&any);
1329			break;
1330		case AF_INET6:
1331			isc_sockaddr_any6(&any);
1332			break;
1333		}
1334		if (isc_sockaddr_equal(&sa, &any)) {
1335			return (ISC_R_SUCCESS);
1336		}
1337		isc_sockaddr_format(&sa, buf, sizeof(buf));
1338		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1339			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1340			      "could not get query source dispatcher (%s)",
1341			      buf);
1342		return (result);
1343	}
1344
1345	*dispatchp = disp;
1346
1347	return (ISC_R_SUCCESS);
1348}
1349
1350static isc_result_t
1351configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1352	dns_rdataclass_t rdclass;
1353	dns_rdatatype_t rdtype;
1354	const cfg_obj_t *obj;
1355	dns_fixedname_t fixed;
1356	unsigned int mode = 0;
1357	const char *str;
1358	isc_buffer_t b;
1359	isc_result_t result;
1360	bool addroot;
1361
1362	result = named_config_getclass(cfg_tuple_get(ent, "class"),
1363				       dns_rdataclass_any, &rdclass);
1364	if (result != ISC_R_SUCCESS) {
1365		return (result);
1366	}
1367
1368	result = named_config_gettype(cfg_tuple_get(ent, "type"),
1369				      dns_rdatatype_any, &rdtype);
1370	if (result != ISC_R_SUCCESS) {
1371		return (result);
1372	}
1373
1374	obj = cfg_tuple_get(ent, "name");
1375	if (cfg_obj_isstring(obj)) {
1376		str = cfg_obj_asstring(obj);
1377	} else {
1378		str = "*";
1379	}
1380	addroot = (strcmp(str, "*") == 0);
1381	isc_buffer_constinit(&b, str, strlen(str));
1382	isc_buffer_add(&b, strlen(str));
1383	dns_fixedname_init(&fixed);
1384	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, dns_rootname,
1385				   0, NULL);
1386	if (result != ISC_R_SUCCESS) {
1387		return (result);
1388	}
1389
1390	obj = cfg_tuple_get(ent, "ordering");
1391	INSIST(cfg_obj_isstring(obj));
1392	str = cfg_obj_asstring(obj);
1393	if (!strcasecmp(str, "fixed")) {
1394#if DNS_RDATASET_FIXED
1395		mode = DNS_RDATASETATTR_FIXEDORDER;
1396#else  /* if DNS_RDATASET_FIXED */
1397		mode = DNS_RDATASETATTR_CYCLIC;
1398#endif /* DNS_RDATASET_FIXED */
1399	} else if (!strcasecmp(str, "random")) {
1400		mode = DNS_RDATASETATTR_RANDOMIZE;
1401	} else if (!strcasecmp(str, "cyclic")) {
1402		mode = DNS_RDATASETATTR_CYCLIC;
1403	} else if (!strcasecmp(str, "none")) {
1404		mode = DNS_RDATASETATTR_NONE;
1405	} else {
1406		UNREACHABLE();
1407	}
1408
1409	/*
1410	 * "*" should match everything including the root (BIND 8 compat).
1411	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1412	 * explicit entry for "." when the name is "*".
1413	 */
1414	if (addroot) {
1415		result = dns_order_add(order, dns_rootname, rdtype, rdclass,
1416				       mode);
1417		if (result != ISC_R_SUCCESS) {
1418			return (result);
1419		}
1420	}
1421
1422	return (dns_order_add(order, dns_fixedname_name(&fixed), rdtype,
1423			      rdclass, mode));
1424}
1425
1426static isc_result_t
1427configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1428	isc_netaddr_t na;
1429	dns_peer_t *peer;
1430	const cfg_obj_t *obj;
1431	const char *str;
1432	isc_result_t result;
1433	unsigned int prefixlen;
1434
1435	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1436
1437	peer = NULL;
1438	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1439	if (result != ISC_R_SUCCESS) {
1440		return (result);
1441	}
1442
1443	obj = NULL;
1444	(void)cfg_map_get(cpeer, "bogus", &obj);
1445	if (obj != NULL) {
1446		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1447	}
1448
1449	obj = NULL;
1450	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1451	if (obj != NULL) {
1452		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1453	}
1454
1455	obj = NULL;
1456	(void)cfg_map_get(cpeer, "request-expire", &obj);
1457	if (obj != NULL) {
1458		CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
1459	}
1460
1461	obj = NULL;
1462	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
1463	if (obj != NULL) {
1464		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1465	}
1466
1467	obj = NULL;
1468	(void)cfg_map_get(cpeer, "request-nsid", &obj);
1469	if (obj != NULL) {
1470		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1471	}
1472
1473	obj = NULL;
1474	(void)cfg_map_get(cpeer, "send-cookie", &obj);
1475	if (obj != NULL) {
1476		CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj)));
1477	}
1478
1479	obj = NULL;
1480	(void)cfg_map_get(cpeer, "edns", &obj);
1481	if (obj != NULL) {
1482		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1483	}
1484
1485	obj = NULL;
1486	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1487	if (obj != NULL) {
1488		uint32_t udpsize = cfg_obj_asuint32(obj);
1489		if (udpsize < 512U) {
1490			udpsize = 512U;
1491		}
1492		if (udpsize > 4096U) {
1493			udpsize = 4096U;
1494		}
1495		CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize));
1496	}
1497
1498	obj = NULL;
1499	(void)cfg_map_get(cpeer, "edns-version", &obj);
1500	if (obj != NULL) {
1501		uint32_t ednsversion = cfg_obj_asuint32(obj);
1502		if (ednsversion > 255U) {
1503			ednsversion = 255U;
1504		}
1505		CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion));
1506	}
1507
1508	obj = NULL;
1509	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
1510	if (obj != NULL) {
1511		uint32_t udpsize = cfg_obj_asuint32(obj);
1512		if (udpsize < 512U) {
1513			udpsize = 512U;
1514		}
1515		if (udpsize > 4096U) {
1516			udpsize = 4096U;
1517		}
1518		CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize));
1519	}
1520
1521	obj = NULL;
1522	(void)cfg_map_get(cpeer, "padding", &obj);
1523	if (obj != NULL) {
1524		uint32_t padding = cfg_obj_asuint32(obj);
1525		if (padding > 512U) {
1526			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
1527				    "server padding value cannot "
1528				    "exceed 512: lowering");
1529			padding = 512U;
1530		}
1531		CHECK(dns_peer_setpadding(peer, (uint16_t)padding));
1532	}
1533
1534	obj = NULL;
1535	(void)cfg_map_get(cpeer, "tcp-only", &obj);
1536	if (obj != NULL) {
1537		CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
1538	}
1539
1540	obj = NULL;
1541	(void)cfg_map_get(cpeer, "tcp-keepalive", &obj);
1542	if (obj != NULL) {
1543		CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj)));
1544	}
1545
1546	obj = NULL;
1547	(void)cfg_map_get(cpeer, "transfers", &obj);
1548	if (obj != NULL) {
1549		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1550	}
1551
1552	obj = NULL;
1553	(void)cfg_map_get(cpeer, "transfer-format", &obj);
1554	if (obj != NULL) {
1555		str = cfg_obj_asstring(obj);
1556		if (strcasecmp(str, "many-answers") == 0) {
1557			CHECK(dns_peer_settransferformat(peer,
1558							 dns_many_answers));
1559		} else if (strcasecmp(str, "one-answer") == 0) {
1560			CHECK(dns_peer_settransferformat(peer, dns_one_answer));
1561		} else {
1562			UNREACHABLE();
1563		}
1564	}
1565
1566	obj = NULL;
1567	(void)cfg_map_get(cpeer, "keys", &obj);
1568	if (obj != NULL) {
1569		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1570		if (result != ISC_R_SUCCESS) {
1571			goto cleanup;
1572		}
1573	}
1574
1575	obj = NULL;
1576	if (na.family == AF_INET) {
1577		(void)cfg_map_get(cpeer, "transfer-source", &obj);
1578	} else {
1579		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1580	}
1581	if (obj != NULL) {
1582		result = dns_peer_settransfersource(peer,
1583						    cfg_obj_assockaddr(obj));
1584		if (result != ISC_R_SUCCESS) {
1585			goto cleanup;
1586		}
1587		named_add_reserved_dispatch(named_g_server,
1588					    cfg_obj_assockaddr(obj));
1589	}
1590
1591	obj = NULL;
1592	if (na.family == AF_INET) {
1593		(void)cfg_map_get(cpeer, "notify-source", &obj);
1594	} else {
1595		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1596	}
1597	if (obj != NULL) {
1598		result = dns_peer_setnotifysource(peer,
1599						  cfg_obj_assockaddr(obj));
1600		if (result != ISC_R_SUCCESS) {
1601			goto cleanup;
1602		}
1603		named_add_reserved_dispatch(named_g_server,
1604					    cfg_obj_assockaddr(obj));
1605	}
1606
1607	obj = NULL;
1608	if (na.family == AF_INET) {
1609		(void)cfg_map_get(cpeer, "query-source", &obj);
1610	} else {
1611		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
1612	}
1613	if (obj != NULL) {
1614		result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj));
1615		if (result != ISC_R_SUCCESS) {
1616			goto cleanup;
1617		}
1618		named_add_reserved_dispatch(named_g_server,
1619					    cfg_obj_assockaddr(obj));
1620	}
1621
1622	*peerp = peer;
1623	return (ISC_R_SUCCESS);
1624
1625cleanup:
1626	dns_peer_detach(&peer);
1627	return (result);
1628}
1629
1630static isc_result_t
1631configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
1632		const dns_dyndbctx_t *dctx) {
1633	isc_result_t result = ISC_R_SUCCESS;
1634	const cfg_obj_t *obj;
1635	const char *name, *library;
1636
1637	/* Get the name of the dyndb instance and the library path . */
1638	name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name"));
1639	library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library"));
1640
1641	obj = cfg_tuple_get(dyndb, "parameters");
1642	if (obj != NULL) {
1643		result = dns_dyndb_load(library, name, cfg_obj_asstring(obj),
1644					cfg_obj_file(obj), cfg_obj_line(obj),
1645					mctx, dctx);
1646	}
1647
1648	if (result != ISC_R_SUCCESS) {
1649		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1650			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1651			      "dynamic database '%s' configuration failed: %s",
1652			      name, isc_result_totext(result));
1653	}
1654	return (result);
1655}
1656
1657static isc_result_t
1658disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1659	isc_result_t result;
1660	const cfg_obj_t *algorithms;
1661	const cfg_listelt_t *element;
1662	const char *str;
1663	dns_fixedname_t fixed;
1664	dns_name_t *name;
1665	isc_buffer_t b;
1666
1667	name = dns_fixedname_initname(&fixed);
1668	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1669	isc_buffer_constinit(&b, str, strlen(str));
1670	isc_buffer_add(&b, strlen(str));
1671	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1672
1673	algorithms = cfg_tuple_get(disabled, "algorithms");
1674	for (element = cfg_list_first(algorithms); element != NULL;
1675	     element = cfg_list_next(element))
1676	{
1677		isc_textregion_t r;
1678		dns_secalg_t alg;
1679
1680		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1681		r.length = strlen(r.base);
1682
1683		result = dns_secalg_fromtext(&alg, &r);
1684		if (result != ISC_R_SUCCESS) {
1685			uint8_t ui;
1686			result = isc_parse_uint8(&ui, r.base, 10);
1687			alg = ui;
1688		}
1689		if (result != ISC_R_SUCCESS) {
1690			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1691				    ISC_LOG_ERROR, "invalid algorithm");
1692			CHECK(result);
1693		}
1694		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1695	}
1696cleanup:
1697	return (result);
1698}
1699
1700static isc_result_t
1701disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1702	isc_result_t result;
1703	const cfg_obj_t *digests;
1704	const cfg_listelt_t *element;
1705	const char *str;
1706	dns_fixedname_t fixed;
1707	dns_name_t *name;
1708	isc_buffer_t b;
1709
1710	name = dns_fixedname_initname(&fixed);
1711	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1712	isc_buffer_constinit(&b, str, strlen(str));
1713	isc_buffer_add(&b, strlen(str));
1714	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1715
1716	digests = cfg_tuple_get(disabled, "digests");
1717	for (element = cfg_list_first(digests); element != NULL;
1718	     element = cfg_list_next(element))
1719	{
1720		isc_textregion_t r;
1721		dns_dsdigest_t digest;
1722
1723		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1724		r.length = strlen(r.base);
1725
1726		/* disable_ds_digests handles numeric values. */
1727		result = dns_dsdigest_fromtext(&digest, &r);
1728		if (result != ISC_R_SUCCESS) {
1729			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1730				    ISC_LOG_ERROR, "invalid algorithm");
1731			CHECK(result);
1732		}
1733		CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
1734	}
1735cleanup:
1736	return (result);
1737}
1738
1739static bool
1740on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1741	const cfg_listelt_t *element;
1742	dns_fixedname_t fixed;
1743	dns_name_t *name;
1744	isc_result_t result;
1745	const cfg_obj_t *value;
1746	const char *str;
1747	isc_buffer_t b;
1748
1749	name = dns_fixedname_initname(&fixed);
1750
1751	for (element = cfg_list_first(disablelist); element != NULL;
1752	     element = cfg_list_next(element))
1753	{
1754		value = cfg_listelt_value(element);
1755		str = cfg_obj_asstring(value);
1756		isc_buffer_constinit(&b, str, strlen(str));
1757		isc_buffer_add(&b, strlen(str));
1758		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
1759		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1760		if (dns_name_equal(name, zonename)) {
1761			return (true);
1762		}
1763	}
1764	return (false);
1765}
1766
1767static isc_result_t
1768check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
1769	     isc_mem_t *mctx) {
1770	char **argv = NULL;
1771	unsigned int i;
1772	isc_result_t result = ISC_R_SUCCESS;
1773
1774	CHECK(dns_zone_getdbtype(zone, &argv, mctx));
1775
1776	/*
1777	 * Check that all the arguments match.
1778	 */
1779	for (i = 0; i < dbtypec; i++) {
1780		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
1781			CHECK(ISC_R_FAILURE);
1782
1783			/*
1784			 * Check that there are not extra arguments.
1785			 */
1786		}
1787	}
1788
1789	/*
1790	 * Check that there are not extra arguments.
1791	 */
1792	if (i == dbtypec && argv[i] != NULL) {
1793		result = ISC_R_FAILURE;
1794	}
1795
1796cleanup:
1797	isc_mem_free(mctx, argv);
1798	return (result);
1799}
1800
1801static isc_result_t
1802setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
1803	isc_result_t result;
1804	isc_stats_t *zoneqrystats;
1805
1806	dns_zone_setstatlevel(zone, level);
1807
1808	zoneqrystats = NULL;
1809	if (level == dns_zonestat_full) {
1810		result = isc_stats_create(mctx, &zoneqrystats,
1811					  ns_statscounter_max);
1812		if (result != ISC_R_SUCCESS) {
1813			return (result);
1814		}
1815	}
1816	dns_zone_setrequeststats(zone, zoneqrystats);
1817	if (zoneqrystats != NULL) {
1818		isc_stats_detach(&zoneqrystats);
1819	}
1820
1821	return (ISC_R_SUCCESS);
1822}
1823
1824static named_cache_t *
1825cachelist_find(named_cachelist_t *cachelist, const char *cachename,
1826	       dns_rdataclass_t rdclass) {
1827	named_cache_t *nsc;
1828
1829	for (nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
1830	     nsc = ISC_LIST_NEXT(nsc, link))
1831	{
1832		if (nsc->rdclass == rdclass &&
1833		    strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1834		{
1835			return (nsc);
1836		}
1837	}
1838
1839	return (NULL);
1840}
1841
1842static bool
1843cache_reusable(dns_view_t *originview, dns_view_t *view,
1844	       bool new_zero_no_soattl) {
1845	if (originview->rdclass != view->rdclass ||
1846	    originview->checknames != view->checknames ||
1847	    dns_resolver_getzeronosoattl(originview->resolver) !=
1848		    new_zero_no_soattl ||
1849	    originview->acceptexpired != view->acceptexpired ||
1850	    originview->enablevalidation != view->enablevalidation ||
1851	    originview->maxcachettl != view->maxcachettl ||
1852	    originview->maxncachettl != view->maxncachettl)
1853	{
1854		return (false);
1855	}
1856
1857	return (true);
1858}
1859
1860static bool
1861cache_sharable(dns_view_t *originview, dns_view_t *view,
1862	       bool new_zero_no_soattl, uint64_t new_max_cache_size,
1863	       uint32_t new_stale_ttl, uint32_t new_stale_refresh_time) {
1864	/*
1865	 * If the cache cannot even reused for the same view, it cannot be
1866	 * shared with other views.
1867	 */
1868	if (!cache_reusable(originview, view, new_zero_no_soattl)) {
1869		return (false);
1870	}
1871
1872	/*
1873	 * Check other cache related parameters that must be consistent among
1874	 * the sharing views.
1875	 */
1876	if (dns_cache_getservestalettl(originview->cache) != new_stale_ttl ||
1877	    dns_cache_getservestalerefresh(originview->cache) !=
1878		    new_stale_refresh_time ||
1879	    dns_cache_getcachesize(originview->cache) != new_max_cache_size)
1880	{
1881		return (false);
1882	}
1883
1884	return (true);
1885}
1886
1887/*
1888 * Callback from DLZ configure when the driver sets up a writeable zone
1889 */
1890static isc_result_t
1891dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
1892	dns_name_t *origin = dns_zone_getorigin(zone);
1893	dns_rdataclass_t zclass = view->rdclass;
1894	isc_result_t result;
1895
1896	result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
1897	if (result != ISC_R_SUCCESS) {
1898		return (result);
1899	}
1900	dns_zone_setstats(zone, named_g_server->zonestats);
1901
1902	return (named_zone_configure_writeable_dlz(dlzdb, zone, zclass,
1903						   origin));
1904}
1905
1906static isc_result_t
1907dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1908	      unsigned int prefixlen, const char *server, const char *contact) {
1909	char reverse[48 + sizeof("ip6.arpa.")] = { 0 };
1910	char buf[sizeof("x.x.")];
1911	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1912	const char *sep = ": view ";
1913	const char *viewname = view->name;
1914	const unsigned char *s6;
1915	dns_fixedname_t fixed;
1916	dns_name_t *name;
1917	dns_zone_t *zone = NULL;
1918	int dns64_dbtypec = 4;
1919	isc_buffer_t b;
1920	isc_result_t result;
1921
1922	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1923		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1924
1925	if (!strcmp(viewname, "_default")) {
1926		sep = "";
1927		viewname = "";
1928	}
1929
1930	/*
1931	 * Construct the reverse name of the zone.
1932	 */
1933	s6 = na->type.in6.s6_addr;
1934	while (prefixlen > 0) {
1935		prefixlen -= 8;
1936		snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen / 8] & 0xf,
1937			 (s6[prefixlen / 8] >> 4) & 0xf);
1938		strlcat(reverse, buf, sizeof(reverse));
1939	}
1940	strlcat(reverse, "ip6.arpa.", sizeof(reverse));
1941
1942	/*
1943	 * Create the actual zone.
1944	 */
1945	if (server != NULL) {
1946		dns64_dbtype[2] = server;
1947	}
1948	if (contact != NULL) {
1949		dns64_dbtype[3] = contact;
1950	}
1951	name = dns_fixedname_initname(&fixed);
1952	isc_buffer_constinit(&b, reverse, strlen(reverse));
1953	isc_buffer_add(&b, strlen(reverse));
1954	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1955	CHECK(dns_zone_create(&zone, mctx));
1956	CHECK(dns_zone_setorigin(zone, name));
1957	dns_zone_setview(zone, view);
1958	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
1959	dns_zone_setclass(zone, view->rdclass);
1960	dns_zone_settype(zone, dns_zone_primary);
1961	dns_zone_setstats(zone, named_g_server->zonestats);
1962	dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype);
1963	if (view->queryacl != NULL) {
1964		dns_zone_setqueryacl(zone, view->queryacl);
1965	}
1966	if (view->queryonacl != NULL) {
1967		dns_zone_setqueryonacl(zone, view->queryonacl);
1968	}
1969	dns_zone_setdialup(zone, dns_dialuptype_no);
1970	dns_zone_setnotifytype(zone, dns_notifytype_no);
1971	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
1972	CHECK(setquerystats(zone, mctx, dns_zonestat_none)); /* XXXMPA */
1973	CHECK(dns_view_addzone(view, zone));
1974	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1975		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1976		      "dns64 reverse zone%s%s: %s", sep, viewname, reverse);
1977
1978cleanup:
1979	if (zone != NULL) {
1980		dns_zone_detach(&zone);
1981	}
1982	return (result);
1983}
1984
1985#ifdef USE_DNSRPS
1986typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
1987struct conf_dnsrps_ctx {
1988	isc_result_t result;
1989	char *cstr;
1990	size_t cstr_size;
1991	isc_mem_t *mctx;
1992};
1993
1994/*
1995 * Add to the DNSRPS configuration string.
1996 */
1997static bool
1998conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
1999	size_t new_len, cur_len, new_cstr_size;
2000	char *new_cstr;
2001	va_list args;
2002
2003	if (ctx->cstr == NULL) {
2004		ctx->cstr = isc_mem_get(ctx->mctx, 256);
2005		ctx->cstr[0] = '\0';
2006		ctx->cstr_size = 256;
2007	}
2008
2009	cur_len = strlen(ctx->cstr);
2010	va_start(args, p);
2011	new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p,
2012			    args) +
2013		  1;
2014	va_end(args);
2015
2016	if (cur_len + new_len <= ctx->cstr_size) {
2017		return (true);
2018	}
2019
2020	new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256;
2021	new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
2022
2023	memmove(new_cstr, ctx->cstr, cur_len);
2024	isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
2025	ctx->cstr_size = new_cstr_size;
2026	ctx->cstr = new_cstr;
2027
2028	/* cannot use args twice after a single va_start()on some systems */
2029	va_start(args, p);
2030	vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
2031	va_end(args);
2032	return (true);
2033}
2034
2035/*
2036 * Get an DNSRPS configuration value using the global and view options
2037 * for the default.  Return false upon failure.
2038 */
2039static bool
2040conf_dnsrps_get(const cfg_obj_t **sub_obj, const cfg_obj_t **maps,
2041		const cfg_obj_t *obj, const char *name,
2042		conf_dnsrps_ctx_t *ctx) {
2043	if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
2044		*sub_obj = NULL;
2045		return (false);
2046	}
2047
2048	*sub_obj = cfg_tuple_get(obj, name);
2049	if (cfg_obj_isvoid(*sub_obj)) {
2050		*sub_obj = NULL;
2051		if (maps != NULL &&
2052		    ISC_R_SUCCESS != named_config_get(maps, name, sub_obj))
2053		{
2054			*sub_obj = NULL;
2055		}
2056	}
2057	return (true);
2058}
2059
2060/*
2061 * Handle a DNSRPS boolean configuration value with the global and view
2062 * options providing the default.
2063 */
2064static void
2065conf_dnsrps_yes_no(const cfg_obj_t *obj, const char *name,
2066		   conf_dnsrps_ctx_t *ctx) {
2067	const cfg_obj_t *sub_obj;
2068
2069	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2070		return;
2071	}
2072	if (sub_obj == NULL) {
2073		return;
2074	}
2075	if (ctx == NULL) {
2076		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2077			    "\"%s\" without \"dnsrps-enable yes\"", name);
2078		return;
2079	}
2080
2081	conf_dnsrps_sadd(ctx, " %s %s", name,
2082			 cfg_obj_asboolean(sub_obj) ? "yes" : "no");
2083}
2084
2085static void
2086conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
2087		conf_dnsrps_ctx_t *ctx) {
2088	const cfg_obj_t *sub_obj;
2089
2090	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2091		return;
2092	}
2093	if (sub_obj == NULL) {
2094		return;
2095	}
2096	if (ctx == NULL) {
2097		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2098			    "\"%s\" without \"dnsrps-enable yes\"", name);
2099		return;
2100	}
2101
2102	if (cfg_obj_isduration(sub_obj)) {
2103		conf_dnsrps_sadd(ctx, " %s %d", name,
2104				 cfg_obj_asduration(sub_obj));
2105	} else {
2106		conf_dnsrps_sadd(ctx, " %s %d", name,
2107				 cfg_obj_asuint32(sub_obj));
2108	}
2109}
2110
2111/*
2112 * Convert the parsed RPZ configuration statement to a string for
2113 * dns_rpz_new_zones().
2114 */
2115static isc_result_t
2116conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps, bool nsip_enabled,
2117	    bool nsdname_enabled, dns_rpz_zbits_t *nsip_on,
2118	    dns_rpz_zbits_t *nsdname_on, char **rps_cstr, size_t *rps_cstr_size,
2119	    const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element) {
2120	conf_dnsrps_ctx_t ctx;
2121	const cfg_obj_t *zone_obj, *obj;
2122	dns_rpz_num_t rpz_num;
2123	bool on;
2124	const char *s;
2125
2126	memset(&ctx, 0, sizeof(ctx));
2127	ctx.result = ISC_R_SUCCESS;
2128	ctx.mctx = view->mctx;
2129
2130	for (rpz_num = 0; zone_element != NULL && ctx.result == ISC_R_SUCCESS;
2131	     ++rpz_num)
2132	{
2133		zone_obj = cfg_listelt_value(zone_element);
2134
2135		s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
2136		conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
2137
2138		obj = cfg_tuple_get(zone_obj, "policy");
2139		if (!cfg_obj_isvoid(obj)) {
2140			s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2141			conf_dnsrps_sadd(&ctx, " policy %s", s);
2142			if (strcasecmp(s, "cname") == 0) {
2143				s = cfg_obj_asstring(
2144					cfg_tuple_get(obj, "cname"));
2145				conf_dnsrps_sadd(&ctx, " %s", s);
2146			}
2147		}
2148
2149		conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
2150		conf_dnsrps_yes_no(zone_obj, "log", &ctx);
2151		conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
2152		obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2153		if (!cfg_obj_isvoid(obj)) {
2154			if (cfg_obj_asboolean(obj)) {
2155				*nsip_on |= DNS_RPZ_ZBIT(rpz_num);
2156			} else {
2157				*nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
2158			}
2159		}
2160		on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2161		if (nsip_enabled != on) {
2162			conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes "
2163						  : " nsip-enable no ");
2164		}
2165		obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2166		if (!cfg_obj_isvoid(obj)) {
2167			if (cfg_obj_asboolean(obj)) {
2168				*nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
2169			} else {
2170				*nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
2171			}
2172		}
2173		on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2174		if (nsdname_enabled != on) {
2175			conf_dnsrps_sadd(&ctx, on ? " nsdname-enable yes "
2176						  : " nsdname-enable no ");
2177		}
2178		conf_dnsrps_sadd(&ctx, ";\n");
2179		zone_element = cfg_list_next(zone_element);
2180	}
2181
2182	conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
2183	conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
2184	conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
2185	conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
2186	conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
2187	if (!nsip_enabled) {
2188		conf_dnsrps_sadd(&ctx, " nsip-enable no ");
2189	}
2190	if (!nsdname_enabled) {
2191		conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
2192	}
2193
2194	/*
2195	 * Get the general dnsrpzd parameters from the response-policy
2196	 * statement in the view and the general options.
2197	 */
2198	if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
2199	    obj != NULL)
2200	{
2201		conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
2202	}
2203
2204	if (ctx.result == ISC_R_SUCCESS) {
2205		*rps_cstr = ctx.cstr;
2206		*rps_cstr_size = ctx.cstr_size;
2207	} else {
2208		if (ctx.cstr != NULL) {
2209			isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
2210		}
2211		*rps_cstr = NULL;
2212		*rps_cstr_size = 0;
2213	}
2214	return (ctx.result);
2215}
2216#endif /* ifdef USE_DNSRPS */
2217
2218static isc_result_t
2219configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2220		   const char *str, const char *msg) {
2221	isc_result_t result;
2222
2223	result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx);
2224	if (result != ISC_R_SUCCESS) {
2225		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2226			    "invalid %s '%s'", msg, str);
2227	}
2228	return (result);
2229}
2230
2231static isc_result_t
2232configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2233		    const char *str, const dns_name_t *origin) {
2234	isc_result_t result;
2235
2236	result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE,
2237				      view->mctx);
2238	if (result != ISC_R_SUCCESS) {
2239		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2240			    "invalid zone '%s'", str);
2241	}
2242	return (result);
2243}
2244
2245static isc_result_t
2246configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
2247		   bool recursive_only_default, bool add_soa_default,
2248		   dns_ttl_t ttl_default, uint32_t minupdateinterval_default,
2249		   const dns_rpz_zone_t *old, bool *old_rpz_okp) {
2250	const cfg_obj_t *rpz_obj, *obj;
2251	const char *str;
2252	dns_rpz_zone_t *zone = NULL;
2253	isc_result_t result;
2254	dns_rpz_num_t rpz_num;
2255
2256	REQUIRE(old != NULL || !*old_rpz_okp);
2257
2258	rpz_obj = cfg_listelt_value(element);
2259
2260	if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
2261		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2262			    "limit of %d response policy zones exceeded",
2263			    DNS_RPZ_MAX_ZONES);
2264		return (ISC_R_FAILURE);
2265	}
2266
2267	result = dns_rpz_new_zone(view->rpzs, &zone);
2268	if (result != ISC_R_SUCCESS) {
2269		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2270			    "Error creating new RPZ zone : %s",
2271			    isc_result_totext(result));
2272		return (result);
2273	}
2274
2275	obj = cfg_tuple_get(rpz_obj, "recursive-only");
2276	if (cfg_obj_isvoid(obj) ? recursive_only_default
2277				: cfg_obj_asboolean(obj))
2278	{
2279		view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num);
2280	} else {
2281		view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num);
2282	}
2283
2284	obj = cfg_tuple_get(rpz_obj, "log");
2285	if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) {
2286		view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num);
2287	} else {
2288		view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num);
2289	}
2290
2291	obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2292	if (cfg_obj_isduration(obj)) {
2293		zone->max_policy_ttl = cfg_obj_asduration(obj);
2294	} else {
2295		zone->max_policy_ttl = ttl_default;
2296	}
2297	if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl) {
2298		*old_rpz_okp = false;
2299	}
2300
2301	obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2302	if (cfg_obj_isduration(obj)) {
2303		zone->min_update_interval = cfg_obj_asduration(obj);
2304	} else {
2305		zone->min_update_interval = minupdateinterval_default;
2306	}
2307	if (*old_rpz_okp &&
2308	    zone->min_update_interval != old->min_update_interval)
2309	{
2310		*old_rpz_okp = false;
2311	}
2312
2313	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
2314	result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone");
2315	if (result != ISC_R_SUCCESS) {
2316		return (result);
2317	}
2318	if (dns_name_equal(&zone->origin, dns_rootname)) {
2319		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2320			    "invalid zone name '%s'", str);
2321		return (DNS_R_EMPTYLABEL);
2322	}
2323	if (!view->rpzs->p.dnsrps_enabled) {
2324		for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1;
2325		     ++rpz_num)
2326		{
2327			if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
2328					   &zone->origin))
2329			{
2330				cfg_obj_log(rpz_obj, named_g_lctx,
2331					    DNS_RPZ_ERROR_LEVEL,
2332					    "duplicate '%s'", str);
2333				result = DNS_R_DUPLICATE;
2334				return (result);
2335			}
2336		}
2337	}
2338	if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) {
2339		*old_rpz_okp = false;
2340	}
2341
2342	result = configure_rpz_name2(view, rpz_obj, &zone->client_ip,
2343				     DNS_RPZ_CLIENT_IP_ZONE, &zone->origin);
2344	if (result != ISC_R_SUCCESS) {
2345		return (result);
2346	}
2347
2348	result = configure_rpz_name2(view, rpz_obj, &zone->ip, DNS_RPZ_IP_ZONE,
2349				     &zone->origin);
2350	if (result != ISC_R_SUCCESS) {
2351		return (result);
2352	}
2353
2354	result = configure_rpz_name2(view, rpz_obj, &zone->nsdname,
2355				     DNS_RPZ_NSDNAME_ZONE, &zone->origin);
2356	if (result != ISC_R_SUCCESS) {
2357		return (result);
2358	}
2359
2360	result = configure_rpz_name2(view, rpz_obj, &zone->nsip,
2361				     DNS_RPZ_NSIP_ZONE, &zone->origin);
2362	if (result != ISC_R_SUCCESS) {
2363		return (result);
2364	}
2365
2366	result = configure_rpz_name(view, rpz_obj, &zone->passthru,
2367				    DNS_RPZ_PASSTHRU_NAME, "name");
2368	if (result != ISC_R_SUCCESS) {
2369		return (result);
2370	}
2371
2372	result = configure_rpz_name(view, rpz_obj, &zone->drop,
2373				    DNS_RPZ_DROP_NAME, "name");
2374	if (result != ISC_R_SUCCESS) {
2375		return (result);
2376	}
2377
2378	result = configure_rpz_name(view, rpz_obj, &zone->tcp_only,
2379				    DNS_RPZ_TCP_ONLY_NAME, "name");
2380	if (result != ISC_R_SUCCESS) {
2381		return (result);
2382	}
2383
2384	obj = cfg_tuple_get(rpz_obj, "policy");
2385	if (cfg_obj_isvoid(obj)) {
2386		zone->policy = DNS_RPZ_POLICY_GIVEN;
2387	} else {
2388		str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2389		zone->policy = dns_rpz_str2policy(str);
2390		INSIST(zone->policy != DNS_RPZ_POLICY_ERROR);
2391		if (zone->policy == DNS_RPZ_POLICY_CNAME) {
2392			str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
2393			result = configure_rpz_name(view, rpz_obj, &zone->cname,
2394						    str, "cname");
2395			if (result != ISC_R_SUCCESS) {
2396				return (result);
2397			}
2398		}
2399	}
2400	if (*old_rpz_okp && (zone->policy != old->policy ||
2401			     !dns_name_equal(&old->cname, &zone->cname)))
2402	{
2403		*old_rpz_okp = false;
2404	}
2405
2406	obj = cfg_tuple_get(rpz_obj, "add-soa");
2407	if (cfg_obj_isvoid(obj)) {
2408		zone->addsoa = add_soa_default;
2409	} else {
2410		zone->addsoa = cfg_obj_asboolean(obj);
2411	}
2412	if (*old_rpz_okp && zone->addsoa != old->addsoa) {
2413		*old_rpz_okp = false;
2414	}
2415
2416	return (ISC_R_SUCCESS);
2417}
2418
2419static isc_result_t
2420configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
2421	      const cfg_obj_t *rpz_obj, bool *old_rpz_okp) {
2422	bool dnsrps_enabled;
2423	const cfg_listelt_t *zone_element;
2424	char *rps_cstr;
2425	size_t rps_cstr_size;
2426	const cfg_obj_t *sub_obj;
2427	bool recursive_only_default, add_soa_default;
2428	bool nsip_enabled, nsdname_enabled;
2429	dns_rpz_zbits_t nsip_on, nsdname_on;
2430	dns_ttl_t ttl_default;
2431	uint32_t minupdateinterval_default;
2432	dns_rpz_zones_t *zones;
2433	const dns_rpz_zones_t *old;
2434	bool pview_must_detach = false;
2435	const dns_rpz_zone_t *old_zone;
2436	isc_result_t result;
2437	int i;
2438
2439	*old_rpz_okp = false;
2440
2441	zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
2442	if (zone_element == NULL) {
2443		return (ISC_R_SUCCESS);
2444	}
2445
2446	nsip_enabled = true;
2447	sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2448	if (!cfg_obj_isvoid(sub_obj)) {
2449		nsip_enabled = cfg_obj_asboolean(sub_obj);
2450	}
2451	nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2452
2453	nsdname_enabled = true;
2454	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2455	if (!cfg_obj_isvoid(sub_obj)) {
2456		nsdname_enabled = cfg_obj_asboolean(sub_obj);
2457	}
2458	nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2459
2460	/*
2461	 * "dnsrps-enable yes|no" can be either a global or response-policy
2462	 * clause.
2463	 */
2464	dnsrps_enabled = false;
2465	rps_cstr = NULL;
2466	rps_cstr_size = 0;
2467	sub_obj = NULL;
2468	(void)named_config_get(maps, "dnsrps-enable", &sub_obj);
2469	if (sub_obj != NULL) {
2470		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2471	}
2472	sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
2473	if (!cfg_obj_isvoid(sub_obj)) {
2474		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2475	}
2476#ifndef USE_DNSRPS
2477	if (dnsrps_enabled) {
2478		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2479			    "\"dnsrps-enable yes\" but"
2480			    " without `./configure --enable-dnsrps`");
2481		return (ISC_R_FAILURE);
2482	}
2483#else  /* ifndef USE_DNSRPS */
2484	if (dnsrps_enabled) {
2485		if (librpz == NULL) {
2486			cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2487				    "\"dnsrps-enable yes\" but %s",
2488				    librpz_lib_open_emsg.c);
2489			return (ISC_R_FAILURE);
2490		}
2491
2492		/*
2493		 * Generate the DNS Response Policy Service
2494		 * configuration string.
2495		 */
2496		result = conf_dnsrps(view, maps, nsip_enabled, nsdname_enabled,
2497				     &nsip_on, &nsdname_on, &rps_cstr,
2498				     &rps_cstr_size, rpz_obj, zone_element);
2499		if (result != ISC_R_SUCCESS) {
2500			return (result);
2501		}
2502	}
2503#endif /* ifndef USE_DNSRPS */
2504
2505	result = dns_rpz_new_zones(view->mctx, named_g_taskmgr,
2506				   named_g_timermgr, rps_cstr, rps_cstr_size,
2507				   &view->rpzs);
2508	if (result != ISC_R_SUCCESS) {
2509		return (result);
2510	}
2511
2512	zones = view->rpzs;
2513
2514	zones->p.nsip_on = nsip_on;
2515	zones->p.nsdname_on = nsdname_on;
2516
2517	sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
2518	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2519		recursive_only_default = false;
2520	} else {
2521		recursive_only_default = true;
2522	}
2523
2524	sub_obj = cfg_tuple_get(rpz_obj, "add-soa");
2525	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2526		add_soa_default = false;
2527	} else {
2528		add_soa_default = true;
2529	}
2530
2531	sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
2532	if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
2533		zones->p.break_dnssec = true;
2534	} else {
2535		zones->p.break_dnssec = false;
2536	}
2537
2538	sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2539	if (cfg_obj_isduration(sub_obj)) {
2540		ttl_default = cfg_obj_asduration(sub_obj);
2541	} else {
2542		ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
2543	}
2544
2545	sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2546	if (cfg_obj_isduration(sub_obj)) {
2547		minupdateinterval_default = cfg_obj_asduration(sub_obj);
2548	} else {
2549		minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
2550	}
2551
2552	sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
2553	if (cfg_obj_isuint32(sub_obj)) {
2554		zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
2555	} else {
2556		zones->p.min_ns_labels = 2;
2557	}
2558
2559	sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
2560	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2561		zones->p.qname_wait_recurse = true;
2562	} else {
2563		zones->p.qname_wait_recurse = false;
2564	}
2565
2566	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-wait-recurse");
2567	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2568		zones->p.nsdname_wait_recurse = true;
2569	} else {
2570		zones->p.nsdname_wait_recurse = false;
2571	}
2572
2573	sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse");
2574	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2575		zones->p.nsip_wait_recurse = true;
2576	} else {
2577		zones->p.nsip_wait_recurse = false;
2578	}
2579
2580	if (pview != NULL) {
2581		old = pview->rpzs;
2582	} else {
2583		result = dns_viewlist_find(&named_g_server->viewlist,
2584					   view->name, view->rdclass, &pview);
2585		if (result == ISC_R_SUCCESS) {
2586			pview_must_detach = true;
2587			old = pview->rpzs;
2588		} else {
2589			old = NULL;
2590		}
2591	}
2592
2593	if (old == NULL) {
2594		*old_rpz_okp = false;
2595	} else {
2596		*old_rpz_okp = true;
2597	}
2598
2599	for (i = 0; zone_element != NULL;
2600	     ++i, zone_element = cfg_list_next(zone_element))
2601	{
2602		INSIST(!*old_rpz_okp || old != NULL);
2603		if (*old_rpz_okp && i < old->p.num_zones) {
2604			old_zone = old->zones[i];
2605		} else {
2606			*old_rpz_okp = false;
2607			old_zone = NULL;
2608		}
2609		result = configure_rpz_zone(
2610			view, zone_element, recursive_only_default,
2611			add_soa_default, ttl_default, minupdateinterval_default,
2612			old_zone, old_rpz_okp);
2613		if (result != ISC_R_SUCCESS) {
2614			if (pview_must_detach) {
2615				dns_view_detach(&pview);
2616			}
2617			return (result);
2618		}
2619	}
2620
2621	/*
2622	 * If this is a reloading and the parameters and list of policy
2623	 * zones are unchanged, then use the same policy data.
2624	 * Data for individual zones that must be reloaded will be merged.
2625	 */
2626	if (*old_rpz_okp) {
2627		if (old != NULL &&
2628		    memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
2629		{
2630			*old_rpz_okp = false;
2631		} else if ((old == NULL || old->rps_cstr == NULL) !=
2632			   (zones->rps_cstr == NULL))
2633		{
2634			*old_rpz_okp = false;
2635		} else if (old != NULL && zones->rps_cstr != NULL &&
2636			   strcmp(old->rps_cstr, zones->rps_cstr) != 0)
2637		{
2638			*old_rpz_okp = false;
2639		}
2640	}
2641
2642	if (*old_rpz_okp) {
2643		dns_rpz_shutdown_rpzs(view->rpzs);
2644		dns_rpz_detach_rpzs(&view->rpzs);
2645		dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
2646		dns_rpz_detach_rpzs(&pview->rpzs);
2647	} else if (old != NULL && pview != NULL) {
2648		++pview->rpzs->rpz_ver;
2649		view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
2650		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
2651			    "updated RPZ policy: version %d",
2652			    view->rpzs->rpz_ver);
2653	}
2654
2655	if (pview_must_detach) {
2656		dns_view_detach(&pview);
2657	}
2658
2659	return (ISC_R_SUCCESS);
2660}
2661
2662static void
2663catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2664	catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2665	isc_result_t result;
2666	dns_forwarders_t *dnsforwarders = NULL;
2667	dns_name_t *name = NULL;
2668	isc_buffer_t namebuf;
2669	isc_buffer_t *confbuf;
2670	char nameb[DNS_NAME_FORMATSIZE];
2671	const cfg_obj_t *zlist = NULL;
2672	cfg_obj_t *zoneconf = NULL;
2673	cfg_obj_t *zoneobj = NULL;
2674	ns_cfgctx_t *cfg;
2675	dns_zone_t *zone = NULL;
2676
2677	cfg = (ns_cfgctx_t *)ev->view->new_zone_config;
2678	if (cfg == NULL) {
2679		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2680			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2681			      "catz: allow-new-zones statement missing from "
2682			      "config; cannot add zone from the catalog");
2683		goto cleanup;
2684	}
2685
2686	name = dns_catz_entry_getname(ev->entry);
2687
2688	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
2689	dns_name_totext(name, true, &namebuf);
2690	isc_buffer_putuint8(&namebuf, 0);
2691
2692	result = dns_fwdtable_find(ev->view->fwdtable, name, NULL,
2693				   &dnsforwarders);
2694	if (result == ISC_R_SUCCESS &&
2695	    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
2696	{
2697		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2698			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2699			      "catz: catz_addmodzone_taskaction: "
2700			      "zone '%s' will not be processed because of the "
2701			      "explicitly configured forwarding for that zone",
2702			      nameb);
2703		goto cleanup;
2704	}
2705
2706	result = dns_zt_find(ev->view->zonetable, name, 0, NULL, &zone);
2707
2708	if (ev->mod) {
2709		dns_catz_zone_t *parentcatz;
2710
2711		if (result != ISC_R_SUCCESS) {
2712			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2713				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2714				      "catz: error \"%s\" while trying to "
2715				      "modify zone '%s'",
2716				      isc_result_totext(result), nameb);
2717			goto cleanup;
2718		}
2719
2720		if (!dns_zone_getadded(zone)) {
2721			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2722				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2723				      "catz: catz_addmodzone_taskaction: "
2724				      "zone '%s' is not a dynamically "
2725				      "added zone",
2726				      nameb);
2727			goto cleanup;
2728		}
2729
2730		parentcatz = dns_zone_get_parentcatz(zone);
2731
2732		if (parentcatz == NULL) {
2733			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2734				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2735				      "catz: catz_addmodzone_taskaction: "
2736				      "zone '%s' exists and is not added by "
2737				      "a catalog zone, so won't be modified",
2738				      nameb);
2739			goto cleanup;
2740		}
2741		if (parentcatz != ev->origin) {
2742			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2743				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2744				      "catz: catz_addmodzone_taskaction: "
2745				      "zone '%s' exists in multiple "
2746				      "catalog zones",
2747				      nameb);
2748			goto cleanup;
2749		}
2750
2751		dns_zone_detach(&zone);
2752	} else {
2753		/* Zone shouldn't already exist when adding */
2754		if (result == ISC_R_SUCCESS) {
2755			if (dns_zone_get_parentcatz(zone) == NULL) {
2756				isc_log_write(
2757					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2758					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2759					"catz: "
2760					"catz_addmodzone_taskaction: "
2761					"zone '%s' will not be added "
2762					"because it is an explicitly "
2763					"configured zone",
2764					nameb);
2765			} else {
2766				isc_log_write(
2767					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2768					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2769					"catz: "
2770					"catz_addmodzone_taskaction: "
2771					"zone '%s' will not be added "
2772					"because another catalog zone "
2773					"already contains an entry with "
2774					"that zone",
2775					nameb);
2776			}
2777			goto cleanup;
2778		} else if (result != ISC_R_NOTFOUND &&
2779			   result != DNS_R_PARTIALMATCH)
2780		{
2781			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2782				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2783				      "catz: error \"%s\" while trying to "
2784				      "add zone '%s'",
2785				      isc_result_totext(result), nameb);
2786			goto cleanup;
2787		} else { /* this can happen in case of DNS_R_PARTIALMATCH */
2788			if (zone != NULL) {
2789				dns_zone_detach(&zone);
2790			}
2791		}
2792	}
2793	RUNTIME_CHECK(zone == NULL);
2794	/* Create a config for new zone */
2795	confbuf = NULL;
2796	result = dns_catz_generate_zonecfg(ev->origin, ev->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_buffer3()
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
2825	result = isc_task_beginexclusive(task);
2826	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2827	dns_view_thaw(ev->view);
2828	result = configure_zone(
2829		cfg->config, zoneobj, cfg->vconfig, ev->cbd->server->mctx,
2830		ev->view, &ev->cbd->server->viewlist,
2831		&ev->cbd->server->kasplist, cfg->actx, true, false, ev->mod);
2832	dns_view_freeze(ev->view);
2833	isc_task_endexclusive(task);
2834
2835	if (result != ISC_R_SUCCESS) {
2836		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2837			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2838			      "catz: failed to configure zone '%s' - %d", nameb,
2839			      result);
2840		goto cleanup;
2841	}
2842
2843	/* Is it there yet? */
2844	CHECK(dns_zt_find(ev->view->zonetable, name, 0, NULL, &zone));
2845
2846	/*
2847	 * Load the zone from the master file.	If this fails, we'll
2848	 * need to undo the configuration we've done already.
2849	 */
2850	result = dns_zone_load(zone, true);
2851	if (result != ISC_R_SUCCESS) {
2852		dns_db_t *dbp = NULL;
2853		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2854			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2855			      "catz: dns_zone_load() failed "
2856			      "with %s; reverting.",
2857			      isc_result_totext(result));
2858
2859		/* If the zone loaded partially, unload it */
2860		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2861			dns_db_detach(&dbp);
2862			dns_zone_unload(zone);
2863		}
2864
2865		/* Remove the zone from the zone table */
2866		dns_zt_unmount(ev->view->zonetable, zone);
2867		goto cleanup;
2868	}
2869
2870	/* Flag the zone as having been added at runtime */
2871	dns_zone_setadded(zone, true);
2872	dns_zone_set_parentcatz(zone, ev->origin);
2873
2874cleanup:
2875	if (zone != NULL) {
2876		dns_zone_detach(&zone);
2877	}
2878	if (zoneconf != NULL) {
2879		cfg_obj_destroy(cfg->add_parser, &zoneconf);
2880	}
2881	dns_catz_entry_detach(ev->origin, &ev->entry);
2882	dns_catz_detach_catz(&ev->origin);
2883	dns_view_detach(&ev->view);
2884	isc_event_free(ISC_EVENT_PTR(&ev));
2885}
2886
2887static void
2888catz_delzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2889	catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2890	isc_result_t result;
2891	dns_zone_t *zone = NULL;
2892	dns_db_t *dbp = NULL;
2893	char cname[DNS_NAME_FORMATSIZE];
2894	const char *file;
2895
2896	result = isc_task_beginexclusive(task);
2897	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2898
2899	dns_name_format(dns_catz_entry_getname(ev->entry), cname,
2900			DNS_NAME_FORMATSIZE);
2901	result = dns_zt_find(ev->view->zonetable,
2902			     dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
2903	if (result != ISC_R_SUCCESS) {
2904		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2905			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2906			      "catz: catz_delzone_taskaction: "
2907			      "zone '%s' not found",
2908			      cname);
2909		goto cleanup;
2910	}
2911
2912	if (!dns_zone_getadded(zone)) {
2913		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2914			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2915			      "catz: catz_delzone_taskaction: "
2916			      "zone '%s' is not a dynamically added zone",
2917			      cname);
2918		goto cleanup;
2919	}
2920
2921	if (dns_zone_get_parentcatz(zone) != ev->origin) {
2922		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2923			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2924			      "catz: catz_delzone_taskaction: zone "
2925			      "'%s' exists in multiple catalog zones",
2926			      cname);
2927		goto cleanup;
2928	}
2929
2930	/* Stop answering for this zone */
2931	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2932		dns_db_detach(&dbp);
2933		dns_zone_unload(zone);
2934	}
2935
2936	CHECK(dns_zt_unmount(ev->view->zonetable, zone));
2937	file = dns_zone_getfile(zone);
2938	if (file != NULL) {
2939		isc_file_remove(file);
2940		file = dns_zone_getjournal(zone);
2941		if (file != NULL) {
2942			isc_file_remove(file);
2943		}
2944	}
2945
2946	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2947		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2948		      "catz: catz_delzone_taskaction: "
2949		      "zone '%s' deleted",
2950		      cname);
2951cleanup:
2952	isc_task_endexclusive(task);
2953	if (zone != NULL) {
2954		dns_zone_detach(&zone);
2955	}
2956	dns_catz_entry_detach(ev->origin, &ev->entry);
2957	dns_catz_detach_catz(&ev->origin);
2958	dns_view_detach(&ev->view);
2959	isc_event_free(ISC_EVENT_PTR(&ev));
2960}
2961
2962static isc_result_t
2963catz_create_chg_task(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
2964		     dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata,
2965		     isc_eventtype_t type) {
2966	catz_chgzone_event_t *event = NULL;
2967	isc_task_t *task = NULL;
2968	isc_result_t result;
2969	isc_taskaction_t action = NULL;
2970
2971	result = isc_taskmgr_excltask(taskmgr, &task);
2972	if (result != ISC_R_SUCCESS) {
2973		return (result);
2974	}
2975
2976	switch (type) {
2977	case DNS_EVENT_CATZADDZONE:
2978	case DNS_EVENT_CATZMODZONE:
2979		action = catz_addmodzone_taskaction;
2980		break;
2981	case DNS_EVENT_CATZDELZONE:
2982		action = catz_delzone_taskaction;
2983		break;
2984	default:
2985		REQUIRE(0);
2986		UNREACHABLE();
2987	}
2988
2989	event = (catz_chgzone_event_t *)isc_event_allocate(
2990		view->mctx, origin, type, action, NULL, sizeof(*event));
2991
2992	event->cbd = (catz_cb_data_t *)udata;
2993	event->entry = NULL;
2994	event->origin = NULL;
2995	event->view = NULL;
2996	event->mod = (type == DNS_EVENT_CATZMODZONE);
2997
2998	dns_catz_entry_attach(entry, &event->entry);
2999	dns_catz_attach_catz(origin, &event->origin);
3000	dns_view_attach(view, &event->view);
3001
3002	isc_task_send(task, ISC_EVENT_PTR(&event));
3003	isc_task_detach(&task);
3004
3005	return (ISC_R_SUCCESS);
3006}
3007
3008static isc_result_t
3009catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3010	     isc_taskmgr_t *taskmgr, void *udata) {
3011	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3012				     DNS_EVENT_CATZADDZONE));
3013}
3014
3015static isc_result_t
3016catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3017	     isc_taskmgr_t *taskmgr, void *udata) {
3018	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3019				     DNS_EVENT_CATZDELZONE));
3020}
3021
3022static isc_result_t
3023catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3024	     isc_taskmgr_t *taskmgr, void *udata) {
3025	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3026				     DNS_EVENT_CATZMODZONE));
3027}
3028
3029static isc_result_t
3030configure_catz_zone(dns_view_t *view, dns_view_t *pview,
3031		    const cfg_obj_t *config, const cfg_listelt_t *element) {
3032	const cfg_obj_t *catz_obj, *obj;
3033	dns_catz_zone_t *zone = NULL;
3034	const char *str;
3035	isc_result_t result;
3036	dns_name_t origin;
3037	dns_catz_options_t *opts;
3038
3039	dns_name_init(&origin, NULL);
3040	catz_obj = cfg_listelt_value(element);
3041
3042	str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
3043
3044	result = dns_name_fromstring(&origin, str, DNS_NAME_DOWNCASE,
3045				     view->mctx);
3046	if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname)) {
3047		result = DNS_R_EMPTYLABEL;
3048	}
3049
3050	if (result != ISC_R_SUCCESS) {
3051		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3052			    "catz: invalid zone name '%s'", str);
3053		goto cleanup;
3054	}
3055
3056	result = dns_catz_add_zone(view->catzs, &origin, &zone);
3057	if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
3058		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3059			    "catz: unable to create catalog zone '%s', "
3060			    "error %s",
3061			    str, isc_result_totext(result));
3062		goto cleanup;
3063	}
3064
3065	if (result == ISC_R_EXISTS) {
3066		isc_ht_iter_t *it = NULL;
3067
3068		RUNTIME_CHECK(pview != NULL);
3069
3070		/*
3071		 * xxxwpk todo: reconfigure the zone!!!!
3072		 */
3073		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3074			    "catz: catalog zone '%s' will not be reconfigured",
3075			    str);
3076		/*
3077		 * We have to walk through all the member zones and attach
3078		 * them to current view
3079		 */
3080		dns_catz_get_iterator(zone, &it);
3081
3082		for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
3083		     result = isc_ht_iter_next(it))
3084		{
3085			dns_name_t *name = NULL;
3086			dns_zone_t *dnszone = NULL;
3087			dns_catz_entry_t *entry = NULL;
3088			isc_result_t tresult;
3089
3090			isc_ht_iter_current(it, (void **)&entry);
3091			name = dns_catz_entry_getname(entry);
3092
3093			tresult = dns_view_findzone(pview, name, &dnszone);
3094			if (tresult != ISC_R_SUCCESS) {
3095				continue;
3096			}
3097
3098			dns_zone_setview(dnszone, view);
3099			dns_view_addzone(view, dnszone);
3100
3101			/*
3102			 * The dns_view_findzone() call above increments the
3103			 * zone's reference count, which we need to decrement
3104			 * back.  However, as dns_zone_detach() sets the
3105			 * supplied pointer to NULL, calling it is deferred
3106			 * until the dnszone variable is no longer used.
3107			 */
3108			dns_zone_detach(&dnszone);
3109		}
3110
3111		isc_ht_iter_destroy(&it);
3112
3113		result = ISC_R_SUCCESS;
3114	}
3115
3116	dns_catz_zone_resetdefoptions(zone);
3117	opts = dns_catz_zone_getdefoptions(zone);
3118
3119	obj = cfg_tuple_get(catz_obj, "default-masters");
3120	if (obj == NULL || !cfg_obj_istuple(obj)) {
3121		obj = cfg_tuple_get(catz_obj, "default-primaries");
3122	}
3123	if (obj != NULL && cfg_obj_istuple(obj)) {
3124		result = named_config_getipandkeylist(
3125			config, "primaries", obj, view->mctx, &opts->masters);
3126	}
3127
3128	obj = cfg_tuple_get(catz_obj, "in-memory");
3129	if (obj != NULL && cfg_obj_isboolean(obj)) {
3130		opts->in_memory = cfg_obj_asboolean(obj);
3131	}
3132
3133	obj = cfg_tuple_get(catz_obj, "zone-directory");
3134	if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) {
3135		opts->zonedir = isc_mem_strdup(view->mctx,
3136					       cfg_obj_asstring(obj));
3137		if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) {
3138			cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3139				    "catz: zone-directory '%s' "
3140				    "not found; zone files will not be "
3141				    "saved",
3142				    opts->zonedir);
3143			opts->in_memory = true;
3144		}
3145	}
3146
3147	obj = cfg_tuple_get(catz_obj, "min-update-interval");
3148	if (obj != NULL && cfg_obj_isduration(obj)) {
3149		opts->min_update_interval = cfg_obj_asduration(obj);
3150	}
3151
3152cleanup:
3153	dns_name_free(&origin, view->mctx);
3154
3155	return (result);
3156}
3157
3158static catz_cb_data_t ns_catz_cbdata;
3159static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
3160	catz_addzone, catz_modzone, catz_delzone, &ns_catz_cbdata
3161};
3162
3163static isc_result_t
3164configure_catz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t *config,
3165	       const cfg_obj_t *catz_obj) {
3166	const cfg_listelt_t *zone_element = NULL;
3167	const dns_catz_zones_t *old = NULL;
3168	bool pview_must_detach = false;
3169	isc_result_t result;
3170
3171	/* xxxwpk TODO do it cleaner, once, somewhere */
3172	ns_catz_cbdata.server = named_g_server;
3173
3174	zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
3175	if (zone_element == NULL) {
3176		return (ISC_R_SUCCESS);
3177	}
3178
3179	CHECK(dns_catz_new_zones(view->mctx, named_g_taskmgr, named_g_timermgr,
3180				 &view->catzs, &ns_catz_zonemodmethods));
3181
3182	if (pview != NULL) {
3183		old = pview->catzs;
3184	} else {
3185		result = dns_viewlist_find(&named_g_server->viewlist,
3186					   view->name, view->rdclass, &pview);
3187		if (result == ISC_R_SUCCESS) {
3188			pview_must_detach = true;
3189			old = pview->catzs;
3190		}
3191	}
3192
3193	if (old != NULL) {
3194		dns_catz_shutdown_catzs(view->catzs);
3195		dns_catz_detach_catzs(&view->catzs);
3196		dns_catz_attach_catzs(pview->catzs, &view->catzs);
3197		dns_catz_detach_catzs(&pview->catzs);
3198		dns_catz_prereconfig(view->catzs);
3199	}
3200
3201	while (zone_element != NULL) {
3202		CHECK(configure_catz_zone(view, pview, config, zone_element));
3203		zone_element = cfg_list_next(zone_element);
3204	}
3205
3206	if (old != NULL) {
3207		dns_catz_postreconfig(view->catzs);
3208	}
3209
3210	result = ISC_R_SUCCESS;
3211
3212cleanup:
3213	if (pview_must_detach) {
3214		dns_view_detach(&pview);
3215	}
3216
3217	return (result);
3218}
3219
3220#define CHECK_RRL(cond, pat, val1, val2)                                   \
3221	do {                                                               \
3222		if (!(cond)) {                                             \
3223			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, pat, \
3224				    val1, val2);                           \
3225			result = ISC_R_RANGE;                              \
3226			goto cleanup;                                      \
3227		}                                                          \
3228	} while (0)
3229
3230#define CHECK_RRL_RATE(rate, def, max_rate, name)                           \
3231	do {                                                                \
3232		obj = NULL;                                                 \
3233		rrl->rate.str = name;                                       \
3234		result = cfg_map_get(map, name, &obj);                      \
3235		if (result == ISC_R_SUCCESS) {                              \
3236			rrl->rate.r = cfg_obj_asuint32(obj);                \
3237			CHECK_RRL(rrl->rate.r <= max_rate, name " %d > %d", \
3238				  rrl->rate.r, max_rate);                   \
3239		} else {                                                    \
3240			rrl->rate.r = def;                                  \
3241		}                                                           \
3242		rrl->rate.scaled = rrl->rate.r;                             \
3243	} while (0)
3244
3245static isc_result_t
3246configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
3247	const cfg_obj_t *obj;
3248	dns_rrl_t *rrl;
3249	isc_result_t result;
3250	int min_entries, i, j;
3251
3252	/*
3253	 * Most DNS servers have few clients, but intentinally open
3254	 * recursive and authoritative servers often have many.
3255	 * So start with a small number of entries unless told otherwise
3256	 * to reduce cold-start costs.
3257	 */
3258	min_entries = 500;
3259	obj = NULL;
3260	result = cfg_map_get(map, "min-table-size", &obj);
3261	if (result == ISC_R_SUCCESS) {
3262		min_entries = cfg_obj_asuint32(obj);
3263		if (min_entries < 1) {
3264			min_entries = 1;
3265		}
3266	}
3267	result = dns_rrl_init(&rrl, view, min_entries);
3268	if (result != ISC_R_SUCCESS) {
3269		return (result);
3270	}
3271
3272	i = ISC_MAX(20000, min_entries);
3273	obj = NULL;
3274	result = cfg_map_get(map, "max-table-size", &obj);
3275	if (result == ISC_R_SUCCESS) {
3276		i = cfg_obj_asuint32(obj);
3277		CHECK_RRL(i >= min_entries,
3278			  "max-table-size %d < min-table-size %d", i,
3279			  min_entries);
3280	}
3281	rrl->max_entries = i;
3282
3283	CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
3284		       "responses-per-second");
3285	CHECK_RRL_RATE(referrals_per_second, rrl->responses_per_second.r,
3286		       DNS_RRL_MAX_RATE, "referrals-per-second");
3287	CHECK_RRL_RATE(nodata_per_second, rrl->responses_per_second.r,
3288		       DNS_RRL_MAX_RATE, "nodata-per-second");
3289	CHECK_RRL_RATE(nxdomains_per_second, rrl->responses_per_second.r,
3290		       DNS_RRL_MAX_RATE, "nxdomains-per-second");
3291	CHECK_RRL_RATE(errors_per_second, rrl->responses_per_second.r,
3292		       DNS_RRL_MAX_RATE, "errors-per-second");
3293
3294	CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
3295
3296	CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
3297
3298	i = 15;
3299	obj = NULL;
3300	result = cfg_map_get(map, "window", &obj);
3301	if (result == ISC_R_SUCCESS) {
3302		i = cfg_obj_asuint32(obj);
3303		CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
3304			  "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
3305	}
3306	rrl->window = i;
3307
3308	i = 0;
3309	obj = NULL;
3310	result = cfg_map_get(map, "qps-scale", &obj);
3311	if (result == ISC_R_SUCCESS) {
3312		i = cfg_obj_asuint32(obj);
3313		CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
3314	}
3315	rrl->qps_scale = i;
3316	rrl->qps = 1.0;
3317
3318	i = 24;
3319	obj = NULL;
3320	result = cfg_map_get(map, "ipv4-prefix-length", &obj);
3321	if (result == ISC_R_SUCCESS) {
3322		i = cfg_obj_asuint32(obj);
3323		CHECK_RRL(i >= 8 && i <= 32,
3324			  "invalid 'ipv4-prefix-length %d'%s", i, "");
3325	}
3326	rrl->ipv4_prefixlen = i;
3327	if (i == 32) {
3328		rrl->ipv4_mask = 0xffffffff;
3329	} else {
3330		rrl->ipv4_mask = htonl(0xffffffff << (32 - i));
3331	}
3332
3333	i = 56;
3334	obj = NULL;
3335	result = cfg_map_get(map, "ipv6-prefix-length", &obj);
3336	if (result == ISC_R_SUCCESS) {
3337		i = cfg_obj_asuint32(obj);
3338		CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
3339			  "ipv6-prefix-length %d < 16 or > %d", i,
3340			  DNS_RRL_MAX_PREFIX);
3341	}
3342	rrl->ipv6_prefixlen = i;
3343	for (j = 0; j < 4; ++j) {
3344		if (i <= 0) {
3345			rrl->ipv6_mask[j] = 0;
3346		} else if (i < 32) {
3347			rrl->ipv6_mask[j] = htonl(0xffffffff << (32 - i));
3348		} else {
3349			rrl->ipv6_mask[j] = 0xffffffff;
3350		}
3351		i -= 32;
3352	}
3353
3354	obj = NULL;
3355	result = cfg_map_get(map, "exempt-clients", &obj);
3356	if (result == ISC_R_SUCCESS) {
3357		result = cfg_acl_fromconfig(obj, config, named_g_lctx,
3358					    named_g_aclconfctx, named_g_mctx, 0,
3359					    &rrl->exempt);
3360		CHECK_RRL(result == ISC_R_SUCCESS, "invalid %s%s",
3361			  "address match list", "");
3362	}
3363
3364	obj = NULL;
3365	result = cfg_map_get(map, "log-only", &obj);
3366	if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) {
3367		rrl->log_only = true;
3368	} else {
3369		rrl->log_only = false;
3370	}
3371
3372	return (ISC_R_SUCCESS);
3373
3374cleanup:
3375	dns_rrl_view_destroy(view);
3376	return (result);
3377}
3378
3379static isc_result_t
3380add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3381	const dns_name_t *origin, const dns_name_t *contact) {
3382	dns_dbnode_t *node = NULL;
3383	dns_rdata_t rdata = DNS_RDATA_INIT;
3384	dns_rdatalist_t rdatalist;
3385	dns_rdataset_t rdataset;
3386	isc_result_t result;
3387	unsigned char buf[DNS_SOA_BUFFERSIZE];
3388
3389	CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 0, 28800,
3390				 7200, 604800, 86400, buf, &rdata));
3391
3392	dns_rdatalist_init(&rdatalist);
3393	rdatalist.type = rdata.type;
3394	rdatalist.rdclass = rdata.rdclass;
3395	rdatalist.ttl = 86400;
3396	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3397
3398	dns_rdataset_init(&rdataset);
3399	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3400	CHECK(dns_db_findnode(db, name, true, &node));
3401	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3402
3403cleanup:
3404	if (node != NULL) {
3405		dns_db_detachnode(db, &node);
3406	}
3407	return (result);
3408}
3409
3410static isc_result_t
3411add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3412       const dns_name_t *nsname) {
3413	dns_dbnode_t *node = NULL;
3414	dns_rdata_ns_t ns;
3415	dns_rdata_t rdata = DNS_RDATA_INIT;
3416	dns_rdatalist_t rdatalist;
3417	dns_rdataset_t rdataset;
3418	isc_result_t result;
3419	isc_buffer_t b;
3420	unsigned char buf[DNS_NAME_MAXWIRE];
3421
3422	isc_buffer_init(&b, buf, sizeof(buf));
3423
3424	ns.common.rdtype = dns_rdatatype_ns;
3425	ns.common.rdclass = dns_db_class(db);
3426	ns.mctx = NULL;
3427	dns_name_init(&ns.name, NULL);
3428	dns_name_clone(nsname, &ns.name);
3429	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
3430				   &ns, &b));
3431
3432	dns_rdatalist_init(&rdatalist);
3433	rdatalist.type = rdata.type;
3434	rdatalist.rdclass = rdata.rdclass;
3435	rdatalist.ttl = 86400;
3436	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3437
3438	dns_rdataset_init(&rdataset);
3439	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3440	CHECK(dns_db_findnode(db, name, true, &node));
3441	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3442
3443cleanup:
3444	if (node != NULL) {
3445		dns_db_detachnode(db, &node);
3446	}
3447	return (result);
3448}
3449
3450static isc_result_t
3451create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
3452		  const cfg_obj_t *zonelist, const char **empty_dbtype,
3453		  int empty_dbtypec, dns_zonestat_level_t statlevel) {
3454	char namebuf[DNS_NAME_FORMATSIZE];
3455	const cfg_listelt_t *element;
3456	const cfg_obj_t *obj;
3457	const cfg_obj_t *zconfig;
3458	const cfg_obj_t *zoptions;
3459	const char *rbt_dbtype[4] = { "rbt" };
3460	const char *sep = ": view ";
3461	const char *str;
3462	const char *viewname = view->name;
3463	dns_db_t *db = NULL;
3464	dns_dbversion_t *version = NULL;
3465	dns_fixedname_t cfixed;
3466	dns_fixedname_t fixed;
3467	dns_fixedname_t nsfixed;
3468	dns_name_t *contact;
3469	dns_name_t *ns;
3470	dns_name_t *zname;
3471	dns_zone_t *zone = NULL;
3472	int rbt_dbtypec = 1;
3473	isc_result_t result;
3474	dns_namereln_t namereln;
3475	int order;
3476	unsigned int nlabels;
3477
3478	zname = dns_fixedname_initname(&fixed);
3479	ns = dns_fixedname_initname(&nsfixed);
3480	contact = dns_fixedname_initname(&cfixed);
3481
3482	/*
3483	 * Look for forward "zones" beneath this empty zone and if so
3484	 * create a custom db for the empty zone.
3485	 */
3486	for (element = cfg_list_first(zonelist); element != NULL;
3487	     element = cfg_list_next(element))
3488	{
3489		zconfig = cfg_listelt_value(element);
3490		str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3491		CHECK(dns_name_fromstring(zname, str, 0, NULL));
3492		namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
3493		if (namereln != dns_namereln_subdomain) {
3494			continue;
3495		}
3496
3497		zoptions = cfg_tuple_get(zconfig, "options");
3498
3499		obj = NULL;
3500		(void)cfg_map_get(zoptions, "type", &obj);
3501		if (obj != NULL &&
3502		    strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
3503		{
3504			obj = NULL;
3505			(void)cfg_map_get(zoptions, "forward", &obj);
3506			if (obj == NULL) {
3507				continue;
3508			}
3509			if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) {
3510				continue;
3511			}
3512		}
3513		if (db == NULL) {
3514			CHECK(dns_db_create(view->mctx, "rbt", name,
3515					    dns_dbtype_zone, view->rdclass, 0,
3516					    NULL, &db));
3517			CHECK(dns_db_newversion(db, &version));
3518			if (strcmp(empty_dbtype[2], "@") == 0) {
3519				dns_name_clone(name, ns);
3520			} else {
3521				CHECK(dns_name_fromstring(ns, empty_dbtype[2],
3522							  0, NULL));
3523			}
3524			CHECK(dns_name_fromstring(contact, empty_dbtype[3], 0,
3525						  NULL));
3526			CHECK(add_soa(db, version, name, ns, contact));
3527			CHECK(add_ns(db, version, name, ns));
3528		}
3529		CHECK(add_ns(db, version, zname, dns_rootname));
3530	}
3531
3532	/*
3533	 * Is the existing zone the ok to use?
3534	 */
3535	if (pzone != NULL) {
3536		unsigned int typec;
3537		const char **dbargv;
3538
3539		if (db != NULL) {
3540			typec = rbt_dbtypec;
3541			dbargv = rbt_dbtype;
3542		} else {
3543			typec = empty_dbtypec;
3544			dbargv = empty_dbtype;
3545		}
3546
3547		result = check_dbtype(pzone, typec, dbargv, view->mctx);
3548		if (result != ISC_R_SUCCESS) {
3549			pzone = NULL;
3550		}
3551
3552		if (pzone != NULL &&
3553		    dns_zone_gettype(pzone) != dns_zone_primary)
3554		{
3555			pzone = NULL;
3556		}
3557		if (pzone != NULL && dns_zone_getfile(pzone) != NULL) {
3558			pzone = NULL;
3559		}
3560		if (pzone != NULL) {
3561			dns_zone_getraw(pzone, &zone);
3562			if (zone != NULL) {
3563				dns_zone_detach(&zone);
3564				pzone = NULL;
3565			}
3566		}
3567	}
3568
3569	if (pzone == NULL) {
3570		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
3571		CHECK(dns_zone_setorigin(zone, name));
3572		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3573		if (db == NULL) {
3574			dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype);
3575		}
3576		dns_zone_setclass(zone, view->rdclass);
3577		dns_zone_settype(zone, dns_zone_primary);
3578		dns_zone_setstats(zone, named_g_server->zonestats);
3579	} else {
3580		dns_zone_attach(pzone, &zone);
3581	}
3582
3583	dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
3584	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3585	dns_zone_setnotifytype(zone, dns_notifytype_no);
3586	dns_zone_setdialup(zone, dns_dialuptype_no);
3587	dns_zone_setautomatic(zone, true);
3588	if (view->queryacl != NULL) {
3589		dns_zone_setqueryacl(zone, view->queryacl);
3590	} else {
3591		dns_zone_clearqueryacl(zone);
3592	}
3593	if (view->queryonacl != NULL) {
3594		dns_zone_setqueryonacl(zone, view->queryonacl);
3595	} else {
3596		dns_zone_clearqueryonacl(zone);
3597	}
3598	dns_zone_clearupdateacl(zone);
3599	if (view->transferacl != NULL) {
3600		dns_zone_setxfracl(zone, view->transferacl);
3601	} else {
3602		dns_zone_clearxfracl(zone);
3603	}
3604
3605	CHECK(setquerystats(zone, view->mctx, statlevel));
3606	if (db != NULL) {
3607		dns_db_closeversion(db, &version, true);
3608		CHECK(dns_zone_replacedb(zone, db, false));
3609	}
3610	dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true);
3611	dns_zone_setview(zone, view);
3612	CHECK(dns_view_addzone(view, zone));
3613
3614	if (!strcmp(viewname, "_default")) {
3615		sep = "";
3616		viewname = "";
3617	}
3618	dns_name_format(name, namebuf, sizeof(namebuf));
3619	isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD,
3620		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3621		      "automatic empty zone%s%s: %s", sep, viewname, namebuf);
3622
3623cleanup:
3624	if (zone != NULL) {
3625		dns_zone_detach(&zone);
3626	}
3627	if (version != NULL) {
3628		dns_db_closeversion(db, &version, false);
3629	}
3630	if (db != NULL) {
3631		dns_db_detach(&db);
3632	}
3633
3634	INSIST(version == NULL);
3635
3636	return (result);
3637}
3638
3639static isc_result_t
3640create_ipv4only_zone(dns_zone_t *pzone, dns_view_t *view,
3641		     const dns_name_t *name, const char *type, isc_mem_t *mctx,
3642		     const char *server, const char *contact) {
3643	char namebuf[DNS_NAME_FORMATSIZE];
3644	const char *dbtype[4] = { "_builtin", NULL, "@", "." };
3645	const char *sep = ": view ";
3646	const char *viewname = view->name;
3647	dns_zone_t *zone = NULL;
3648	int dbtypec = 4;
3649	isc_result_t result;
3650
3651	REQUIRE(type != NULL);
3652
3653	if (!strcmp(viewname, "_default")) {
3654		sep = "";
3655		viewname = "";
3656	}
3657
3658	dbtype[1] = type;
3659	if (server != NULL) {
3660		dbtype[2] = server;
3661	}
3662	if (contact != NULL) {
3663		dbtype[3] = contact;
3664	}
3665
3666	if (pzone != NULL) {
3667		result = check_dbtype(pzone, dbtypec, dbtype, view->mctx);
3668		if (result != ISC_R_SUCCESS) {
3669			pzone = NULL;
3670		}
3671	}
3672
3673	if (pzone == NULL) {
3674		/*
3675		 * Create the actual zone.
3676		 */
3677		CHECK(dns_zone_create(&zone, mctx));
3678		CHECK(dns_zone_setorigin(zone, name));
3679		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3680		dns_zone_setclass(zone, view->rdclass);
3681		dns_zone_settype(zone, dns_zone_primary);
3682		dns_zone_setstats(zone, named_g_server->zonestats);
3683		dns_zone_setdbtype(zone, dbtypec, dbtype);
3684		dns_zone_setdialup(zone, dns_dialuptype_no);
3685		dns_zone_setnotifytype(zone, dns_notifytype_no);
3686		dns_zone_setautomatic(zone, true);
3687		dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3688	} else {
3689		dns_zone_attach(pzone, &zone);
3690	}
3691	if (view->queryacl != NULL) {
3692		dns_zone_setqueryacl(zone, view->queryacl);
3693	} else {
3694		dns_zone_clearqueryacl(zone);
3695	}
3696	if (view->queryonacl != NULL) {
3697		dns_zone_setqueryonacl(zone, view->queryonacl);
3698	} else {
3699		dns_zone_clearqueryonacl(zone);
3700	}
3701	dns_zone_setview(zone, view);
3702	CHECK(dns_view_addzone(view, zone));
3703
3704	dns_name_format(name, namebuf, sizeof(namebuf));
3705	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3706		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3707		      "automatic ipv4only zone%s%s: %s", sep, viewname,
3708		      namebuf);
3709
3710cleanup:
3711	if (zone != NULL) {
3712		dns_zone_detach(&zone);
3713	}
3714	return (result);
3715}
3716
3717#ifdef HAVE_DNSTAP
3718static isc_result_t
3719configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
3720	isc_result_t result;
3721	const cfg_obj_t *obj, *obj2;
3722	const cfg_listelt_t *element;
3723	const char *dpath;
3724	const cfg_obj_t *dlist = NULL;
3725	dns_dtmsgtype_t dttypes = 0;
3726	unsigned int i;
3727	struct fstrm_iothr_options *fopt = NULL;
3728
3729	result = named_config_get(maps, "dnstap", &dlist);
3730	if (result != ISC_R_SUCCESS) {
3731		return (ISC_R_SUCCESS);
3732	}
3733
3734	for (element = cfg_list_first(dlist); element != NULL;
3735	     element = cfg_list_next(element))
3736	{
3737		const char *str;
3738		dns_dtmsgtype_t dt = 0;
3739
3740		obj = cfg_listelt_value(element);
3741		obj2 = cfg_tuple_get(obj, "type");
3742		str = cfg_obj_asstring(obj2);
3743		if (strcasecmp(str, "client") == 0) {
3744			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR;
3745		} else if (strcasecmp(str, "auth") == 0) {
3746			dt |= DNS_DTTYPE_AQ | DNS_DTTYPE_AR;
3747		} else if (strcasecmp(str, "resolver") == 0) {
3748			dt |= DNS_DTTYPE_RQ | DNS_DTTYPE_RR;
3749		} else if (strcasecmp(str, "forwarder") == 0) {
3750			dt |= DNS_DTTYPE_FQ | DNS_DTTYPE_FR;
3751		} else if (strcasecmp(str, "update") == 0) {
3752			dt |= DNS_DTTYPE_UQ | DNS_DTTYPE_UR;
3753		} else if (strcasecmp(str, "all") == 0) {
3754			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR | DNS_DTTYPE_AQ |
3755			      DNS_DTTYPE_AR | DNS_DTTYPE_RQ | DNS_DTTYPE_RR |
3756			      DNS_DTTYPE_FQ | DNS_DTTYPE_FR | DNS_DTTYPE_UQ |
3757			      DNS_DTTYPE_UR;
3758		}
3759
3760		obj2 = cfg_tuple_get(obj, "mode");
3761		if (obj2 == NULL || cfg_obj_isvoid(obj2)) {
3762			dttypes |= dt;
3763			continue;
3764		}
3765
3766		str = cfg_obj_asstring(obj2);
3767		if (strcasecmp(str, "query") == 0) {
3768			dt &= ~DNS_DTTYPE_RESPONSE;
3769		} else if (strcasecmp(str, "response") == 0) {
3770			dt &= ~DNS_DTTYPE_QUERY;
3771		}
3772
3773		dttypes |= dt;
3774	}
3775
3776	if (named_g_server->dtenv == NULL && dttypes != 0) {
3777		dns_dtmode_t dmode;
3778		uint64_t max_size = 0;
3779		uint32_t rolls = 0;
3780		isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment;
3781
3782		obj = NULL;
3783		CHECKM(named_config_get(maps, "dnstap-output", &obj),
3784		       "'dnstap-output' must be set if 'dnstap' is set");
3785
3786		obj2 = cfg_tuple_get(obj, "mode");
3787		if (obj2 == NULL) {
3788			CHECKM(ISC_R_FAILURE, "dnstap-output mode not found");
3789		}
3790		if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) {
3791			dmode = dns_dtmode_file;
3792		} else {
3793			dmode = dns_dtmode_unix;
3794		}
3795
3796		obj2 = cfg_tuple_get(obj, "path");
3797		if (obj2 == NULL) {
3798			CHECKM(ISC_R_FAILURE, "dnstap-output path not found");
3799		}
3800
3801		dpath = cfg_obj_asstring(obj2);
3802
3803		obj2 = cfg_tuple_get(obj, "size");
3804		if (obj2 != NULL && cfg_obj_isuint64(obj2)) {
3805			max_size = cfg_obj_asuint64(obj2);
3806			if (max_size > SIZE_MAX) {
3807				cfg_obj_log(obj2, named_g_lctx, ISC_LOG_WARNING,
3808					    "'dnstap-output size "
3809					    "%" PRIu64 "' "
3810					    "is too large for this "
3811					    "system; reducing to %lu",
3812					    max_size, (unsigned long)SIZE_MAX);
3813				max_size = SIZE_MAX;
3814			}
3815		}
3816
3817		obj2 = cfg_tuple_get(obj, "versions");
3818		if (obj2 != NULL && cfg_obj_isuint32(obj2)) {
3819			rolls = cfg_obj_asuint32(obj2);
3820		} else {
3821			rolls = ISC_LOG_ROLLINFINITE;
3822		}
3823
3824		obj2 = cfg_tuple_get(obj, "suffix");
3825		if (obj2 != NULL && cfg_obj_isstring(obj2) &&
3826		    strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0)
3827		{
3828			suffix = isc_log_rollsuffix_timestamp;
3829		}
3830
3831		fopt = fstrm_iothr_options_init();
3832		/*
3833		 * Both network threads and worker threads may log dnstap data.
3834		 */
3835		fstrm_iothr_options_set_num_input_queues(fopt,
3836							 2 * named_g_cpus);
3837		fstrm_iothr_options_set_queue_model(
3838			fopt, FSTRM_IOTHR_QUEUE_MODEL_MPSC);
3839
3840		obj = NULL;
3841		result = named_config_get(maps, "fstrm-set-buffer-hint", &obj);
3842		if (result == ISC_R_SUCCESS) {
3843			i = cfg_obj_asuint32(obj);
3844			fstrm_iothr_options_set_buffer_hint(fopt, i);
3845		}
3846
3847		obj = NULL;
3848		result = named_config_get(maps, "fstrm-set-flush-timeout",
3849					  &obj);
3850		if (result == ISC_R_SUCCESS) {
3851			i = cfg_obj_asuint32(obj);
3852			fstrm_iothr_options_set_flush_timeout(fopt, i);
3853		}
3854
3855		obj = NULL;
3856		result = named_config_get(maps, "fstrm-set-input-queue-size",
3857					  &obj);
3858		if (result == ISC_R_SUCCESS) {
3859			i = cfg_obj_asuint32(obj);
3860			fstrm_iothr_options_set_input_queue_size(fopt, i);
3861		}
3862
3863		obj = NULL;
3864		result = named_config_get(
3865			maps, "fstrm-set-output-notify-threshold", &obj);
3866		if (result == ISC_R_SUCCESS) {
3867			i = cfg_obj_asuint32(obj);
3868			fstrm_iothr_options_set_queue_notify_threshold(fopt, i);
3869		}
3870
3871		obj = NULL;
3872		result = named_config_get(maps, "fstrm-set-output-queue-model",
3873					  &obj);
3874		if (result == ISC_R_SUCCESS) {
3875			if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0) {
3876				i = FSTRM_IOTHR_QUEUE_MODEL_SPSC;
3877			} else {
3878				i = FSTRM_IOTHR_QUEUE_MODEL_MPSC;
3879			}
3880			fstrm_iothr_options_set_queue_model(fopt, i);
3881		}
3882
3883		obj = NULL;
3884		result = named_config_get(maps, "fstrm-set-output-queue-size",
3885					  &obj);
3886		if (result == ISC_R_SUCCESS) {
3887			i = cfg_obj_asuint32(obj);
3888			fstrm_iothr_options_set_output_queue_size(fopt, i);
3889		}
3890
3891		obj = NULL;
3892		result = named_config_get(maps, "fstrm-set-reopen-interval",
3893					  &obj);
3894		if (result == ISC_R_SUCCESS) {
3895			i = cfg_obj_asduration(obj);
3896			fstrm_iothr_options_set_reopen_interval(fopt, i);
3897		}
3898
3899		CHECKM(dns_dt_create(named_g_mctx, dmode, dpath, &fopt,
3900				     named_g_server->task,
3901				     &named_g_server->dtenv),
3902		       "unable to create dnstap environment");
3903
3904		CHECKM(dns_dt_setupfile(named_g_server->dtenv, max_size, rolls,
3905					suffix),
3906		       "unable to set up dnstap logfile");
3907	}
3908
3909	if (named_g_server->dtenv == NULL) {
3910		return (ISC_R_SUCCESS);
3911	}
3912
3913	obj = NULL;
3914	result = named_config_get(maps, "dnstap-version", &obj);
3915	if (result != ISC_R_SUCCESS) {
3916		/* not specified; use the product and version */
3917		dns_dt_setversion(named_g_server->dtenv, PACKAGE_STRING);
3918	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3919		/* Quoted string */
3920		dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj));
3921	}
3922
3923	obj = NULL;
3924	result = named_config_get(maps, "dnstap-identity", &obj);
3925	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
3926		/* "hostname" is interpreted as boolean true */
3927		char buf[256];
3928		if (gethostname(buf, sizeof(buf)) == 0) {
3929			dns_dt_setidentity(named_g_server->dtenv, buf);
3930		}
3931	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3932		/* Quoted string */
3933		dns_dt_setidentity(named_g_server->dtenv,
3934				   cfg_obj_asstring(obj));
3935	}
3936
3937	dns_dt_attach(named_g_server->dtenv, &view->dtenv);
3938	view->dttypes = dttypes;
3939
3940	result = ISC_R_SUCCESS;
3941
3942cleanup:
3943	if (fopt != NULL) {
3944		fstrm_iothr_options_destroy(&fopt);
3945	}
3946
3947	return (result);
3948}
3949#endif /* HAVE_DNSTAP */
3950
3951static isc_result_t
3952create_mapped_acl(void) {
3953	isc_result_t result;
3954	dns_acl_t *acl = NULL;
3955	struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT;
3956	isc_netaddr_t addr;
3957
3958	isc_netaddr_fromin6(&addr, &in6);
3959
3960	result = dns_acl_create(named_g_mctx, 1, &acl);
3961	if (result != ISC_R_SUCCESS) {
3962		return (result);
3963	}
3964
3965	result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
3966	if (result == ISC_R_SUCCESS) {
3967		dns_acl_attach(acl, &named_g_mapped);
3968	}
3969	dns_acl_detach(&acl);
3970	return (result);
3971}
3972
3973/*%
3974 * A callback for the cfg_pluginlist_foreach() call in configure_view() below.
3975 * If registering any plugin fails, registering subsequent ones is not
3976 * attempted.
3977 */
3978static isc_result_t
3979register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
3980		    const char *plugin_path, const char *parameters,
3981		    void *callback_data) {
3982	dns_view_t *view = callback_data;
3983	char full_path[PATH_MAX];
3984	isc_result_t result;
3985
3986	result = ns_plugin_expandpath(plugin_path, full_path,
3987				      sizeof(full_path));
3988	if (result != ISC_R_SUCCESS) {
3989		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3990			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3991			      "%s: plugin configuration failed: "
3992			      "unable to get full plugin path: %s",
3993			      plugin_path, isc_result_totext(result));
3994		return (result);
3995	}
3996
3997	result = ns_plugin_register(full_path, parameters, config,
3998				    cfg_obj_file(obj), cfg_obj_line(obj),
3999				    named_g_mctx, named_g_lctx,
4000				    named_g_aclconfctx, view);
4001	if (result != ISC_R_SUCCESS) {
4002		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4003			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4004			      "%s: plugin configuration failed: %s", full_path,
4005			      isc_result_totext(result));
4006	}
4007
4008	return (result);
4009}
4010
4011/*
4012 * Determine if a minimal-sized cache can be used for a given view, according
4013 * to 'maps' (implicit defaults, global options, view options) and 'optionmaps'
4014 * (global options, view options).  This is only allowed for views which have
4015 * recursion disabled and do not have "max-cache-size" set explicitly.  Using
4016 * minimal-sized caches prevents a situation in which all explicitly configured
4017 * and built-in views inherit the default "max-cache-size 90%;" setting, which
4018 * could lead to memory exhaustion with multiple views configured.
4019 */
4020static bool
4021minimal_cache_allowed(const cfg_obj_t *maps[4],
4022		      const cfg_obj_t *optionmaps[3]) {
4023	const cfg_obj_t *obj;
4024
4025	/*
4026	 * Do not use a minimal-sized cache for a view with recursion enabled.
4027	 */
4028	obj = NULL;
4029	(void)named_config_get(maps, "recursion", &obj);
4030	INSIST(obj != NULL);
4031	if (cfg_obj_asboolean(obj)) {
4032		return (false);
4033	}
4034
4035	/*
4036	 * Do not use a minimal-sized cache if a specific size was requested.
4037	 */
4038	obj = NULL;
4039	(void)named_config_get(optionmaps, "max-cache-size", &obj);
4040	if (obj != NULL) {
4041		return (false);
4042	}
4043
4044	return (true);
4045}
4046
4047static const char *const response_synonyms[] = { "response", NULL };
4048
4049static const dns_name_t *
4050algorithm_name(unsigned int alg) {
4051	switch (alg) {
4052	case DST_ALG_HMACMD5:
4053		return (dns_tsig_hmacmd5_name);
4054	case DST_ALG_HMACSHA1:
4055		return (dns_tsig_hmacsha1_name);
4056	case DST_ALG_HMACSHA224:
4057		return (dns_tsig_hmacsha224_name);
4058	case DST_ALG_HMACSHA256:
4059		return (dns_tsig_hmacsha256_name);
4060	case DST_ALG_HMACSHA384:
4061		return (dns_tsig_hmacsha384_name);
4062	case DST_ALG_HMACSHA512:
4063		return (dns_tsig_hmacsha512_name);
4064	case DST_ALG_GSSAPI:
4065		return (dns_tsig_gssapi_name);
4066	default:
4067		UNREACHABLE();
4068	}
4069}
4070
4071/*
4072 * Configure 'view' according to 'vconfig', taking defaults from
4073 * 'config' where values are missing in 'vconfig'.
4074 *
4075 * When configuring the default view, 'vconfig' will be NULL and the
4076 * global defaults in 'config' used exclusively.
4077 */
4078static isc_result_t
4079configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
4080	       cfg_obj_t *vconfig, named_cachelist_t *cachelist,
4081	       dns_kasplist_t *kasplist, const cfg_obj_t *bindkeys,
4082	       isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints) {
4083	const cfg_obj_t *maps[4];
4084	const cfg_obj_t *cfgmaps[3];
4085	const cfg_obj_t *optionmaps[3];
4086	const cfg_obj_t *options = NULL;
4087	const cfg_obj_t *voptions = NULL;
4088	const cfg_obj_t *forwardtype;
4089	const cfg_obj_t *forwarders;
4090	const cfg_obj_t *alternates;
4091	const cfg_obj_t *zonelist;
4092	const cfg_obj_t *dlzlist;
4093	const cfg_obj_t *dlz;
4094	const cfg_obj_t *prefetch_trigger;
4095	const cfg_obj_t *prefetch_eligible;
4096	unsigned int dlzargc;
4097	char **dlzargv;
4098	const cfg_obj_t *dyndb_list, *plugin_list;
4099	const cfg_obj_t *disabled;
4100	const cfg_obj_t *obj, *obj2;
4101	const cfg_listelt_t *element = NULL;
4102	const cfg_listelt_t *zone_element_latest = NULL;
4103	in_port_t port;
4104	dns_cache_t *cache = NULL;
4105	isc_result_t result;
4106	size_t max_cache_size;
4107	uint32_t max_cache_size_percent = 0;
4108	size_t max_adb_size;
4109	uint32_t lame_ttl, fail_ttl;
4110	uint32_t max_stale_ttl = 0;
4111	uint32_t stale_refresh_time = 0;
4112	dns_tsig_keyring_t *ring = NULL;
4113	dns_transport_list_t *transports = NULL;
4114	dns_view_t *pview = NULL; /* Production view */
4115	isc_mem_t *cmctx = NULL, *hmctx = NULL;
4116	dns_dispatch_t *dispatch4 = NULL;
4117	dns_dispatch_t *dispatch6 = NULL;
4118	bool rpz_configured = false;
4119	bool catz_configured = false;
4120	bool shared_cache = false;
4121	int i = 0, j = 0, k = 0;
4122	const char *str;
4123	const char *cachename = NULL;
4124	dns_order_t *order = NULL;
4125	uint32_t udpsize;
4126	uint32_t maxbits;
4127	unsigned int resopts = 0;
4128	dns_zone_t *zone = NULL;
4129	uint32_t max_clients_per_query;
4130	bool empty_zones_enable;
4131	const cfg_obj_t *disablelist = NULL;
4132	isc_stats_t *resstats = NULL;
4133	dns_stats_t *resquerystats = NULL;
4134	bool auto_root = false;
4135	named_cache_t *nsc;
4136	bool zero_no_soattl;
4137	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
4138	unsigned int query_timeout, ndisp;
4139	bool old_rpz_ok = false;
4140	dns_dyndbctx_t *dctx = NULL;
4141	unsigned int resolver_param;
4142	dns_ntatable_t *ntatable = NULL;
4143	const char *qminmode = NULL;
4144
4145	REQUIRE(DNS_VIEW_VALID(view));
4146
4147	if (config != NULL) {
4148		(void)cfg_map_get(config, "options", &options);
4149	}
4150
4151	/*
4152	 * maps: view options, options, defaults
4153	 * cfgmaps: view options, config
4154	 * optionmaps: view options, options
4155	 */
4156	if (vconfig != NULL) {
4157		voptions = cfg_tuple_get(vconfig, "options");
4158		maps[i++] = voptions;
4159		optionmaps[j++] = voptions;
4160		cfgmaps[k++] = voptions;
4161	}
4162	if (options != NULL) {
4163		maps[i++] = options;
4164		optionmaps[j++] = options;
4165	}
4166
4167	maps[i++] = named_g_defaults;
4168	maps[i] = NULL;
4169	optionmaps[j] = NULL;
4170	if (config != NULL) {
4171		cfgmaps[k++] = config;
4172	}
4173	cfgmaps[k] = NULL;
4174
4175	/*
4176	 * Set the view's port number for outgoing queries.
4177	 */
4178	CHECKM(named_config_getport(config, "port", &port), "port");
4179	dns_view_setdstport(view, port);
4180
4181	/*
4182	 * Make the list of response policy zone names for a view that
4183	 * is used for real lookups and so cares about hints.
4184	 */
4185	obj = NULL;
4186	if (view->rdclass == dns_rdataclass_in && need_hints &&
4187	    named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS)
4188	{
4189		CHECK(configure_rpz(view, NULL, maps, obj, &old_rpz_ok));
4190		rpz_configured = true;
4191	}
4192
4193	obj = NULL;
4194	if (view->rdclass != dns_rdataclass_in && need_hints &&
4195	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
4196	{
4197		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4198			    "'catalog-zones' option is only supported "
4199			    "for views with class IN");
4200	}
4201
4202	obj = NULL;
4203	if (view->rdclass == dns_rdataclass_in && need_hints &&
4204	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
4205	{
4206		CHECK(configure_catz(view, NULL, config, obj));
4207		catz_configured = true;
4208	}
4209
4210	/*
4211	 * Configure the zones.
4212	 */
4213	zonelist = NULL;
4214	if (voptions != NULL) {
4215		(void)cfg_map_get(voptions, "zone", &zonelist);
4216	} else {
4217		(void)cfg_map_get(config, "zone", &zonelist);
4218	}
4219
4220	/*
4221	 * Load zone configuration
4222	 */
4223	for (element = cfg_list_first(zonelist); element != NULL;
4224	     element = cfg_list_next(element))
4225	{
4226		const cfg_obj_t *zconfig = cfg_listelt_value(element);
4227		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
4228				     viewlist, kasplist, actx, false,
4229				     old_rpz_ok, false));
4230		zone_element_latest = element;
4231	}
4232
4233	/*
4234	 * Check that a primary or secondary zone was found for each
4235	 * zone named in the response policy statement, unless we are
4236	 * using RPZ service interface.
4237	 */
4238	if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
4239		dns_rpz_num_t n;
4240
4241		for (n = 0; n < view->rpzs->p.num_zones; ++n) {
4242			if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
4243				char namebuf[DNS_NAME_FORMATSIZE];
4244
4245				dns_name_format(&view->rpzs->zones[n]->origin,
4246						namebuf, sizeof(namebuf));
4247				isc_log_write(named_g_lctx,
4248					      NAMED_LOGCATEGORY_GENERAL,
4249					      NAMED_LOGMODULE_SERVER,
4250					      DNS_RPZ_ERROR_LEVEL,
4251					      "rpz '%s' is not a primary or a "
4252					      "secondary zone",
4253					      namebuf);
4254				result = ISC_R_NOTFOUND;
4255				goto cleanup;
4256			}
4257		}
4258	}
4259
4260	/*
4261	 * If we're allowing added zones, then load zone configuration
4262	 * from the newzone file for zones that were added during previous
4263	 * runs.
4264	 */
4265	CHECK(configure_newzones(view, config, vconfig, mctx, actx));
4266
4267	/*
4268	 * Create Dynamically Loadable Zone driver.
4269	 */
4270	dlzlist = NULL;
4271	if (voptions != NULL) {
4272		(void)cfg_map_get(voptions, "dlz", &dlzlist);
4273	} else {
4274		(void)cfg_map_get(config, "dlz", &dlzlist);
4275	}
4276
4277	for (element = cfg_list_first(dlzlist); element != NULL;
4278	     element = cfg_list_next(element))
4279	{
4280		dlz = cfg_listelt_value(element);
4281
4282		obj = NULL;
4283		(void)cfg_map_get(dlz, "database", &obj);
4284		if (obj != NULL) {
4285			dns_dlzdb_t *dlzdb = NULL;
4286			const cfg_obj_t *name, *search = NULL;
4287			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
4288
4289			if (s == NULL) {
4290				result = ISC_R_NOMEMORY;
4291				goto cleanup;
4292			}
4293
4294			result = isc_commandline_strtoargv(mctx, s, &dlzargc,
4295							   &dlzargv, 0);
4296			if (result != ISC_R_SUCCESS) {
4297				isc_mem_free(mctx, s);
4298				goto cleanup;
4299			}
4300
4301			name = cfg_map_getname(dlz);
4302			result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
4303					       dlzargv[0], dlzargc, dlzargv,
4304					       &dlzdb);
4305			isc_mem_free(mctx, s);
4306			isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
4307			if (result != ISC_R_SUCCESS) {
4308				goto cleanup;
4309			}
4310
4311			/*
4312			 * If the DLZ backend supports configuration,
4313			 * and is searchable, then call its configure
4314			 * method now.  If not searchable, we'll take
4315			 * care of it when we process the zone statement.
4316			 */
4317			(void)cfg_map_get(dlz, "search", &search);
4318			if (search == NULL || cfg_obj_asboolean(search)) {
4319				dlzdb->search = true;
4320				result = dns_dlzconfigure(
4321					view, dlzdb, dlzconfigure_callback);
4322				if (result != ISC_R_SUCCESS) {
4323					goto cleanup;
4324				}
4325				ISC_LIST_APPEND(view->dlz_searched, dlzdb,
4326						link);
4327			} else {
4328				dlzdb->search = false;
4329				ISC_LIST_APPEND(view->dlz_unsearched, dlzdb,
4330						link);
4331			}
4332		}
4333	}
4334
4335	/*
4336	 * Obtain configuration parameters that affect the decision of whether
4337	 * we can reuse/share an existing cache.
4338	 */
4339	obj = NULL;
4340	result = named_config_get(maps, "max-cache-size", &obj);
4341	INSIST(result == ISC_R_SUCCESS);
4342	/*
4343	 * If "-T maxcachesize=..." is in effect, it overrides any other
4344	 * "max-cache-size" setting found in configuration, either implicit or
4345	 * explicit.  For simplicity, the value passed to that command line
4346	 * option is always treated as the number of bytes to set
4347	 * "max-cache-size" to.
4348	 */
4349	if (named_g_maxcachesize != 0) {
4350		max_cache_size = named_g_maxcachesize;
4351	} else if (minimal_cache_allowed(maps, optionmaps)) {
4352		/*
4353		 * dns_cache_setcachesize() will adjust this to the smallest
4354		 * allowed value.
4355		 */
4356		max_cache_size = 1;
4357	} else if (cfg_obj_isstring(obj)) {
4358		str = cfg_obj_asstring(obj);
4359		INSIST(strcasecmp(str, "unlimited") == 0);
4360		max_cache_size = 0;
4361	} else if (cfg_obj_ispercentage(obj)) {
4362		max_cache_size = SIZE_AS_PERCENT;
4363		max_cache_size_percent = cfg_obj_aspercentage(obj);
4364	} else {
4365		isc_resourcevalue_t value;
4366		value = cfg_obj_asuint64(obj);
4367		if (value > SIZE_MAX) {
4368			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4369				    "'max-cache-size "
4370				    "%" PRIu64 "' "
4371				    "is too large for this "
4372				    "system; reducing to %lu",
4373				    value, (unsigned long)SIZE_MAX);
4374			value = SIZE_MAX;
4375		}
4376		max_cache_size = (size_t)value;
4377	}
4378
4379	if (max_cache_size == SIZE_AS_PERCENT) {
4380		uint64_t totalphys = isc_meminfo_totalphys();
4381
4382		max_cache_size =
4383			(size_t)(totalphys * max_cache_size_percent / 100);
4384		if (totalphys == 0) {
4385			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4386				    "Unable to determine amount of physical "
4387				    "memory, setting 'max-cache-size' to "
4388				    "unlimited");
4389		} else {
4390			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
4391				    "'max-cache-size %d%%' "
4392				    "- setting to %" PRIu64 "MB "
4393				    "(out of %" PRIu64 "MB)",
4394				    max_cache_size_percent,
4395				    (uint64_t)(max_cache_size / (1024 * 1024)),
4396				    totalphys / (1024 * 1024));
4397		}
4398	}
4399
4400	/* Check-names. */
4401	obj = NULL;
4402	result = named_checknames_get(maps, response_synonyms, &obj);
4403	INSIST(result == ISC_R_SUCCESS);
4404
4405	str = cfg_obj_asstring(obj);
4406	if (strcasecmp(str, "fail") == 0) {
4407		resopts |= DNS_RESOLVER_CHECKNAMES |
4408			   DNS_RESOLVER_CHECKNAMESFAIL;
4409		view->checknames = true;
4410	} else if (strcasecmp(str, "warn") == 0) {
4411		resopts |= DNS_RESOLVER_CHECKNAMES;
4412		view->checknames = false;
4413	} else if (strcasecmp(str, "ignore") == 0) {
4414		view->checknames = false;
4415	} else {
4416		UNREACHABLE();
4417	}
4418
4419	obj = NULL;
4420	result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj);
4421	INSIST(result == ISC_R_SUCCESS);
4422	zero_no_soattl = cfg_obj_asboolean(obj);
4423
4424	obj = NULL;
4425	result = named_config_get(maps, "dns64", &obj);
4426	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
4427	    strcmp(view->name, "_meta"))
4428	{
4429		isc_netaddr_t na, suffix, *sp;
4430		unsigned int prefixlen;
4431		const char *server, *contact;
4432		const cfg_obj_t *myobj;
4433
4434		myobj = NULL;
4435		result = named_config_get(maps, "dns64-server", &myobj);
4436		if (result == ISC_R_SUCCESS) {
4437			server = cfg_obj_asstring(myobj);
4438		} else {
4439			server = NULL;
4440		}
4441
4442		myobj = NULL;
4443		result = named_config_get(maps, "dns64-contact", &myobj);
4444		if (result == ISC_R_SUCCESS) {
4445			contact = cfg_obj_asstring(myobj);
4446		} else {
4447			contact = NULL;
4448		}
4449
4450		for (element = cfg_list_first(obj); element != NULL;
4451		     element = cfg_list_next(element))
4452		{
4453			const cfg_obj_t *map = cfg_listelt_value(element);
4454			dns_dns64_t *dns64 = NULL;
4455			unsigned int dns64options = 0;
4456
4457			cfg_obj_asnetprefix(cfg_map_getname(map), &na,
4458					    &prefixlen);
4459
4460			obj = NULL;
4461			(void)cfg_map_get(map, "suffix", &obj);
4462			if (obj != NULL) {
4463				sp = &suffix;
4464				isc_netaddr_fromsockaddr(
4465					sp, cfg_obj_assockaddr(obj));
4466			} else {
4467				sp = NULL;
4468			}
4469
4470			clients = mapped = excluded = NULL;
4471			obj = NULL;
4472			(void)cfg_map_get(map, "clients", &obj);
4473			if (obj != NULL) {
4474				result = cfg_acl_fromconfig(obj, config,
4475							    named_g_lctx, actx,
4476							    mctx, 0, &clients);
4477				if (result != ISC_R_SUCCESS) {
4478					goto cleanup;
4479				}
4480			}
4481			obj = NULL;
4482			(void)cfg_map_get(map, "mapped", &obj);
4483			if (obj != NULL) {
4484				result = cfg_acl_fromconfig(obj, config,
4485							    named_g_lctx, actx,
4486							    mctx, 0, &mapped);
4487				if (result != ISC_R_SUCCESS) {
4488					goto cleanup;
4489				}
4490			}
4491			obj = NULL;
4492			(void)cfg_map_get(map, "exclude", &obj);
4493			if (obj != NULL) {
4494				result = cfg_acl_fromconfig(obj, config,
4495							    named_g_lctx, actx,
4496							    mctx, 0, &excluded);
4497				if (result != ISC_R_SUCCESS) {
4498					goto cleanup;
4499				}
4500			} else {
4501				if (named_g_mapped == NULL) {
4502					result = create_mapped_acl();
4503					if (result != ISC_R_SUCCESS) {
4504						goto cleanup;
4505					}
4506				}
4507				dns_acl_attach(named_g_mapped, &excluded);
4508			}
4509
4510			obj = NULL;
4511			(void)cfg_map_get(map, "recursive-only", &obj);
4512			if (obj != NULL && cfg_obj_asboolean(obj)) {
4513				dns64options |= DNS_DNS64_RECURSIVE_ONLY;
4514			}
4515
4516			obj = NULL;
4517			(void)cfg_map_get(map, "break-dnssec", &obj);
4518			if (obj != NULL && cfg_obj_asboolean(obj)) {
4519				dns64options |= DNS_DNS64_BREAK_DNSSEC;
4520			}
4521
4522			result = dns_dns64_create(mctx, &na, prefixlen, sp,
4523						  clients, mapped, excluded,
4524						  dns64options, &dns64);
4525			if (result != ISC_R_SUCCESS) {
4526				goto cleanup;
4527			}
4528			dns_dns64_append(&view->dns64, dns64);
4529			view->dns64cnt++;
4530			result = dns64_reverse(view, mctx, &na, prefixlen,
4531					       server, contact);
4532			if (result != ISC_R_SUCCESS) {
4533				goto cleanup;
4534			}
4535			if (clients != NULL) {
4536				dns_acl_detach(&clients);
4537			}
4538			if (mapped != NULL) {
4539				dns_acl_detach(&mapped);
4540			}
4541			if (excluded != NULL) {
4542				dns_acl_detach(&excluded);
4543			}
4544		}
4545	}
4546
4547	obj = NULL;
4548	result = named_config_get(maps, "dnssec-accept-expired", &obj);
4549	INSIST(result == ISC_R_SUCCESS);
4550	view->acceptexpired = cfg_obj_asboolean(obj);
4551
4552	obj = NULL;
4553	/* 'optionmaps', not 'maps': don't check named_g_defaults yet */
4554	(void)named_config_get(optionmaps, "dnssec-validation", &obj);
4555	if (obj == NULL) {
4556		/*
4557		 * Default to VALIDATION_DEFAULT as set in config.c.
4558		 */
4559		(void)cfg_map_get(named_g_defaults, "dnssec-validation", &obj);
4560		INSIST(obj != NULL);
4561	}
4562	if (obj != NULL) {
4563		if (cfg_obj_isboolean(obj)) {
4564			view->enablevalidation = cfg_obj_asboolean(obj);
4565		} else {
4566			/*
4567			 * If dnssec-validation is set but not boolean,
4568			 * then it must be "auto"
4569			 */
4570			view->enablevalidation = true;
4571			auto_root = true;
4572		}
4573	}
4574
4575	obj = NULL;
4576	result = named_config_get(maps, "max-cache-ttl", &obj);
4577	INSIST(result == ISC_R_SUCCESS);
4578	view->maxcachettl = cfg_obj_asduration(obj);
4579
4580	obj = NULL;
4581	result = named_config_get(maps, "max-ncache-ttl", &obj);
4582	INSIST(result == ISC_R_SUCCESS);
4583	view->maxncachettl = cfg_obj_asduration(obj);
4584
4585	obj = NULL;
4586	result = named_config_get(maps, "min-cache-ttl", &obj);
4587	INSIST(result == ISC_R_SUCCESS);
4588	view->mincachettl = cfg_obj_asduration(obj);
4589
4590	obj = NULL;
4591	result = named_config_get(maps, "min-ncache-ttl", &obj);
4592	INSIST(result == ISC_R_SUCCESS);
4593	view->minncachettl = cfg_obj_asduration(obj);
4594
4595	obj = NULL;
4596	result = named_config_get(maps, "synth-from-dnssec", &obj);
4597	INSIST(result == ISC_R_SUCCESS);
4598	view->synthfromdnssec = cfg_obj_asboolean(obj);
4599
4600	obj = NULL;
4601	result = named_config_get(maps, "stale-cache-enable", &obj);
4602	INSIST(result == ISC_R_SUCCESS);
4603	if (cfg_obj_asboolean(obj)) {
4604		obj = NULL;
4605		result = named_config_get(maps, "max-stale-ttl", &obj);
4606		INSIST(result == ISC_R_SUCCESS);
4607		max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4608	}
4609	/*
4610	 * If 'stale-cache-enable' is false, max_stale_ttl is set to 0,
4611	 * meaning keeping stale RRsets in cache is disabled.
4612	 */
4613
4614	obj = NULL;
4615	result = named_config_get(maps, "stale-answer-enable", &obj);
4616	INSIST(result == ISC_R_SUCCESS);
4617	view->staleanswersenable = cfg_obj_asboolean(obj);
4618
4619	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
4620				   view->rdclass, &pview);
4621	if (result == ISC_R_SUCCESS) {
4622		view->staleanswersok = pview->staleanswersok;
4623		dns_view_detach(&pview);
4624	} else {
4625		view->staleanswersok = dns_stale_answer_conf;
4626	}
4627
4628	obj = NULL;
4629	result = named_config_get(maps, "stale-answer-client-timeout", &obj);
4630	INSIST(result == ISC_R_SUCCESS);
4631	if (cfg_obj_isstring(obj)) {
4632		/*
4633		 * The only string values available for this option
4634		 * are "disabled" and "off".
4635		 * We use (uint32_t) -1 to represent disabled since
4636		 * a value of zero means that stale data can be used
4637		 * to promptly answer the query, while an attempt to
4638		 * refresh the RRset will still be made in background.
4639		 */
4640		view->staleanswerclienttimeout = (uint32_t)-1;
4641	} else {
4642		view->staleanswerclienttimeout = cfg_obj_asuint32(obj);
4643	}
4644
4645	obj = NULL;
4646	result = named_config_get(maps, "stale-refresh-time", &obj);
4647	INSIST(result == ISC_R_SUCCESS);
4648	stale_refresh_time = cfg_obj_asduration(obj);
4649
4650	/*
4651	 * Configure the view's cache.
4652	 *
4653	 * First, check to see if there are any attach-cache options.  If yes,
4654	 * attempt to lookup an existing cache at attach it to the view.  If
4655	 * there is not one, then try to reuse an existing cache if possible;
4656	 * otherwise create a new cache.
4657	 *
4658	 * Note that the ADB is not preserved or shared in either case.
4659	 *
4660	 * When a matching view is found, the associated statistics are also
4661	 * retrieved and reused.
4662	 *
4663	 * XXX Determining when it is safe to reuse or share a cache is tricky.
4664	 * When the view's configuration changes, the cached data may become
4665	 * invalid because it reflects our old view of the world.  We check
4666	 * some of the configuration parameters that could invalidate the cache
4667	 * or otherwise make it unshareable, but there are other configuration
4668	 * options that should be checked.  For example, if a view uses a
4669	 * forwarder, changes in the forwarder configuration may invalidate
4670	 * the cache.  At the moment, it's the administrator's responsibility to
4671	 * ensure these configuration options don't invalidate reusing/sharing.
4672	 */
4673	obj = NULL;
4674	result = named_config_get(maps, "attach-cache", &obj);
4675	if (result == ISC_R_SUCCESS) {
4676		cachename = cfg_obj_asstring(obj);
4677	} else {
4678		cachename = view->name;
4679	}
4680	cache = NULL;
4681	nsc = cachelist_find(cachelist, cachename, view->rdclass);
4682	if (nsc != NULL) {
4683		if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
4684				    max_cache_size, max_stale_ttl,
4685				    stale_refresh_time))
4686		{
4687			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4688				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4689				      "views %s and %s can't share the cache "
4690				      "due to configuration parameter mismatch",
4691				      nsc->primaryview->name, view->name);
4692			result = ISC_R_FAILURE;
4693			goto cleanup;
4694		}
4695		dns_cache_attach(nsc->cache, &cache);
4696		shared_cache = true;
4697	} else {
4698		if (strcmp(cachename, view->name) == 0) {
4699			result = dns_viewlist_find(&named_g_server->viewlist,
4700						   cachename, view->rdclass,
4701						   &pview);
4702			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4703			{
4704				goto cleanup;
4705			}
4706			if (pview != NULL) {
4707				if (!cache_reusable(pview, view,
4708						    zero_no_soattl))
4709				{
4710					isc_log_write(named_g_lctx,
4711						      NAMED_LOGCATEGORY_GENERAL,
4712						      NAMED_LOGMODULE_SERVER,
4713						      ISC_LOG_DEBUG(1),
4714						      "cache cannot be reused "
4715						      "for view %s due to "
4716						      "configuration parameter "
4717						      "mismatch",
4718						      view->name);
4719				} else {
4720					INSIST(pview->cache != NULL);
4721					isc_log_write(named_g_lctx,
4722						      NAMED_LOGCATEGORY_GENERAL,
4723						      NAMED_LOGMODULE_SERVER,
4724						      ISC_LOG_DEBUG(3),
4725						      "reusing existing cache");
4726					dns_cache_attach(pview->cache, &cache);
4727				}
4728				dns_view_getresstats(pview, &resstats);
4729				dns_view_getresquerystats(pview,
4730							  &resquerystats);
4731				dns_view_detach(&pview);
4732			}
4733		}
4734		if (cache == NULL) {
4735			/*
4736			 * Create a cache with the desired name.  This normally
4737			 * equals the view name, but may also be a forward
4738			 * reference to a view that share the cache with this
4739			 * view but is not yet configured.  If it is not the
4740			 * view name but not a forward reference either, then it
4741			 * is simply a named cache that is not shared.
4742			 *
4743			 * We use two separate memory contexts for the
4744			 * cache, for the main cache memory and the heap
4745			 * memory.
4746			 */
4747			isc_mem_create(&cmctx);
4748			isc_mem_setname(cmctx, "cache");
4749			isc_mem_create(&hmctx);
4750			isc_mem_setname(hmctx, "cache_heap");
4751			CHECK(dns_cache_create(cmctx, hmctx, named_g_taskmgr,
4752					       named_g_timermgr, view->rdclass,
4753					       cachename, "rbt", 0, NULL,
4754					       &cache));
4755			isc_mem_detach(&cmctx);
4756			isc_mem_detach(&hmctx);
4757		}
4758		nsc = isc_mem_get(mctx, sizeof(*nsc));
4759		nsc->cache = NULL;
4760		dns_cache_attach(cache, &nsc->cache);
4761		nsc->primaryview = view;
4762		nsc->needflush = false;
4763		nsc->adbsizeadjusted = false;
4764		nsc->rdclass = view->rdclass;
4765		ISC_LINK_INIT(nsc, link);
4766		ISC_LIST_APPEND(*cachelist, nsc, link);
4767	}
4768	dns_view_setcache(view, cache, shared_cache);
4769
4770	dns_cache_setcachesize(cache, max_cache_size);
4771	dns_cache_setservestalettl(cache, max_stale_ttl);
4772	dns_cache_setservestalerefresh(cache, stale_refresh_time);
4773
4774	dns_cache_detach(&cache);
4775
4776	obj = NULL;
4777	result = named_config_get(maps, "stale-answer-ttl", &obj);
4778	INSIST(result == ISC_R_SUCCESS);
4779	view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4780
4781	/*
4782	 * Resolver.
4783	 */
4784	CHECK(get_view_querysource_dispatch(
4785		maps, AF_INET, &dispatch4,
4786		(ISC_LIST_PREV(view, link) == NULL)));
4787	CHECK(get_view_querysource_dispatch(
4788		maps, AF_INET6, &dispatch6,
4789		(ISC_LIST_PREV(view, link) == NULL)));
4790	if (dispatch4 == NULL && dispatch6 == NULL) {
4791		UNEXPECTED_ERROR("unable to obtain either an IPv4 or"
4792				 " an IPv6 dispatch");
4793		result = ISC_R_UNEXPECTED;
4794		goto cleanup;
4795	}
4796
4797	if (resstats == NULL) {
4798		CHECK(isc_stats_create(mctx, &resstats,
4799				       dns_resstatscounter_max));
4800	}
4801	dns_view_setresstats(view, resstats);
4802	if (resquerystats == NULL) {
4803		CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
4804	}
4805	dns_view_setresquerystats(view, resquerystats);
4806
4807	ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH);
4808	CHECK(dns_view_createresolver(
4809		view, named_g_taskmgr, RESOLVER_NTASKS_PERCPU * named_g_cpus,
4810		ndisp, named_g_netmgr, named_g_timermgr, resopts,
4811		named_g_dispatchmgr, dispatch4, dispatch6));
4812
4813	/*
4814	 * Set the ADB cache size to 1/8th of the max-cache-size or
4815	 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
4816	 */
4817	max_adb_size = 0;
4818	if (max_cache_size != 0U) {
4819		max_adb_size = max_cache_size / 8;
4820		if (max_adb_size == 0U) {
4821			max_adb_size = 1; /* Force minimum. */
4822		}
4823		if (view != nsc->primaryview &&
4824		    max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE)
4825		{
4826			max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
4827			if (!nsc->adbsizeadjusted) {
4828				dns_adb_setadbsize(nsc->primaryview->adb,
4829						   MAX_ADB_SIZE_FOR_CACHESHARE);
4830				nsc->adbsizeadjusted = true;
4831			}
4832		}
4833	}
4834	dns_adb_setadbsize(view->adb, max_adb_size);
4835
4836	/*
4837	 * Set up ADB quotas
4838	 */
4839	{
4840		uint32_t fps, freq;
4841		double low, high, discount;
4842
4843		obj = NULL;
4844		result = named_config_get(maps, "fetches-per-server", &obj);
4845		INSIST(result == ISC_R_SUCCESS);
4846		obj2 = cfg_tuple_get(obj, "fetches");
4847		fps = cfg_obj_asuint32(obj2);
4848		obj2 = cfg_tuple_get(obj, "response");
4849		if (!cfg_obj_isvoid(obj2)) {
4850			const char *resp = cfg_obj_asstring(obj2);
4851			isc_result_t r = DNS_R_SERVFAIL;
4852
4853			if (strcasecmp(resp, "drop") == 0) {
4854				r = DNS_R_DROP;
4855			} else if (strcasecmp(resp, "fail") == 0) {
4856				r = DNS_R_SERVFAIL;
4857			} else {
4858				UNREACHABLE();
4859			}
4860
4861			dns_resolver_setquotaresponse(view->resolver,
4862						      dns_quotatype_server, r);
4863		}
4864
4865		obj = NULL;
4866		result = named_config_get(maps, "fetch-quota-params", &obj);
4867		INSIST(result == ISC_R_SUCCESS);
4868
4869		obj2 = cfg_tuple_get(obj, "frequency");
4870		freq = cfg_obj_asuint32(obj2);
4871
4872		obj2 = cfg_tuple_get(obj, "low");
4873		low = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4874
4875		obj2 = cfg_tuple_get(obj, "high");
4876		high = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4877
4878		obj2 = cfg_tuple_get(obj, "discount");
4879		discount = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4880
4881		dns_adb_setquota(view->adb, fps, freq, low, high, discount);
4882	}
4883
4884	/*
4885	 * Set resolver's lame-ttl.
4886	 */
4887	obj = NULL;
4888	result = named_config_get(maps, "lame-ttl", &obj);
4889	INSIST(result == ISC_R_SUCCESS);
4890	lame_ttl = cfg_obj_asduration(obj);
4891	if (lame_ttl > 0) {
4892		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4893			    "disabling lame cache despite lame-ttl > 0 as it "
4894			    "may cause performance issues");
4895		lame_ttl = 0;
4896	}
4897	dns_resolver_setlamettl(view->resolver, lame_ttl);
4898
4899	/*
4900	 * Set the resolver's query timeout.
4901	 */
4902	obj = NULL;
4903	result = named_config_get(maps, "resolver-query-timeout", &obj);
4904	INSIST(result == ISC_R_SUCCESS);
4905	query_timeout = cfg_obj_asuint32(obj);
4906	dns_resolver_settimeout(view->resolver, query_timeout);
4907
4908	/*
4909	 * Adjust stale-answer-client-timeout upper bound
4910	 * to be resolver-query-timeout - 1s.
4911	 * This assignment is safe as dns_resolver_settimeout()
4912	 * ensures that resolver->querytimeout value will be in the
4913	 * [MINIMUM_QUERY_TIMEOUT, MAXIMUM_QUERY_TIMEOUT] range and
4914	 * MINIMUM_QUERY_TIMEOUT is > 1000 (in ms).
4915	 */
4916	if (view->staleanswerclienttimeout != (uint32_t)-1 &&
4917	    view->staleanswerclienttimeout >
4918		    (dns_resolver_gettimeout(view->resolver) - 1000))
4919	{
4920		view->staleanswerclienttimeout =
4921			dns_resolver_gettimeout(view->resolver) - 1000;
4922		isc_log_write(
4923			named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4924			NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
4925			"stale-answer-client-timeout adjusted to %" PRIu32,
4926			view->staleanswerclienttimeout);
4927	}
4928
4929	/* Specify whether to use 0-TTL for negative response for SOA query */
4930	dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
4931
4932	/*
4933	 * Set the resolver's EDNS UDP size.
4934	 */
4935	obj = NULL;
4936	result = named_config_get(maps, "edns-udp-size", &obj);
4937	INSIST(result == ISC_R_SUCCESS);
4938	udpsize = cfg_obj_asuint32(obj);
4939	if (udpsize < 512) {
4940		udpsize = 512;
4941	}
4942	if (udpsize > 4096) {
4943		udpsize = 4096;
4944	}
4945	dns_resolver_setudpsize(view->resolver, (uint16_t)udpsize);
4946
4947	/*
4948	 * Set the maximum UDP response size.
4949	 */
4950	obj = NULL;
4951	result = named_config_get(maps, "max-udp-size", &obj);
4952	INSIST(result == ISC_R_SUCCESS);
4953	udpsize = cfg_obj_asuint32(obj);
4954	if (udpsize < 512) {
4955		udpsize = 512;
4956	}
4957	if (udpsize > 4096) {
4958		udpsize = 4096;
4959	}
4960	view->maxudp = udpsize;
4961
4962	/*
4963	 * Set the maximum UDP when a COOKIE is not provided.
4964	 */
4965	obj = NULL;
4966	result = named_config_get(maps, "nocookie-udp-size", &obj);
4967	INSIST(result == ISC_R_SUCCESS);
4968	udpsize = cfg_obj_asuint32(obj);
4969	if (udpsize < 128) {
4970		udpsize = 128;
4971	}
4972	if (udpsize > view->maxudp) {
4973		udpsize = view->maxudp;
4974	}
4975	view->nocookieudp = udpsize;
4976
4977	/*
4978	 * Set the maximum rsa exponent bits.
4979	 */
4980	obj = NULL;
4981	result = named_config_get(maps, "max-rsa-exponent-size", &obj);
4982	INSIST(result == ISC_R_SUCCESS);
4983	maxbits = cfg_obj_asuint32(obj);
4984	if (maxbits != 0 && maxbits < 35) {
4985		maxbits = 35;
4986	}
4987	if (maxbits > 4096) {
4988		maxbits = 4096;
4989	}
4990	view->maxbits = maxbits;
4991
4992	/*
4993	 * Set resolver retry parameters.
4994	 */
4995	obj = NULL;
4996	CHECK(named_config_get(maps, "resolver-retry-interval", &obj));
4997	resolver_param = cfg_obj_asuint32(obj);
4998	if (resolver_param > 0) {
4999		dns_resolver_setretryinterval(view->resolver, resolver_param);
5000	}
5001
5002	obj = NULL;
5003	CHECK(named_config_get(maps, "resolver-nonbackoff-tries", &obj));
5004	resolver_param = cfg_obj_asuint32(obj);
5005	if (resolver_param > 0) {
5006		dns_resolver_setnonbackofftries(view->resolver, resolver_param);
5007	}
5008
5009	/*
5010	 * Set supported DNSSEC algorithms.
5011	 */
5012	dns_resolver_reset_algorithms(view->resolver);
5013	disabled = NULL;
5014	(void)named_config_get(maps, "disable-algorithms", &disabled);
5015	if (disabled != NULL) {
5016		for (element = cfg_list_first(disabled); element != NULL;
5017		     element = cfg_list_next(element))
5018		{
5019			CHECK(disable_algorithms(cfg_listelt_value(element),
5020						 view->resolver));
5021		}
5022	}
5023
5024	/*
5025	 * Set supported DS digest types.
5026	 */
5027	dns_resolver_reset_ds_digests(view->resolver);
5028	disabled = NULL;
5029	(void)named_config_get(maps, "disable-ds-digests", &disabled);
5030	if (disabled != NULL) {
5031		for (element = cfg_list_first(disabled); element != NULL;
5032		     element = cfg_list_next(element))
5033		{
5034			CHECK(disable_ds_digests(cfg_listelt_value(element),
5035						 view->resolver));
5036		}
5037	}
5038
5039	/*
5040	 * A global or view "forwarders" option, if present,
5041	 * creates an entry for "." in the forwarding table.
5042	 */
5043	forwardtype = NULL;
5044	forwarders = NULL;
5045	(void)named_config_get(maps, "forward", &forwardtype);
5046	(void)named_config_get(maps, "forwarders", &forwarders);
5047	if (forwarders != NULL) {
5048		CHECK(configure_forward(config, view, dns_rootname, forwarders,
5049					forwardtype));
5050	}
5051
5052	/*
5053	 * Dual Stack Servers.
5054	 */
5055	alternates = NULL;
5056	(void)named_config_get(maps, "dual-stack-servers", &alternates);
5057	if (alternates != NULL) {
5058		CHECK(configure_alternates(config, view, alternates));
5059	}
5060
5061	/*
5062	 * We have default hints for class IN if we need them.
5063	 */
5064	if (view->rdclass == dns_rdataclass_in && view->hints == NULL) {
5065		dns_view_sethints(view, named_g_server->in_roothints);
5066	}
5067
5068	/*
5069	 * If we still have no hints, this is a non-IN view with no
5070	 * "hints zone" configured.  Issue a warning, except if this
5071	 * is a root server.  Root servers never need to consult
5072	 * their hints, so it's no point requiring users to configure
5073	 * them.
5074	 */
5075	if (view->hints == NULL) {
5076		dns_zone_t *rootzone = NULL;
5077		(void)dns_view_findzone(view, dns_rootname, &rootzone);
5078		if (rootzone != NULL) {
5079			dns_zone_detach(&rootzone);
5080			need_hints = false;
5081		}
5082		if (need_hints) {
5083			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
5084				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
5085				      "no root hints for view '%s'",
5086				      view->name);
5087		}
5088	}
5089
5090	/*
5091	 * Configure the view's transports (DoT/DoH)
5092	 */
5093	CHECK(named_transports_fromconfig(config, vconfig, view->mctx,
5094					  &transports));
5095	dns_view_settransports(view, transports);
5096	dns_transport_list_detach(&transports);
5097
5098	/*
5099	 * Configure the view's TSIG keys.
5100	 */
5101	CHECK(named_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
5102	if (named_g_server->sessionkey != NULL) {
5103		dns_tsigkey_t *tsigkey = NULL;
5104		result = dns_tsigkey_createfromkey(
5105			named_g_server->session_keyname,
5106			algorithm_name(named_g_server->session_keyalg),
5107			named_g_server->sessionkey, false, NULL, 0, 0, mctx,
5108			NULL, &tsigkey);
5109		if (result == ISC_R_SUCCESS) {
5110			result = dns_tsigkeyring_add(
5111				ring, named_g_server->session_keyname, tsigkey);
5112			dns_tsigkey_detach(&tsigkey);
5113		}
5114		CHECK(result);
5115	}
5116	dns_view_setkeyring(view, ring);
5117	dns_tsigkeyring_detach(&ring);
5118
5119	/*
5120	 * See if we can re-use a dynamic key ring.
5121	 */
5122	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
5123				   view->rdclass, &pview);
5124	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
5125		goto cleanup;
5126	}
5127	if (pview != NULL) {
5128		dns_view_getdynamickeyring(pview, &ring);
5129		if (ring != NULL) {
5130			dns_view_setdynamickeyring(view, ring);
5131		}
5132		dns_tsigkeyring_detach(&ring);
5133		dns_view_detach(&pview);
5134	} else {
5135		dns_view_restorekeyring(view);
5136	}
5137
5138	/*
5139	 * Configure the view's peer list.
5140	 */
5141	{
5142		const cfg_obj_t *peers = NULL;
5143		dns_peerlist_t *newpeers = NULL;
5144
5145		(void)named_config_get(cfgmaps, "server", &peers);
5146		CHECK(dns_peerlist_new(mctx, &newpeers));
5147		for (element = cfg_list_first(peers); element != NULL;
5148		     element = cfg_list_next(element))
5149		{
5150			const cfg_obj_t *cpeer = cfg_listelt_value(element);
5151			dns_peer_t *peer;
5152
5153			CHECK(configure_peer(cpeer, mctx, &peer));
5154			dns_peerlist_addpeer(newpeers, peer);
5155			dns_peer_detach(&peer);
5156		}
5157		dns_peerlist_detach(&view->peers);
5158		view->peers = newpeers; /* Transfer ownership. */
5159	}
5160
5161	/*
5162	 *	Configure the views rrset-order.
5163	 */
5164	{
5165		const cfg_obj_t *rrsetorder = NULL;
5166
5167		(void)named_config_get(maps, "rrset-order", &rrsetorder);
5168		CHECK(dns_order_create(mctx, &order));
5169		for (element = cfg_list_first(rrsetorder); element != NULL;
5170		     element = cfg_list_next(element))
5171		{
5172			const cfg_obj_t *ent = cfg_listelt_value(element);
5173
5174			CHECK(configure_order(order, ent));
5175		}
5176		if (view->order != NULL) {
5177			dns_order_detach(&view->order);
5178		}
5179		dns_order_attach(order, &view->order);
5180		dns_order_detach(&order);
5181	}
5182	/*
5183	 * Copy the aclenv object.
5184	 */
5185	dns_aclenv_copy(view->aclenv, ns_interfacemgr_getaclenv(
5186					      named_g_server->interfacemgr));
5187
5188	/*
5189	 * Configure the "match-clients" and "match-destinations" ACL.
5190	 * (These are only meaningful at the view level, but 'config'
5191	 * must be passed so that named ACLs defined at the global level
5192	 * can be retrieved.)
5193	 */
5194	CHECK(configure_view_acl(vconfig, config, NULL, "match-clients", NULL,
5195				 actx, named_g_mctx, &view->matchclients));
5196	CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations",
5197				 NULL, actx, named_g_mctx,
5198				 &view->matchdestinations));
5199
5200	/*
5201	 * Configure the "match-recursive-only" option.
5202	 */
5203	obj = NULL;
5204	(void)named_config_get(maps, "match-recursive-only", &obj);
5205	if (obj != NULL && cfg_obj_asboolean(obj)) {
5206		view->matchrecursiveonly = true;
5207	} else {
5208		view->matchrecursiveonly = false;
5209	}
5210
5211	/*
5212	 * Configure other configurable data.
5213	 */
5214	obj = NULL;
5215	result = named_config_get(maps, "recursion", &obj);
5216	INSIST(result == ISC_R_SUCCESS);
5217	view->recursion = cfg_obj_asboolean(obj);
5218
5219	obj = NULL;
5220	result = named_config_get(maps, "qname-minimization", &obj);
5221	INSIST(result == ISC_R_SUCCESS);
5222	qminmode = cfg_obj_asstring(obj);
5223	INSIST(qminmode != NULL);
5224	if (!strcmp(qminmode, "strict")) {
5225		view->qminimization = true;
5226		view->qmin_strict = true;
5227	} else if (!strcmp(qminmode, "relaxed")) {
5228		view->qminimization = true;
5229		view->qmin_strict = false;
5230	} else { /* "disabled" or "off" */
5231		view->qminimization = false;
5232		view->qmin_strict = false;
5233	}
5234
5235	obj = NULL;
5236	result = named_config_get(maps, "auth-nxdomain", &obj);
5237	INSIST(result == ISC_R_SUCCESS);
5238	view->auth_nxdomain = cfg_obj_asboolean(obj);
5239
5240	/* deprecated */
5241	obj = NULL;
5242	result = named_config_get(maps, "glue-cache", &obj);
5243	INSIST(result == ISC_R_SUCCESS);
5244	view->use_glue_cache = cfg_obj_asboolean(obj);
5245
5246	obj = NULL;
5247	result = named_config_get(maps, "minimal-any", &obj);
5248	INSIST(result == ISC_R_SUCCESS);
5249	view->minimal_any = cfg_obj_asboolean(obj);
5250
5251	obj = NULL;
5252	result = named_config_get(maps, "minimal-responses", &obj);
5253	INSIST(result == ISC_R_SUCCESS);
5254	if (cfg_obj_isboolean(obj)) {
5255		if (cfg_obj_asboolean(obj)) {
5256			view->minimalresponses = dns_minimal_yes;
5257		} else {
5258			view->minimalresponses = dns_minimal_no;
5259		}
5260	} else {
5261		str = cfg_obj_asstring(obj);
5262		if (strcasecmp(str, "no-auth") == 0) {
5263			view->minimalresponses = dns_minimal_noauth;
5264		} else if (strcasecmp(str, "no-auth-recursive") == 0) {
5265			view->minimalresponses = dns_minimal_noauthrec;
5266		} else {
5267			UNREACHABLE();
5268		}
5269	}
5270
5271	obj = NULL;
5272	result = named_config_get(maps, "transfer-format", &obj);
5273	INSIST(result == ISC_R_SUCCESS);
5274	str = cfg_obj_asstring(obj);
5275	if (strcasecmp(str, "many-answers") == 0) {
5276		view->transfer_format = dns_many_answers;
5277	} else if (strcasecmp(str, "one-answer") == 0) {
5278		view->transfer_format = dns_one_answer;
5279	} else {
5280		UNREACHABLE();
5281	}
5282
5283	obj = NULL;
5284	result = named_config_get(maps, "trust-anchor-telemetry", &obj);
5285	INSIST(result == ISC_R_SUCCESS);
5286	view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
5287
5288	obj = NULL;
5289	result = named_config_get(maps, "root-key-sentinel", &obj);
5290	INSIST(result == ISC_R_SUCCESS);
5291	view->root_key_sentinel = cfg_obj_asboolean(obj);
5292
5293	/*
5294	 * Set the "allow-query", "allow-query-cache", "allow-recursion",
5295	 * "allow-recursion-on" and "allow-query-cache-on" ACLs if
5296	 * configured in named.conf, but NOT from the global defaults.
5297	 * This is done by leaving the third argument to configure_view_acl()
5298	 * NULL.
5299	 *
5300	 * We ignore the global defaults here because these ACLs
5301	 * can inherit from each other.  If any are still unset after
5302	 * applying the inheritance rules, we'll look up the defaults at
5303	 * that time.
5304	 */
5305
5306	/* named.conf only */
5307	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query", NULL,
5308				 actx, named_g_mctx, &view->queryacl));
5309
5310	/* named.conf only */
5311	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache",
5312				 NULL, actx, named_g_mctx, &view->cacheacl));
5313	/* named.conf only */
5314	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
5315				 NULL, actx, named_g_mctx, &view->cacheonacl));
5316
5317	if (strcmp(view->name, "_bind") != 0 &&
5318	    view->rdclass != dns_rdataclass_chaos)
5319	{
5320		/* named.conf only */
5321		CHECK(configure_view_acl(vconfig, config, NULL,
5322					 "allow-recursion", NULL, actx,
5323					 named_g_mctx, &view->recursionacl));
5324		/* named.conf only */
5325		CHECK(configure_view_acl(vconfig, config, NULL,
5326					 "allow-recursion-on", NULL, actx,
5327					 named_g_mctx, &view->recursiononacl));
5328	}
5329
5330	if (view->recursion) {
5331		/*
5332		 * "allow-query-cache" inherits from "allow-recursion" if set,
5333		 * otherwise from "allow-query" if set.
5334		 */
5335		if (view->cacheacl == NULL) {
5336			if (view->recursionacl != NULL) {
5337				dns_acl_attach(view->recursionacl,
5338					       &view->cacheacl);
5339			} else if (view->queryacl != NULL) {
5340				dns_acl_attach(view->queryacl, &view->cacheacl);
5341			}
5342		}
5343
5344		/*
5345		 * "allow-recursion" inherits from "allow-query-cache" if set,
5346		 * otherwise from "allow-query" if set.
5347		 */
5348		if (view->recursionacl == NULL) {
5349			if (view->cacheacl != NULL) {
5350				dns_acl_attach(view->cacheacl,
5351					       &view->recursionacl);
5352			} else if (view->queryacl != NULL) {
5353				dns_acl_attach(view->queryacl,
5354					       &view->recursionacl);
5355			}
5356		}
5357
5358		/*
5359		 * "allow-query-cache-on" inherits from "allow-recursion-on"
5360		 * if set.
5361		 */
5362		if (view->cacheonacl == NULL) {
5363			if (view->recursiononacl != NULL) {
5364				dns_acl_attach(view->recursiononacl,
5365					       &view->cacheonacl);
5366			}
5367		}
5368
5369		/*
5370		 * "allow-recursion-on" inherits from "allow-query-cache-on"
5371		 * if set.
5372		 */
5373		if (view->recursiononacl == NULL) {
5374			if (view->cacheonacl != NULL) {
5375				dns_acl_attach(view->cacheonacl,
5376					       &view->recursiononacl);
5377			}
5378		}
5379
5380		/*
5381		 * If any are still unset at this point, we now get default
5382		 * values for from the global config.
5383		 */
5384
5385		if (view->recursionacl == NULL) {
5386			/* global default only */
5387			CHECK(configure_view_acl(
5388				NULL, NULL, named_g_config, "allow-recursion",
5389				NULL, actx, named_g_mctx, &view->recursionacl));
5390		}
5391		if (view->recursiononacl == NULL) {
5392			/* global default only */
5393			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5394						 "allow-recursion-on", NULL,
5395						 actx, named_g_mctx,
5396						 &view->recursiononacl));
5397		}
5398		if (view->cacheacl == NULL) {
5399			/* global default only */
5400			CHECK(configure_view_acl(
5401				NULL, NULL, named_g_config, "allow-query-cache",
5402				NULL, actx, named_g_mctx, &view->cacheacl));
5403		}
5404		if (view->cacheonacl == NULL) {
5405			/* global default only */
5406			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5407						 "allow-query-cache-on", NULL,
5408						 actx, named_g_mctx,
5409						 &view->cacheonacl));
5410		}
5411	} else {
5412		/*
5413		 * We're not recursive; if the query-cache ACLs haven't
5414		 * been set at the options/view level, set them to none.
5415		 */
5416		if (view->cacheacl == NULL) {
5417			CHECK(dns_acl_none(mctx, &view->cacheacl));
5418		}
5419		if (view->cacheonacl == NULL) {
5420			CHECK(dns_acl_none(mctx, &view->cacheonacl));
5421		}
5422	}
5423
5424	/*
5425	 * Finished setting recursion and query-cache ACLs, so now we
5426	 * can get the allow-query default if it wasn't set in named.conf
5427	 */
5428	if (view->queryacl == NULL) {
5429		/* global default only */
5430		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5431					 "allow-query", NULL, actx,
5432					 named_g_mctx, &view->queryacl));
5433	}
5434
5435	/*
5436	 * Ignore case when compressing responses to the specified
5437	 * clients. This causes case not always to be preserved,
5438	 * and is needed by some broken clients.
5439	 */
5440	CHECK(configure_view_acl(vconfig, config, named_g_config,
5441				 "no-case-compress", NULL, actx, named_g_mctx,
5442				 &view->nocasecompress));
5443
5444	/*
5445	 * Disable name compression completely, this is a tradeoff
5446	 * between CPU and network usage.
5447	 */
5448	obj = NULL;
5449	result = named_config_get(maps, "message-compression", &obj);
5450	INSIST(result == ISC_R_SUCCESS);
5451	view->msgcompression = cfg_obj_asboolean(obj);
5452
5453	/*
5454	 * Filter setting on addresses in the answer section.
5455	 */
5456	CHECK(configure_view_acl(vconfig, config, named_g_config,
5457				 "deny-answer-addresses", "acl", actx,
5458				 named_g_mctx, &view->denyansweracl));
5459	CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
5460				       "except-from", named_g_mctx,
5461				       &view->answeracl_exclude));
5462
5463	/*
5464	 * Filter setting on names (CNAME/DNAME targets) in the answer section.
5465	 */
5466	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5467				       "name", named_g_mctx,
5468				       &view->denyanswernames));
5469	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5470				       "except-from", named_g_mctx,
5471				       &view->answernames_exclude));
5472
5473	/*
5474	 * Configure sortlist, if set
5475	 */
5476	CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx,
5477				      &view->sortlist));
5478
5479	/*
5480	 * Configure default allow-update and allow-update-forwarding ACLs,
5481	 * so they can be inherited by zones. (XXX: These are not
5482	 * read from the options/view level here. However, they may be
5483	 * read from there in zoneconf.c:configure_zone_acl() later.)
5484	 */
5485	if (view->updateacl == NULL) {
5486		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5487					 "allow-update", NULL, actx,
5488					 named_g_mctx, &view->updateacl));
5489	}
5490	if (view->upfwdacl == NULL) {
5491		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5492					 "allow-update-forwarding", NULL, actx,
5493					 named_g_mctx, &view->upfwdacl));
5494	}
5495
5496	/*
5497	 * Configure default allow-transfer and allow-notify ACLs so they
5498	 * can be inherited by zones.
5499	 */
5500	if (view->transferacl == NULL) {
5501		CHECK(configure_view_acl(vconfig, config, named_g_config,
5502					 "allow-transfer", NULL, actx,
5503					 named_g_mctx, &view->transferacl));
5504	}
5505	if (view->notifyacl == NULL) {
5506		CHECK(configure_view_acl(vconfig, config, named_g_config,
5507					 "allow-notify", NULL, actx,
5508					 named_g_mctx, &view->notifyacl));
5509	}
5510
5511	obj = NULL;
5512	result = named_config_get(maps, "provide-ixfr", &obj);
5513	INSIST(result == ISC_R_SUCCESS);
5514	view->provideixfr = cfg_obj_asboolean(obj);
5515
5516	obj = NULL;
5517	result = named_config_get(maps, "request-nsid", &obj);
5518	INSIST(result == ISC_R_SUCCESS);
5519	view->requestnsid = cfg_obj_asboolean(obj);
5520
5521	obj = NULL;
5522	result = named_config_get(maps, "send-cookie", &obj);
5523	INSIST(result == ISC_R_SUCCESS);
5524	view->sendcookie = cfg_obj_asboolean(obj);
5525
5526	obj = NULL;
5527	if (view->pad_acl != NULL) {
5528		dns_acl_detach(&view->pad_acl);
5529	}
5530	result = named_config_get(optionmaps, "response-padding", &obj);
5531	if (result == ISC_R_SUCCESS) {
5532		const cfg_obj_t *padobj = cfg_tuple_get(obj, "block-size");
5533		const cfg_obj_t *aclobj = cfg_tuple_get(obj, "acl");
5534		uint32_t padding = cfg_obj_asuint32(padobj);
5535
5536		if (padding > 512U) {
5537			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
5538				    "response-padding block-size cannot "
5539				    "exceed 512: lowering");
5540			padding = 512U;
5541		}
5542		view->padding = (uint16_t)padding;
5543		CHECK(cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx,
5544					 named_g_mctx, 0, &view->pad_acl));
5545	}
5546
5547	obj = NULL;
5548	result = named_config_get(maps, "require-server-cookie", &obj);
5549	INSIST(result == ISC_R_SUCCESS);
5550	view->requireservercookie = cfg_obj_asboolean(obj);
5551
5552	obj = NULL;
5553	result = named_config_get(maps, "v6-bias", &obj);
5554	INSIST(result == ISC_R_SUCCESS);
5555	view->v6bias = cfg_obj_asuint32(obj) * 1000;
5556
5557	obj = NULL;
5558	result = named_config_get(maps, "max-clients-per-query", &obj);
5559	INSIST(result == ISC_R_SUCCESS);
5560	max_clients_per_query = cfg_obj_asuint32(obj);
5561
5562	obj = NULL;
5563	result = named_config_get(maps, "clients-per-query", &obj);
5564	INSIST(result == ISC_R_SUCCESS);
5565	dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj),
5566					max_clients_per_query);
5567
5568	obj = NULL;
5569	result = named_config_get(maps, "max-recursion-depth", &obj);
5570	INSIST(result == ISC_R_SUCCESS);
5571	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
5572
5573	obj = NULL;
5574	result = named_config_get(maps, "max-recursion-queries", &obj);
5575	INSIST(result == ISC_R_SUCCESS);
5576	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
5577
5578	obj = NULL;
5579	result = named_config_get(maps, "fetches-per-zone", &obj);
5580	INSIST(result == ISC_R_SUCCESS);
5581	obj2 = cfg_tuple_get(obj, "fetches");
5582	dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
5583	obj2 = cfg_tuple_get(obj, "response");
5584	if (!cfg_obj_isvoid(obj2)) {
5585		const char *resp = cfg_obj_asstring(obj2);
5586		isc_result_t r = DNS_R_SERVFAIL;
5587
5588		if (strcasecmp(resp, "drop") == 0) {
5589			r = DNS_R_DROP;
5590		} else if (strcasecmp(resp, "fail") == 0) {
5591			r = DNS_R_SERVFAIL;
5592		} else {
5593			UNREACHABLE();
5594		}
5595
5596		dns_resolver_setquotaresponse(view->resolver,
5597					      dns_quotatype_zone, r);
5598	}
5599
5600	obj = NULL;
5601	result = named_config_get(maps, "prefetch", &obj);
5602	INSIST(result == ISC_R_SUCCESS);
5603	prefetch_trigger = cfg_tuple_get(obj, "trigger");
5604	view->prefetch_trigger = cfg_obj_asuint32(prefetch_trigger);
5605	if (view->prefetch_trigger > 10) {
5606		view->prefetch_trigger = 10;
5607	}
5608	prefetch_eligible = cfg_tuple_get(obj, "eligible");
5609	if (cfg_obj_isvoid(prefetch_eligible)) {
5610		int m;
5611		for (m = 1; maps[m] != NULL; m++) {
5612			obj = NULL;
5613			result = named_config_get(&maps[m], "prefetch", &obj);
5614			INSIST(result == ISC_R_SUCCESS);
5615			prefetch_eligible = cfg_tuple_get(obj, "eligible");
5616			if (cfg_obj_isuint32(prefetch_eligible)) {
5617				break;
5618			}
5619		}
5620		INSIST(cfg_obj_isuint32(prefetch_eligible));
5621	}
5622	view->prefetch_eligible = cfg_obj_asuint32(prefetch_eligible);
5623	if (view->prefetch_eligible < view->prefetch_trigger + 6) {
5624		view->prefetch_eligible = view->prefetch_trigger + 6;
5625	}
5626
5627	/*
5628	 * For now, there is only one kind of trusted keys, the
5629	 * "security roots".
5630	 */
5631	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
5632					auto_root, mctx));
5633	dns_resolver_resetmustbesecure(view->resolver);
5634	obj = NULL;
5635	result = named_config_get(maps, "dnssec-must-be-secure", &obj);
5636	if (result == ISC_R_SUCCESS) {
5637		CHECK(mustbesecure(obj, view->resolver));
5638	}
5639
5640	obj = NULL;
5641	result = named_config_get(maps, "nta-recheck", &obj);
5642	INSIST(result == ISC_R_SUCCESS);
5643	view->nta_recheck = cfg_obj_asduration(obj);
5644
5645	obj = NULL;
5646	result = named_config_get(maps, "nta-lifetime", &obj);
5647	INSIST(result == ISC_R_SUCCESS);
5648	view->nta_lifetime = cfg_obj_asduration(obj);
5649
5650	obj = NULL;
5651	result = named_config_get(maps, "preferred-glue", &obj);
5652	if (result == ISC_R_SUCCESS) {
5653		str = cfg_obj_asstring(obj);
5654		if (strcasecmp(str, "a") == 0) {
5655			view->preferred_glue = dns_rdatatype_a;
5656		} else if (strcasecmp(str, "aaaa") == 0) {
5657			view->preferred_glue = dns_rdatatype_aaaa;
5658		} else {
5659			view->preferred_glue = 0;
5660		}
5661	} else {
5662		view->preferred_glue = 0;
5663	}
5664
5665	obj = NULL;
5666	result = named_config_get(maps, "root-delegation-only", &obj);
5667	if (result == ISC_R_SUCCESS) {
5668		dns_view_setrootdelonly(view, true);
5669	}
5670	if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
5671		const cfg_obj_t *exclude;
5672		dns_fixedname_t fixed;
5673		dns_name_t *name;
5674
5675		name = dns_fixedname_initname(&fixed);
5676		for (element = cfg_list_first(obj); element != NULL;
5677		     element = cfg_list_next(element))
5678		{
5679			exclude = cfg_listelt_value(element);
5680			CHECK(dns_name_fromstring(
5681				name, cfg_obj_asstring(exclude), 0, NULL));
5682			dns_view_excludedelegationonly(view, name);
5683		}
5684	} else {
5685		dns_view_setrootdelonly(view, false);
5686	}
5687
5688	/*
5689	 * Load DynDB modules.
5690	 */
5691	dyndb_list = NULL;
5692	if (voptions != NULL) {
5693		(void)cfg_map_get(voptions, "dyndb", &dyndb_list);
5694	} else {
5695		(void)cfg_map_get(config, "dyndb", &dyndb_list);
5696	}
5697
5698	for (element = cfg_list_first(dyndb_list); element != NULL;
5699	     element = cfg_list_next(element))
5700	{
5701		const cfg_obj_t *dyndb = cfg_listelt_value(element);
5702
5703		if (dctx == NULL) {
5704			const void *hashinit = isc_hash_get_initializer();
5705			CHECK(dns_dyndb_createctx(mctx, hashinit, named_g_lctx,
5706						  view, named_g_server->zonemgr,
5707						  named_g_server->task,
5708						  named_g_timermgr, &dctx));
5709		}
5710
5711		CHECK(configure_dyndb(dyndb, mctx, dctx));
5712	}
5713
5714	/*
5715	 * Load plugins.
5716	 */
5717	plugin_list = NULL;
5718	if (voptions != NULL) {
5719		(void)cfg_map_get(voptions, "plugin", &plugin_list);
5720	} else {
5721		(void)cfg_map_get(config, "plugin", &plugin_list);
5722	}
5723
5724	if (plugin_list != NULL) {
5725		INSIST(view->hooktable == NULL);
5726		CHECK(ns_hooktable_create(view->mctx,
5727					  (ns_hooktable_t **)&view->hooktable));
5728		view->hooktable_free = ns_hooktable_free;
5729
5730		ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
5731		view->plugins_free = ns_plugins_free;
5732
5733		CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
5734					     register_one_plugin, view));
5735	}
5736
5737	/*
5738	 * Setup automatic empty zones.  If recursion is off then
5739	 * they are disabled by default.
5740	 */
5741	obj = NULL;
5742	(void)named_config_get(maps, "empty-zones-enable", &obj);
5743	(void)named_config_get(maps, "disable-empty-zone", &disablelist);
5744	if (obj == NULL && disablelist == NULL &&
5745	    view->rdclass == dns_rdataclass_in)
5746	{
5747		empty_zones_enable = view->recursion;
5748	} else if (view->rdclass == dns_rdataclass_in) {
5749		if (obj != NULL) {
5750			empty_zones_enable = cfg_obj_asboolean(obj);
5751		} else {
5752			empty_zones_enable = view->recursion;
5753		}
5754	} else {
5755		empty_zones_enable = false;
5756	}
5757
5758	if (empty_zones_enable) {
5759		const char *empty;
5760		int empty_zone = 0;
5761		dns_fixedname_t fixed;
5762		dns_name_t *name;
5763		isc_buffer_t buffer;
5764		char server[DNS_NAME_FORMATSIZE + 1];
5765		char contact[DNS_NAME_FORMATSIZE + 1];
5766		const char *empty_dbtype[4] = { "_builtin", "empty", NULL,
5767						NULL };
5768		int empty_dbtypec = 4;
5769		dns_zonestat_level_t statlevel = dns_zonestat_none;
5770
5771		name = dns_fixedname_initname(&fixed);
5772
5773		obj = NULL;
5774		result = named_config_get(maps, "empty-server", &obj);
5775		if (result == ISC_R_SUCCESS) {
5776			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5777						  0, NULL));
5778			isc_buffer_init(&buffer, server, sizeof(server) - 1);
5779			CHECK(dns_name_totext(name, false, &buffer));
5780			server[isc_buffer_usedlength(&buffer)] = 0;
5781			empty_dbtype[2] = server;
5782		} else {
5783			empty_dbtype[2] = "@";
5784		}
5785
5786		obj = NULL;
5787		result = named_config_get(maps, "empty-contact", &obj);
5788		if (result == ISC_R_SUCCESS) {
5789			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5790						  0, NULL));
5791			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
5792			CHECK(dns_name_totext(name, false, &buffer));
5793			contact[isc_buffer_usedlength(&buffer)] = 0;
5794			empty_dbtype[3] = contact;
5795		} else {
5796			empty_dbtype[3] = ".";
5797		}
5798
5799		obj = NULL;
5800		result = named_config_get(maps, "zone-statistics", &obj);
5801		INSIST(result == ISC_R_SUCCESS);
5802		if (cfg_obj_isboolean(obj)) {
5803			if (cfg_obj_asboolean(obj)) {
5804				statlevel = dns_zonestat_full;
5805			} else {
5806				statlevel = dns_zonestat_none;
5807			}
5808		} else {
5809			const char *levelstr = cfg_obj_asstring(obj);
5810			if (strcasecmp(levelstr, "full") == 0) {
5811				statlevel = dns_zonestat_full;
5812			} else if (strcasecmp(levelstr, "terse") == 0) {
5813				statlevel = dns_zonestat_terse;
5814			} else if (strcasecmp(levelstr, "none") == 0) {
5815				statlevel = dns_zonestat_none;
5816			} else {
5817				UNREACHABLE();
5818			}
5819		}
5820
5821		for (empty = empty_zones[empty_zone]; empty != NULL;
5822		     empty = empty_zones[++empty_zone])
5823		{
5824			dns_forwarders_t *dnsforwarders = NULL;
5825
5826			/*
5827			 * Look for zone on drop list.
5828			 */
5829			CHECK(dns_name_fromstring(name, empty, 0, NULL));
5830			if (disablelist != NULL &&
5831			    on_disable_list(disablelist, name))
5832			{
5833				continue;
5834			}
5835
5836			/*
5837			 * This zone already exists.
5838			 */
5839			(void)dns_view_findzone(view, name, &zone);
5840			if (zone != NULL) {
5841				dns_zone_detach(&zone);
5842				continue;
5843			}
5844
5845			/*
5846			 * If we would forward this name don't add a
5847			 * empty zone for it.
5848			 */
5849			result = dns_fwdtable_find(view->fwdtable, name, NULL,
5850						   &dnsforwarders);
5851			if ((result == ISC_R_SUCCESS ||
5852			     result == DNS_R_PARTIALMATCH) &&
5853			    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
5854			{
5855				continue;
5856			}
5857
5858			/*
5859			 * See if we can re-use a existing zone.
5860			 */
5861			result = dns_viewlist_find(&named_g_server->viewlist,
5862						   view->name, view->rdclass,
5863						   &pview);
5864			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
5865			{
5866				goto cleanup;
5867			}
5868
5869			if (pview != NULL) {
5870				(void)dns_view_findzone(pview, name, &zone);
5871				dns_view_detach(&pview);
5872			}
5873
5874			CHECK(create_empty_zone(zone, name, view, zonelist,
5875						empty_dbtype, empty_dbtypec,
5876						statlevel));
5877			if (zone != NULL) {
5878				dns_zone_detach(&zone);
5879			}
5880		}
5881	}
5882
5883	obj = NULL;
5884	if (view->rdclass == dns_rdataclass_in) {
5885		(void)named_config_get(maps, "ipv4only-enable", &obj);
5886	}
5887	if (view->rdclass == dns_rdataclass_in && (obj != NULL)
5888		    ? cfg_obj_asboolean(obj)
5889		    : !ISC_LIST_EMPTY(view->dns64))
5890	{
5891		const char *server, *contact;
5892		dns_fixedname_t fixed;
5893		dns_name_t *name;
5894		struct {
5895			const char *name;
5896			const char *type;
5897		} zones[] = {
5898			{ "ipv4only.arpa", "ipv4only" },
5899			{ "170.0.0.192.in-addr.arpa", "ipv4reverse" },
5900			{ "171.0.0.192.in-addr.arpa", "ipv4reverse" },
5901		};
5902		size_t ipv4only_zone;
5903
5904		obj = NULL;
5905		result = named_config_get(maps, "ipv4only-server", &obj);
5906		if (result == ISC_R_SUCCESS) {
5907			server = cfg_obj_asstring(obj);
5908		} else {
5909			server = NULL;
5910		}
5911
5912		obj = NULL;
5913		result = named_config_get(maps, "ipv4only-contact", &obj);
5914		if (result == ISC_R_SUCCESS) {
5915			contact = cfg_obj_asstring(obj);
5916		} else {
5917			contact = NULL;
5918		}
5919
5920		name = dns_fixedname_initname(&fixed);
5921		for (ipv4only_zone = 0; ipv4only_zone < ARRAY_SIZE(zones);
5922		     ipv4only_zone++)
5923		{
5924			dns_forwarders_t *dnsforwarders = NULL;
5925
5926			CHECK(dns_name_fromstring(
5927				name, zones[ipv4only_zone].name, 0, NULL));
5928
5929			(void)dns_view_findzone(view, name, &zone);
5930			if (zone != NULL) {
5931				dns_zone_detach(&zone);
5932				continue;
5933			}
5934
5935			/*
5936			 * If we would forward this name don't add it.
5937			 */
5938			result = dns_fwdtable_find(view->fwdtable, name, NULL,
5939						   &dnsforwarders);
5940			if ((result == ISC_R_SUCCESS ||
5941			     result == DNS_R_PARTIALMATCH) &&
5942			    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
5943			{
5944				continue;
5945			}
5946
5947			/*
5948			 * See if we can re-use a existing zone.
5949			 */
5950			result = dns_viewlist_find(&named_g_server->viewlist,
5951						   view->name, view->rdclass,
5952						   &pview);
5953			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
5954			{
5955				goto cleanup;
5956			}
5957
5958			if (pview != NULL) {
5959				(void)dns_view_findzone(pview, name, &zone);
5960				dns_view_detach(&pview);
5961			}
5962
5963			CHECK(create_ipv4only_zone(zone, view, name,
5964						   zones[ipv4only_zone].type,
5965						   mctx, server, contact));
5966			if (zone != NULL) {
5967				dns_zone_detach(&zone);
5968			}
5969		}
5970	}
5971
5972	obj = NULL;
5973	result = named_config_get(maps, "rate-limit", &obj);
5974	if (result == ISC_R_SUCCESS) {
5975		result = configure_rrl(view, config, obj);
5976		if (result != ISC_R_SUCCESS) {
5977			goto cleanup;
5978		}
5979	}
5980
5981	/*
5982	 * Set the servfail-ttl.
5983	 */
5984	obj = NULL;
5985	result = named_config_get(maps, "servfail-ttl", &obj);
5986	INSIST(result == ISC_R_SUCCESS);
5987	fail_ttl = cfg_obj_asduration(obj);
5988	if (fail_ttl > 30) {
5989		fail_ttl = 30;
5990	}
5991	dns_view_setfailttl(view, fail_ttl);
5992
5993	/*
5994	 * Name space to look up redirect information in.
5995	 */
5996	obj = NULL;
5997	result = named_config_get(maps, "nxdomain-redirect", &obj);
5998	if (result == ISC_R_SUCCESS) {
5999		dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
6000		CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0,
6001					  NULL));
6002		view->redirectzone = name;
6003	} else {
6004		view->redirectzone = NULL;
6005	}
6006
6007	/*
6008	 * Exceptions to DNSSEC validation.
6009	 */
6010	obj = NULL;
6011	result = named_config_get(maps, "validate-except", &obj);
6012	if (result == ISC_R_SUCCESS) {
6013		result = dns_view_getntatable(view, &ntatable);
6014	}
6015	if (result == ISC_R_SUCCESS) {
6016		for (element = cfg_list_first(obj); element != NULL;
6017		     element = cfg_list_next(element))
6018		{
6019			dns_fixedname_t fntaname;
6020			dns_name_t *ntaname;
6021
6022			ntaname = dns_fixedname_initname(&fntaname);
6023			obj = cfg_listelt_value(element);
6024			CHECK(dns_name_fromstring(
6025				ntaname, cfg_obj_asstring(obj), 0, NULL));
6026			CHECK(dns_ntatable_add(ntatable, ntaname, true, 0,
6027					       0xffffffffU));
6028		}
6029	}
6030
6031#ifdef HAVE_DNSTAP
6032	/*
6033	 * Set up the dnstap environment and configure message
6034	 * types to log.
6035	 */
6036	CHECK(configure_dnstap(maps, view));
6037#endif /* HAVE_DNSTAP */
6038
6039	result = ISC_R_SUCCESS;
6040
6041cleanup:
6042	/*
6043	 * Revert to the old view if there was an error.
6044	 */
6045	if (result != ISC_R_SUCCESS) {
6046		isc_result_t result2;
6047
6048		result2 = dns_viewlist_find(&named_g_server->viewlist,
6049					    view->name, view->rdclass, &pview);
6050		if (result2 == ISC_R_SUCCESS) {
6051			dns_view_thaw(pview);
6052
6053			obj = NULL;
6054			if (rpz_configured &&
6055			    pview->rdclass == dns_rdataclass_in && need_hints &&
6056			    named_config_get(maps, "response-policy", &obj) ==
6057				    ISC_R_SUCCESS)
6058			{
6059				/*
6060				 * We are swapping the places of the `view` and
6061				 * `pview` in the function's parameters list
6062				 * because we are reverting the same operation
6063				 * done previously in the "correct" order.
6064				 */
6065				result2 = configure_rpz(pview, view, maps, obj,
6066							&old_rpz_ok);
6067				if (result2 != ISC_R_SUCCESS) {
6068					isc_log_write(named_g_lctx,
6069						      NAMED_LOGCATEGORY_GENERAL,
6070						      NAMED_LOGMODULE_SERVER,
6071						      ISC_LOG_ERROR,
6072						      "rpz configuration "
6073						      "revert failed for view "
6074						      "'%s'",
6075						      pview->name);
6076				}
6077			}
6078
6079			obj = NULL;
6080			if (catz_configured &&
6081			    pview->rdclass == dns_rdataclass_in && need_hints &&
6082			    named_config_get(maps, "catalog-zones", &obj) ==
6083				    ISC_R_SUCCESS)
6084			{
6085				/*
6086				 * We are swapping the places of the `view` and
6087				 * `pview` in the function's parameters list
6088				 * because we are reverting the same operation
6089				 * done previously in the "correct" order.
6090				 */
6091				result2 = configure_catz(pview, view, config,
6092							 obj);
6093				if (result2 != ISC_R_SUCCESS) {
6094					isc_log_write(named_g_lctx,
6095						      NAMED_LOGCATEGORY_GENERAL,
6096						      NAMED_LOGMODULE_SERVER,
6097						      ISC_LOG_ERROR,
6098						      "catz configuration "
6099						      "revert failed for view "
6100						      "'%s'",
6101						      pview->name);
6102				}
6103			}
6104
6105			dns_view_freeze(pview);
6106		}
6107
6108		if (pview != NULL) {
6109			dns_view_detach(&pview);
6110		}
6111
6112		if (zone_element_latest != NULL) {
6113			for (element = cfg_list_first(zonelist);
6114			     element != NULL; element = cfg_list_next(element))
6115			{
6116				const cfg_obj_t *zconfig =
6117					cfg_listelt_value(element);
6118				configure_zone_setviewcommit(result, zconfig,
6119							     view);
6120				if (element == zone_element_latest) {
6121					/*
6122					 * This was the latest element that was
6123					 * successfully configured earlier.
6124					 */
6125					break;
6126				}
6127			}
6128		}
6129	}
6130
6131	if (ntatable != NULL) {
6132		dns_ntatable_detach(&ntatable);
6133	}
6134	if (clients != NULL) {
6135		dns_acl_detach(&clients);
6136	}
6137	if (mapped != NULL) {
6138		dns_acl_detach(&mapped);
6139	}
6140	if (excluded != NULL) {
6141		dns_acl_detach(&excluded);
6142	}
6143	if (ring != NULL) {
6144		dns_tsigkeyring_detach(&ring);
6145	}
6146	if (zone != NULL) {
6147		dns_zone_detach(&zone);
6148	}
6149	if (dispatch4 != NULL) {
6150		dns_dispatch_detach(&dispatch4);
6151	}
6152	if (dispatch6 != NULL) {
6153		dns_dispatch_detach(&dispatch6);
6154	}
6155	if (resstats != NULL) {
6156		isc_stats_detach(&resstats);
6157	}
6158	if (resquerystats != NULL) {
6159		dns_stats_detach(&resquerystats);
6160	}
6161	if (order != NULL) {
6162		dns_order_detach(&order);
6163	}
6164	if (cmctx != NULL) {
6165		isc_mem_detach(&cmctx);
6166	}
6167	if (hmctx != NULL) {
6168		isc_mem_detach(&hmctx);
6169	}
6170	if (cache != NULL) {
6171		dns_cache_detach(&cache);
6172	}
6173	if (dctx != NULL) {
6174		dns_dyndb_destroyctx(&dctx);
6175	}
6176
6177	return (result);
6178}
6179
6180static isc_result_t
6181configure_hints(dns_view_t *view, const char *filename) {
6182	isc_result_t result;
6183	dns_db_t *db;
6184
6185	db = NULL;
6186	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
6187	if (result == ISC_R_SUCCESS) {
6188		dns_view_sethints(view, db);
6189		dns_db_detach(&db);
6190	}
6191
6192	return (result);
6193}
6194
6195static isc_result_t
6196configure_alternates(const cfg_obj_t *config, dns_view_t *view,
6197		     const cfg_obj_t *alternates) {
6198	const cfg_obj_t *portobj;
6199	const cfg_obj_t *addresses;
6200	const cfg_listelt_t *element;
6201	isc_result_t result = ISC_R_SUCCESS;
6202	in_port_t port;
6203
6204	/*
6205	 * Determine which port to send requests to.
6206	 */
6207	CHECKM(named_config_getport(config, "port", &port), "port");
6208
6209	if (alternates != NULL) {
6210		portobj = cfg_tuple_get(alternates, "port");
6211		if (cfg_obj_isuint32(portobj)) {
6212			uint32_t val = cfg_obj_asuint32(portobj);
6213			if (val > UINT16_MAX) {
6214				cfg_obj_log(portobj, named_g_lctx,
6215					    ISC_LOG_ERROR,
6216					    "port '%u' out of range", val);
6217				return (ISC_R_RANGE);
6218			}
6219			port = (in_port_t)val;
6220		}
6221	}
6222
6223	addresses = NULL;
6224	if (alternates != NULL) {
6225		addresses = cfg_tuple_get(alternates, "addresses");
6226	}
6227
6228	for (element = cfg_list_first(addresses); element != NULL;
6229	     element = cfg_list_next(element))
6230	{
6231		const cfg_obj_t *alternate = cfg_listelt_value(element);
6232		isc_sockaddr_t sa;
6233
6234		if (!cfg_obj_issockaddr(alternate)) {
6235			dns_fixedname_t fixed;
6236			dns_name_t *name;
6237			const char *str = cfg_obj_asstring(
6238				cfg_tuple_get(alternate, "name"));
6239			isc_buffer_t buffer;
6240			in_port_t myport = port;
6241
6242			isc_buffer_constinit(&buffer, str, strlen(str));
6243			isc_buffer_add(&buffer, strlen(str));
6244			name = dns_fixedname_initname(&fixed);
6245			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
6246						NULL));
6247
6248			portobj = cfg_tuple_get(alternate, "port");
6249			if (cfg_obj_isuint32(portobj)) {
6250				uint32_t val = cfg_obj_asuint32(portobj);
6251				if (val > UINT16_MAX) {
6252					cfg_obj_log(portobj, named_g_lctx,
6253						    ISC_LOG_ERROR,
6254						    "port '%u' out of range",
6255						    val);
6256					return (ISC_R_RANGE);
6257				}
6258				myport = (in_port_t)val;
6259			}
6260			dns_resolver_addalternate(view->resolver, NULL, name,
6261						  myport);
6262			continue;
6263		}
6264
6265		sa = *cfg_obj_assockaddr(alternate);
6266		if (isc_sockaddr_getport(&sa) == 0) {
6267			isc_sockaddr_setport(&sa, port);
6268		}
6269		dns_resolver_addalternate(view->resolver, &sa, NULL, 0);
6270	}
6271
6272cleanup:
6273	return (result);
6274}
6275
6276static isc_result_t
6277configure_forward(const cfg_obj_t *config, dns_view_t *view,
6278		  const dns_name_t *origin, const cfg_obj_t *forwarders,
6279		  const cfg_obj_t *forwardtype) {
6280	const cfg_obj_t *portobj = NULL;
6281	const cfg_obj_t *faddresses = NULL;
6282	const cfg_listelt_t *element = NULL;
6283	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
6284	dns_forwarderlist_t fwdlist;
6285	dns_forwarder_t *fwd = NULL;
6286	isc_result_t result;
6287	in_port_t port;
6288
6289	ISC_LIST_INIT(fwdlist);
6290
6291	/*
6292	 * Determine which port to send forwarded requests to.
6293	 */
6294	CHECKM(named_config_getport(config, "port", &port), "port");
6295
6296	if (forwarders != NULL) {
6297		portobj = cfg_tuple_get(forwarders, "port");
6298		if (cfg_obj_isuint32(portobj)) {
6299			uint32_t val = cfg_obj_asuint32(portobj);
6300			if (val > UINT16_MAX) {
6301				cfg_obj_log(portobj, named_g_lctx,
6302					    ISC_LOG_ERROR,
6303					    "port '%u' out of range", val);
6304				return (ISC_R_RANGE);
6305			}
6306			port = (in_port_t)val;
6307		}
6308	}
6309
6310	faddresses = NULL;
6311	if (forwarders != NULL) {
6312		faddresses = cfg_tuple_get(forwarders, "addresses");
6313	}
6314
6315	for (element = cfg_list_first(faddresses); element != NULL;
6316	     element = cfg_list_next(element))
6317	{
6318		const cfg_obj_t *forwarder = cfg_listelt_value(element);
6319		fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
6320		fwd->addr = *cfg_obj_assockaddr(forwarder);
6321		if (isc_sockaddr_getport(&fwd->addr) == 0) {
6322			isc_sockaddr_setport(&fwd->addr, port);
6323		}
6324		ISC_LINK_INIT(fwd, link);
6325		ISC_LIST_APPEND(fwdlist, fwd, link);
6326	}
6327
6328	if (ISC_LIST_EMPTY(fwdlist)) {
6329		if (forwardtype != NULL) {
6330			cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING,
6331				    "no forwarders seen; disabling "
6332				    "forwarding");
6333		}
6334		fwdpolicy = dns_fwdpolicy_none;
6335	} else {
6336		if (forwardtype == NULL) {
6337			fwdpolicy = dns_fwdpolicy_first;
6338		} else {
6339			const char *forwardstr = cfg_obj_asstring(forwardtype);
6340			if (strcasecmp(forwardstr, "first") == 0) {
6341				fwdpolicy = dns_fwdpolicy_first;
6342			} else if (strcasecmp(forwardstr, "only") == 0) {
6343				fwdpolicy = dns_fwdpolicy_only;
6344			} else {
6345				UNREACHABLE();
6346			}
6347		}
6348	}
6349
6350	result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
6351				     fwdpolicy);
6352	if (result != ISC_R_SUCCESS) {
6353		char namebuf[DNS_NAME_FORMATSIZE];
6354		dns_name_format(origin, namebuf, sizeof(namebuf));
6355		cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING,
6356			    "could not set up forwarding for domain '%s': %s",
6357			    namebuf, isc_result_totext(result));
6358		goto cleanup;
6359	}
6360
6361	if (fwdpolicy == dns_fwdpolicy_only) {
6362		dns_view_sfd_add(view, origin);
6363	}
6364
6365	result = ISC_R_SUCCESS;
6366
6367cleanup:
6368
6369	while (!ISC_LIST_EMPTY(fwdlist)) {
6370		fwd = ISC_LIST_HEAD(fwdlist);
6371		ISC_LIST_UNLINK(fwdlist, fwd, link);
6372		isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
6373	}
6374
6375	return (result);
6376}
6377
6378static isc_result_t
6379get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
6380	     dns_rdataclass_t *classp) {
6381	isc_result_t result = ISC_R_SUCCESS;
6382	const char *viewname;
6383	dns_rdataclass_t viewclass;
6384
6385	REQUIRE(namep != NULL && *namep == NULL);
6386	REQUIRE(classp != NULL);
6387
6388	if (vconfig != NULL) {
6389		const cfg_obj_t *classobj = NULL;
6390
6391		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
6392		classobj = cfg_tuple_get(vconfig, "class");
6393		CHECK(named_config_getclass(classobj, dns_rdataclass_in,
6394					    &viewclass));
6395		if (dns_rdataclass_ismeta(viewclass)) {
6396			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6397				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6398				      "view '%s': class must not be meta",
6399				      viewname);
6400			CHECK(ISC_R_FAILURE);
6401		}
6402	} else {
6403		viewname = "_default";
6404		viewclass = dns_rdataclass_in;
6405	}
6406
6407	*namep = viewname;
6408	*classp = viewclass;
6409
6410cleanup:
6411	return (result);
6412}
6413
6414/*
6415 * Find a view based on its configuration info and attach to it.
6416 *
6417 * If 'vconfig' is NULL, attach to the default view.
6418 */
6419static isc_result_t
6420find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6421	  dns_view_t **viewp) {
6422	isc_result_t result;
6423	const char *viewname = NULL;
6424	dns_rdataclass_t viewclass;
6425	dns_view_t *view = NULL;
6426
6427	result = get_viewinfo(vconfig, &viewname, &viewclass);
6428	if (result != ISC_R_SUCCESS) {
6429		return (result);
6430	}
6431
6432	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6433	if (result != ISC_R_SUCCESS) {
6434		return (result);
6435	}
6436
6437	*viewp = view;
6438	return (ISC_R_SUCCESS);
6439}
6440
6441/*
6442 * Create a new view and add it to the list.
6443 *
6444 * If 'vconfig' is NULL, create the default view.
6445 *
6446 * The view created is attached to '*viewp'.
6447 */
6448static isc_result_t
6449create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6450	    dns_view_t **viewp) {
6451	isc_result_t result;
6452	const char *viewname = NULL;
6453	dns_rdataclass_t viewclass;
6454	dns_view_t *view = NULL;
6455
6456	result = get_viewinfo(vconfig, &viewname, &viewclass);
6457	if (result != ISC_R_SUCCESS) {
6458		return (result);
6459	}
6460
6461	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6462	if (result == ISC_R_SUCCESS) {
6463		return (ISC_R_EXISTS);
6464	}
6465	if (result != ISC_R_NOTFOUND) {
6466		return (result);
6467	}
6468	INSIST(view == NULL);
6469
6470	result = dns_view_create(named_g_mctx, viewclass, viewname, &view);
6471	if (result != ISC_R_SUCCESS) {
6472		return (result);
6473	}
6474
6475	isc_nonce_buf(view->secret, sizeof(view->secret));
6476
6477	ISC_LIST_APPEND(*viewlist, view, link);
6478	dns_view_attach(view, viewp);
6479	return (ISC_R_SUCCESS);
6480}
6481
6482/*
6483 * Configure or reconfigure a zone.
6484 */
6485static isc_result_t
6486configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
6487	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
6488	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
6489	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
6490	       bool modify) {
6491	dns_view_t *pview = NULL; /* Production view */
6492	dns_zone_t *zone = NULL;  /* New or reused zone */
6493	dns_zone_t *raw = NULL;	  /* New or reused raw zone */
6494	dns_zone_t *dupzone = NULL;
6495	const cfg_obj_t *options = NULL;
6496	const cfg_obj_t *zoptions = NULL;
6497	const cfg_obj_t *typeobj = NULL;
6498	const cfg_obj_t *forwarders = NULL;
6499	const cfg_obj_t *forwardtype = NULL;
6500	const cfg_obj_t *ixfrfromdiffs = NULL;
6501	const cfg_obj_t *only = NULL;
6502	const cfg_obj_t *viewobj = NULL;
6503	isc_result_t result = ISC_R_SUCCESS;
6504	isc_result_t tresult;
6505	isc_buffer_t buffer;
6506	dns_fixedname_t fixorigin;
6507	dns_name_t *origin;
6508	const char *zname;
6509	dns_rdataclass_t zclass;
6510	const char *ztypestr;
6511	dns_rpz_num_t rpz_num;
6512	bool zone_is_catz = false;
6513	bool zone_maybe_inline = false;
6514	bool inline_signing = false;
6515	bool fullsign = false;
6516
6517	options = NULL;
6518	(void)cfg_map_get(config, "options", &options);
6519
6520	zoptions = cfg_tuple_get(zconfig, "options");
6521
6522	/*
6523	 * Get the zone origin as a dns_name_t.
6524	 */
6525	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
6526	isc_buffer_constinit(&buffer, zname, strlen(zname));
6527	isc_buffer_add(&buffer, strlen(zname));
6528	dns_fixedname_init(&fixorigin);
6529	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
6530				dns_rootname, 0, NULL));
6531	origin = dns_fixedname_name(&fixorigin);
6532
6533	CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"),
6534				    view->rdclass, &zclass));
6535	if (zclass != view->rdclass) {
6536		const char *vname = NULL;
6537		if (vconfig != NULL) {
6538			vname = cfg_obj_asstring(
6539				cfg_tuple_get(vconfig, "name"));
6540		} else {
6541			vname = "<default view>";
6542		}
6543
6544		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6545			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6546			      "zone '%s': wrong class for view '%s'", zname,
6547			      vname);
6548		result = ISC_R_FAILURE;
6549		goto cleanup;
6550	}
6551
6552	(void)cfg_map_get(zoptions, "in-view", &viewobj);
6553	if (viewobj != NULL) {
6554		const char *inview = cfg_obj_asstring(viewobj);
6555		dns_view_t *otherview = NULL;
6556
6557		if (viewlist == NULL) {
6558			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6559				    "'in-view' option is not permitted in "
6560				    "dynamically added zones");
6561			result = ISC_R_FAILURE;
6562			goto cleanup;
6563		}
6564
6565		result = dns_viewlist_find(viewlist, inview, view->rdclass,
6566					   &otherview);
6567		if (result != ISC_R_SUCCESS) {
6568			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6569				    "view '%s' is not yet defined.", inview);
6570			result = ISC_R_FAILURE;
6571			goto cleanup;
6572		}
6573
6574		result = dns_view_findzone(otherview, origin, &zone);
6575		dns_view_detach(&otherview);
6576		if (result != ISC_R_SUCCESS) {
6577			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6578				    "zone '%s' not defined in view '%s'", zname,
6579				    inview);
6580			result = ISC_R_FAILURE;
6581			goto cleanup;
6582		}
6583
6584		CHECK(dns_view_addzone(view, zone));
6585		dns_zone_detach(&zone);
6586
6587		/*
6588		 * If the zone contains a 'forwarders' statement, configure
6589		 * selective forwarding.  Note: this is not inherited from the
6590		 * other view.
6591		 */
6592		forwarders = NULL;
6593		result = cfg_map_get(zoptions, "forwarders", &forwarders);
6594		if (result == ISC_R_SUCCESS) {
6595			forwardtype = NULL;
6596			(void)cfg_map_get(zoptions, "forward", &forwardtype);
6597			CHECK(configure_forward(config, view, origin,
6598						forwarders, forwardtype));
6599		}
6600		result = ISC_R_SUCCESS;
6601		goto cleanup;
6602	}
6603
6604	(void)cfg_map_get(zoptions, "type", &typeobj);
6605	if (typeobj == NULL) {
6606		cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6607			    "zone '%s' 'type' not specified", zname);
6608		result = ISC_R_FAILURE;
6609		goto cleanup;
6610	}
6611	ztypestr = cfg_obj_asstring(typeobj);
6612
6613	/*
6614	 * "hints zones" aren't zones.	If we've got one,
6615	 * configure it and return.
6616	 */
6617	if (strcasecmp(ztypestr, "hint") == 0) {
6618		const cfg_obj_t *fileobj = NULL;
6619		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
6620			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6621				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6622				      "zone '%s': 'file' not specified", zname);
6623			result = ISC_R_FAILURE;
6624			goto cleanup;
6625		}
6626		if (dns_name_equal(origin, dns_rootname)) {
6627			const char *hintsfile = cfg_obj_asstring(fileobj);
6628
6629			CHECK(configure_hints(view, hintsfile));
6630
6631			/*
6632			 * Hint zones may also refer to delegation only points.
6633			 */
6634			only = NULL;
6635			tresult = cfg_map_get(zoptions, "delegation-only",
6636					      &only);
6637			if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
6638			{
6639				dns_view_adddelegationonly(view, origin);
6640			}
6641		} else {
6642			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6643				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
6644				      "ignoring non-root hint zone '%s'",
6645				      zname);
6646			result = ISC_R_SUCCESS;
6647		}
6648		/* Skip ordinary zone processing. */
6649		goto cleanup;
6650	}
6651
6652	/*
6653	 * "forward zones" aren't zones either.  Translate this syntax into
6654	 * the appropriate selective forwarding configuration and return.
6655	 */
6656	if (strcasecmp(ztypestr, "forward") == 0) {
6657		forwardtype = NULL;
6658		forwarders = NULL;
6659
6660		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6661		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
6662		CHECK(configure_forward(config, view, origin, forwarders,
6663					forwardtype));
6664
6665		/*
6666		 * Forward zones may also set delegation only.
6667		 */
6668		only = NULL;
6669		tresult = cfg_map_get(zoptions, "delegation-only", &only);
6670		if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) {
6671			dns_view_adddelegationonly(view, origin);
6672		}
6673		goto cleanup;
6674	}
6675
6676	/*
6677	 * "delegation-only zones" aren't zones either.
6678	 */
6679	if (strcasecmp(ztypestr, "delegation-only") == 0) {
6680		dns_view_adddelegationonly(view, origin);
6681		goto cleanup;
6682	}
6683
6684	/*
6685	 * Redirect zones only require minimal configuration.
6686	 */
6687	if (strcasecmp(ztypestr, "redirect") == 0) {
6688		if (view->redirect != NULL) {
6689			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6690				    "redirect zone already exists");
6691			result = ISC_R_EXISTS;
6692			goto cleanup;
6693		}
6694		result = dns_viewlist_find(viewlist, view->name, view->rdclass,
6695					   &pview);
6696		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6697			goto cleanup;
6698		}
6699		if (pview != NULL && pview->redirect != NULL) {
6700			dns_zone_attach(pview->redirect, &zone);
6701			dns_zone_setview(zone, view);
6702		} else {
6703			CHECK(dns_zonemgr_createzone(named_g_server->zonemgr,
6704						     &zone));
6705			CHECK(dns_zone_setorigin(zone, origin));
6706			dns_zone_setview(zone, view);
6707			CHECK(dns_zonemgr_managezone(named_g_server->zonemgr,
6708						     zone));
6709			dns_zone_setstats(zone, named_g_server->zonestats);
6710		}
6711		CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
6712					   kasplist, zone, NULL));
6713		dns_zone_attach(zone, &view->redirect);
6714		goto cleanup;
6715	}
6716
6717	if (!modify) {
6718		/*
6719		 * Check for duplicates in the new zone table.
6720		 */
6721		result = dns_view_findzone(view, origin, &dupzone);
6722		if (result == ISC_R_SUCCESS) {
6723			/*
6724			 * We already have this zone!
6725			 */
6726			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6727				    "zone '%s' already exists", zname);
6728			dns_zone_detach(&dupzone);
6729			result = ISC_R_EXISTS;
6730			goto cleanup;
6731		}
6732		INSIST(dupzone == NULL);
6733	}
6734
6735	/*
6736	 * Note whether this is a response policy zone and which one if so,
6737	 * unless we are using RPZ service interface.  In that case, the
6738	 * BIND zone database has nothing to do with rpz and so we don't care.
6739	 */
6740	for (rpz_num = 0;; ++rpz_num) {
6741		if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
6742		    view->rpzs->p.dnsrps_enabled)
6743		{
6744			rpz_num = DNS_RPZ_INVALID_NUM;
6745			break;
6746		}
6747		if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
6748		{
6749			break;
6750		}
6751	}
6752
6753	if (view->catzs != NULL &&
6754	    dns_catz_get_zone(view->catzs, origin) != NULL)
6755	{
6756		zone_is_catz = true;
6757	}
6758
6759	/*
6760	 * See if we can reuse an existing zone.  This is
6761	 * only possible if all of these are true:
6762	 *   - The zone's view exists
6763	 *   - A zone with the right name exists in the view
6764	 *   - The zone is compatible with the config
6765	 *     options (e.g., an existing primary zone cannot
6766	 *     be reused if the options specify a secondary zone)
6767	 *   - The zone was not and is still not a response policy zone
6768	 *     or the zone is a policy zone with an unchanged number
6769	 *     and we are using the old policy zone summary data.
6770	 */
6771	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6772				   view->rdclass, &pview);
6773	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6774		goto cleanup;
6775	}
6776	if (pview != NULL) {
6777		result = dns_view_findzone(pview, origin, &zone);
6778	}
6779	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6780		goto cleanup;
6781	}
6782
6783	if (zone != NULL && !named_zone_reusable(zone, zconfig)) {
6784		dns_zone_detach(&zone);
6785		fullsign = true;
6786	}
6787
6788	if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
6789			     (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
6790	{
6791		dns_zone_detach(&zone);
6792	}
6793
6794	if (zone != NULL) {
6795		/*
6796		 * We found a reusable zone.  Make it use the
6797		 * new view.
6798		 */
6799		dns_zone_setview(zone, view);
6800	} else {
6801		/*
6802		 * We cannot reuse an existing zone, we have
6803		 * to create a new one.
6804		 */
6805		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6806		CHECK(dns_zone_setorigin(zone, origin));
6807		dns_zone_setview(zone, view);
6808		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6809		dns_zone_setstats(zone, named_g_server->zonestats);
6810	}
6811	if (rpz_num != DNS_RPZ_INVALID_NUM) {
6812		result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
6813		if (result != ISC_R_SUCCESS) {
6814			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6815				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6816				      "zone '%s': incompatible"
6817				      " masterfile-format or database"
6818				      " for a response policy zone",
6819				      zname);
6820			goto cleanup;
6821		}
6822	}
6823
6824	if (zone_is_catz) {
6825		dns_zone_catz_enable(zone, view->catzs);
6826	} else if (dns_zone_catz_is_enabled(zone)) {
6827		dns_zone_catz_disable(zone);
6828	}
6829
6830	/*
6831	 * If the zone contains a 'forwarders' statement, configure
6832	 * selective forwarding.
6833	 */
6834	forwarders = NULL;
6835	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) {
6836		forwardtype = NULL;
6837		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6838		CHECK(configure_forward(config, view, origin, forwarders,
6839					forwardtype));
6840	}
6841
6842	/*
6843	 * Stub and forward zones may also refer to delegation only points.
6844	 */
6845	only = NULL;
6846	if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) {
6847		if (cfg_obj_asboolean(only)) {
6848			dns_view_adddelegationonly(view, origin);
6849		}
6850	}
6851
6852	/*
6853	 * Mark whether the zone was originally added at runtime or not
6854	 */
6855	dns_zone_setadded(zone, added);
6856
6857	/*
6858	 * Determine if we need to set up inline signing.
6859	 */
6860	zone_maybe_inline = ((strcasecmp(ztypestr, "primary") == 0 ||
6861			      strcasecmp(ztypestr, "master") == 0 ||
6862			      strcasecmp(ztypestr, "secondary") == 0 ||
6863			      strcasecmp(ztypestr, "slave") == 0));
6864
6865	if (zone_maybe_inline) {
6866		inline_signing = named_zone_inlinesigning(zconfig);
6867	}
6868	if (inline_signing) {
6869		dns_zone_getraw(zone, &raw);
6870		if (raw == NULL) {
6871			CHECK(dns_zone_create(&raw, mctx));
6872			CHECK(dns_zone_setorigin(raw, origin));
6873			dns_zone_setview(raw, view);
6874			dns_zone_setstats(raw, named_g_server->zonestats);
6875			CHECK(dns_zone_link(zone, raw));
6876		}
6877		if (cfg_map_get(zoptions, "ixfr-from-differences",
6878				&ixfrfromdiffs) == ISC_R_SUCCESS)
6879		{
6880			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6881				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6882				      "zone '%s': 'ixfr-from-differences' is "
6883				      "ignored for inline-signed zones",
6884				      zname);
6885		}
6886	}
6887
6888	/*
6889	 * Configure the zone.
6890	 */
6891	CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
6892				   zone, raw));
6893
6894	/*
6895	 * Add the zone to its view in the new view list.
6896	 */
6897	if (!modify) {
6898		CHECK(dns_view_addzone(view, zone));
6899	}
6900
6901	if (zone_is_catz) {
6902		/*
6903		 * force catz reload if the zone is loaded;
6904		 * if it's not it'll get reloaded on zone load
6905		 */
6906		dns_db_t *db = NULL;
6907
6908		tresult = dns_zone_getdb(zone, &db);
6909		if (tresult == ISC_R_SUCCESS) {
6910			dns_catz_dbupdate_callback(db, view->catzs);
6911			dns_db_detach(&db);
6912		}
6913	}
6914
6915	/*
6916	 * Ensure that zone keys are reloaded on reconfig
6917	 */
6918	if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) {
6919		dns_zone_rekey(zone, fullsign);
6920	}
6921
6922cleanup:
6923	if (zone != NULL) {
6924		dns_zone_detach(&zone);
6925	}
6926	if (raw != NULL) {
6927		dns_zone_detach(&raw);
6928	}
6929	if (pview != NULL) {
6930		dns_view_detach(&pview);
6931	}
6932
6933	return (result);
6934}
6935
6936/*
6937 * Configure built-in zone for storing managed-key data.
6938 */
6939static isc_result_t
6940add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
6941	isc_result_t result;
6942	dns_view_t *pview = NULL;
6943	dns_zone_t *zone = NULL;
6944	dns_acl_t *none = NULL;
6945	char filename[PATH_MAX];
6946	bool defaultview;
6947
6948	REQUIRE(view != NULL);
6949
6950	/* See if we can re-use an existing keydata zone. */
6951	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6952				   view->rdclass, &pview);
6953	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6954		return (result);
6955	}
6956
6957	if (pview != NULL) {
6958		if (pview->managed_keys != NULL) {
6959			dns_zone_attach(pview->managed_keys,
6960					&view->managed_keys);
6961			dns_zone_setview(pview->managed_keys, view);
6962			dns_zone_setviewcommit(pview->managed_keys);
6963			dns_view_detach(&pview);
6964			dns_zone_synckeyzone(view->managed_keys);
6965			return (ISC_R_SUCCESS);
6966		}
6967
6968		dns_view_detach(&pview);
6969	}
6970
6971	/* No existing keydata zone was found; create one */
6972	CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6973	CHECK(dns_zone_setorigin(zone, dns_rootname));
6974
6975	defaultview = (strcmp(view->name, "_default") == 0);
6976	CHECK(isc_file_sanitize(
6977		directory, defaultview ? "managed-keys" : view->name,
6978		defaultview ? "bind" : "mkeys", filename, sizeof(filename)));
6979	CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text,
6980			       &dns_master_style_default));
6981
6982	dns_zone_setview(zone, view);
6983	dns_zone_settype(zone, dns_zone_key);
6984	dns_zone_setclass(zone, view->rdclass);
6985
6986	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6987
6988	CHECK(dns_acl_none(mctx, &none));
6989	dns_zone_setqueryacl(zone, none);
6990	dns_zone_setqueryonacl(zone, none);
6991	dns_acl_detach(&none);
6992
6993	dns_zone_setdialup(zone, dns_dialuptype_no);
6994	dns_zone_setnotifytype(zone, dns_notifytype_no);
6995	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
6996	dns_zone_setjournalsize(zone, 0);
6997
6998	dns_zone_setstats(zone, named_g_server->zonestats);
6999	CHECK(setquerystats(zone, mctx, dns_zonestat_none));
7000
7001	if (view->managed_keys != NULL) {
7002		dns_zone_detach(&view->managed_keys);
7003	}
7004	dns_zone_attach(zone, &view->managed_keys);
7005
7006	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7007		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7008		      "set up managed keys zone for view %s, file '%s'",
7009		      view->name, filename);
7010
7011cleanup:
7012	if (zone != NULL) {
7013		dns_zone_detach(&zone);
7014	}
7015	if (none != NULL) {
7016		dns_acl_detach(&none);
7017	}
7018
7019	return (result);
7020}
7021
7022/*
7023 * Configure a single server quota.
7024 */
7025static void
7026configure_server_quota(const cfg_obj_t **maps, const char *name,
7027		       isc_quota_t *quota) {
7028	const cfg_obj_t *obj = NULL;
7029	isc_result_t result;
7030
7031	result = named_config_get(maps, name, &obj);
7032	INSIST(result == ISC_R_SUCCESS);
7033	isc_quota_max(quota, cfg_obj_asuint32(obj));
7034}
7035
7036/*
7037 * This function is called as soon as the 'directory' statement has been
7038 * parsed.  This can be extended to support other options if necessary.
7039 */
7040static isc_result_t
7041directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
7042	isc_result_t result;
7043	const char *directory;
7044
7045	REQUIRE(strcasecmp("directory", clausename) == 0);
7046
7047	UNUSED(arg);
7048	UNUSED(clausename);
7049
7050	/*
7051	 * Change directory.
7052	 */
7053	directory = cfg_obj_asstring(obj);
7054
7055	if (!isc_file_ischdiridempotent(directory)) {
7056		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
7057			    "option 'directory' contains relative path '%s'",
7058			    directory);
7059	}
7060
7061#if 0
7062	if (!isc_file_isdirwritable(directory)) {
7063		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7064			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7065			      "directory '%s' is not writable", directory);
7066		return (ISC_R_NOPERM);
7067	}
7068#endif
7069
7070	result = isc_dir_chdir(directory);
7071	if (result != ISC_R_SUCCESS) {
7072		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7073			    "change directory to '%s' failed: %s", directory,
7074			    isc_result_totext(result));
7075		return (result);
7076	}
7077
7078	return (ISC_R_SUCCESS);
7079}
7080
7081/*
7082 * This event callback is invoked to do periodic network interface
7083 * scanning.
7084 */
7085
7086static void
7087interface_timer_tick(isc_task_t *task, isc_event_t *event) {
7088	named_server_t *server = (named_server_t *)event->ev_arg;
7089	INSIST(task == server->task);
7090	UNUSED(task);
7091
7092	isc_event_free(&event);
7093	ns_interfacemgr_scan(server->interfacemgr, false, false);
7094}
7095
7096static void
7097heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
7098	named_server_t *server = (named_server_t *)event->ev_arg;
7099	dns_view_t *view;
7100
7101	UNUSED(task);
7102	isc_event_free(&event);
7103	view = ISC_LIST_HEAD(server->viewlist);
7104	while (view != NULL) {
7105		dns_view_dialup(view);
7106		view = ISC_LIST_NEXT(view, link);
7107	}
7108}
7109
7110typedef struct {
7111	isc_mem_t *mctx;
7112	isc_task_t *task;
7113	dns_fetch_t *fetch;
7114	dns_view_t *view;
7115	dns_fixedname_t tatname;
7116	dns_fixedname_t keyname;
7117	dns_rdataset_t rdataset;
7118	dns_rdataset_t sigrdataset;
7119} ns_tat_t;
7120
7121static int
7122cid(const void *a, const void *b) {
7123	const uint16_t ida = *(const uint16_t *)a;
7124	const uint16_t idb = *(const uint16_t *)b;
7125	if (ida < idb) {
7126		return (-1);
7127	} else if (ida > idb) {
7128		return (1);
7129	} else {
7130		return (0);
7131	}
7132}
7133
7134static void
7135tat_done(isc_task_t *task, isc_event_t *event) {
7136	dns_fetchevent_t *devent;
7137	ns_tat_t *tat;
7138
7139	INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE);
7140	INSIST(event->ev_arg != NULL);
7141
7142	UNUSED(task);
7143
7144	tat = event->ev_arg;
7145	devent = (dns_fetchevent_t *)event;
7146
7147	/* Free resources which are not of interest */
7148	if (devent->node != NULL) {
7149		dns_db_detachnode(devent->db, &devent->node);
7150	}
7151	if (devent->db != NULL) {
7152		dns_db_detach(&devent->db);
7153	}
7154	isc_event_free(&event);
7155	dns_resolver_destroyfetch(&tat->fetch);
7156	if (dns_rdataset_isassociated(&tat->rdataset)) {
7157		dns_rdataset_disassociate(&tat->rdataset);
7158	}
7159	if (dns_rdataset_isassociated(&tat->sigrdataset)) {
7160		dns_rdataset_disassociate(&tat->sigrdataset);
7161	}
7162	dns_view_detach(&tat->view);
7163	isc_task_detach(&tat->task);
7164	isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
7165}
7166
7167struct dotat_arg {
7168	dns_view_t *view;
7169	isc_task_t *task;
7170};
7171
7172/*%
7173 * Prepare the QNAME for the TAT query to be sent by processing the trust
7174 * anchors present at 'keynode' of 'keytable'.  Store the result in 'dst' and
7175 * the domain name which 'keynode' is associated with in 'origin'.
7176 *
7177 * A maximum of 12 key IDs can be reported in a single TAT query due to the
7178 * 63-octet length limit for any single label in a domain name.  If there are
7179 * more than 12 keys configured at 'keynode', only the first 12 will be
7180 * reported in the TAT query.
7181 */
7182static isc_result_t
7183get_tat_qname(dns_name_t *target, dns_name_t *keyname, dns_keynode_t *keynode) {
7184	dns_rdataset_t dsset;
7185	unsigned int i, n = 0;
7186	uint16_t ids[12];
7187	isc_textregion_t r;
7188	char label[64];
7189	int m;
7190
7191	dns_rdataset_init(&dsset);
7192	if (dns_keynode_dsset(keynode, &dsset)) {
7193		isc_result_t result;
7194
7195		for (result = dns_rdataset_first(&dsset);
7196		     result == ISC_R_SUCCESS;
7197		     result = dns_rdataset_next(&dsset))
7198		{
7199			dns_rdata_t rdata = DNS_RDATA_INIT;
7200			dns_rdata_ds_t ds;
7201
7202			dns_rdata_reset(&rdata);
7203			dns_rdataset_current(&dsset, &rdata);
7204			result = dns_rdata_tostruct(&rdata, &ds, NULL);
7205			RUNTIME_CHECK(result == ISC_R_SUCCESS);
7206			if (n < (sizeof(ids) / sizeof(ids[0]))) {
7207				ids[n] = ds.key_tag;
7208				n++;
7209			}
7210		}
7211		dns_rdataset_disassociate(&dsset);
7212	}
7213
7214	if (n == 0) {
7215		return (DNS_R_EMPTYNAME);
7216	}
7217
7218	if (n > 1) {
7219		qsort(ids, n, sizeof(ids[0]), cid);
7220	}
7221
7222	/*
7223	 * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
7224	 * of the keyid.
7225	 */
7226	label[0] = 0;
7227	r.base = label;
7228	r.length = sizeof(label);
7229	m = snprintf(r.base, r.length, "_ta");
7230	if (m < 0 || (unsigned)m > r.length) {
7231		return (ISC_R_FAILURE);
7232	}
7233	isc_textregion_consume(&r, m);
7234	for (i = 0; i < n; i++) {
7235		m = snprintf(r.base, r.length, "-%04x", ids[i]);
7236		if (m < 0 || (unsigned)m > r.length) {
7237			return (ISC_R_FAILURE);
7238		}
7239		isc_textregion_consume(&r, m);
7240	}
7241
7242	return (dns_name_fromstring2(target, label, keyname, 0, NULL));
7243}
7244
7245static void
7246tat_send(isc_task_t *task, isc_event_t *event) {
7247	ns_tat_t *tat;
7248	char namebuf[DNS_NAME_FORMATSIZE];
7249	dns_fixedname_t fdomain;
7250	dns_name_t *domain;
7251	dns_rdataset_t nameservers;
7252	isc_result_t result;
7253	dns_name_t *keyname;
7254	dns_name_t *tatname;
7255
7256	INSIST(event != NULL && event->ev_type == NAMED_EVENT_TATSEND);
7257	INSIST(event->ev_arg != NULL);
7258
7259	UNUSED(task);
7260
7261	tat = event->ev_arg;
7262
7263	keyname = dns_fixedname_name(&tat->keyname);
7264	tatname = dns_fixedname_name(&tat->tatname);
7265
7266	dns_name_format(tatname, namebuf, sizeof(namebuf));
7267	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7268		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7269		      "%s: sending trust-anchor-telemetry query '%s/NULL'",
7270		      tat->view->name, namebuf);
7271
7272	/*
7273	 * TAT queries should be sent to the authoritative servers for a given
7274	 * zone.  If this function is called for a keytable node corresponding
7275	 * to a locally served zone, calling dns_resolver_createfetch() with
7276	 * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be
7277	 * resolved locally, without sending any TAT queries upstream.
7278	 *
7279	 * Work around this issue by calling dns_view_findzonecut() first.  If
7280	 * the zone is served locally, the NS RRset for the given domain name
7281	 * will be retrieved from local data; if it is not, the deepest zone
7282	 * cut we have for it will be retrieved from cache.  In either case,
7283	 * passing the results to dns_resolver_createfetch() will prevent it
7284	 * from returning NXDOMAIN for 'tatname' while still allowing it to
7285	 * chase down any potential delegations returned by upstream servers in
7286	 * order to eventually find the destination host to send the TAT query
7287	 * to.
7288	 *
7289	 * After the dns_view_findzonecut() call, 'domain' will hold the
7290	 * deepest zone cut we can find for 'keyname' while 'nameservers' will
7291	 * hold the NS RRset at that zone cut.
7292	 */
7293	domain = dns_fixedname_initname(&fdomain);
7294	dns_rdataset_init(&nameservers);
7295	result = dns_view_findzonecut(tat->view, keyname, domain, NULL, 0, 0,
7296				      true, true, &nameservers, NULL);
7297	if (result == ISC_R_SUCCESS) {
7298		result = dns_resolver_createfetch(
7299			tat->view->resolver, tatname, dns_rdatatype_null,
7300			domain, &nameservers, NULL, NULL, 0, 0, 0, NULL,
7301			tat->task, tat_done, tat, &tat->rdataset,
7302			&tat->sigrdataset, &tat->fetch);
7303	}
7304
7305	/*
7306	 * 'domain' holds the dns_name_t pointer inside a dst_key_t structure.
7307	 * dns_resolver_createfetch() creates its own copy of 'domain' if it
7308	 * succeeds.  Thus, 'domain' is not freed here.
7309	 *
7310	 * Even if dns_view_findzonecut() returned something else than
7311	 * ISC_R_SUCCESS, it still could have associated 'nameservers'.
7312	 * dns_resolver_createfetch() creates its own copy of 'nameservers' if
7313	 * it succeeds.  Thus, we need to check whether 'nameservers' is
7314	 * associated and release it if it is.
7315	 */
7316	if (dns_rdataset_isassociated(&nameservers)) {
7317		dns_rdataset_disassociate(&nameservers);
7318	}
7319
7320	if (result != ISC_R_SUCCESS) {
7321		dns_view_detach(&tat->view);
7322		isc_task_detach(&tat->task);
7323		isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
7324	}
7325	isc_event_free(&event);
7326}
7327
7328static void
7329dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, dns_name_t *keyname,
7330      void *arg) {
7331	struct dotat_arg *dotat_arg = arg;
7332	isc_result_t result;
7333	dns_view_t *view;
7334	isc_task_t *task;
7335	ns_tat_t *tat;
7336	isc_event_t *event;
7337
7338	REQUIRE(keytable != NULL);
7339	REQUIRE(keynode != NULL);
7340	REQUIRE(dotat_arg != NULL);
7341
7342	view = dotat_arg->view;
7343	task = dotat_arg->task;
7344
7345	tat = isc_mem_get(dotat_arg->view->mctx, sizeof(*tat));
7346
7347	tat->fetch = NULL;
7348	tat->mctx = NULL;
7349	tat->task = NULL;
7350	tat->view = NULL;
7351	dns_rdataset_init(&tat->rdataset);
7352	dns_rdataset_init(&tat->sigrdataset);
7353	dns_name_copy(keyname, dns_fixedname_initname(&tat->keyname));
7354	result = get_tat_qname(dns_fixedname_initname(&tat->tatname), keyname,
7355			       keynode);
7356	if (result != ISC_R_SUCCESS) {
7357		isc_mem_put(dotat_arg->view->mctx, tat, sizeof(*tat));
7358		return;
7359	}
7360	isc_mem_attach(dotat_arg->view->mctx, &tat->mctx);
7361	isc_task_attach(task, &tat->task);
7362	dns_view_attach(view, &tat->view);
7363
7364	/*
7365	 * We don't want to be holding the keytable lock when calling
7366	 * dns_view_findzonecut() as it creates a lock order loop so
7367	 * call dns_view_findzonecut() in a event handler.
7368	 *
7369	 * zone->lock (dns_zone_setviewcommit) while holding view->lock
7370	 * (dns_view_setviewcommit)
7371	 *
7372	 * keytable->lock (dns_keytable_find) while holding zone->lock
7373	 * (zone_asyncload)
7374	 *
7375	 * view->lock (dns_view_findzonecut) while holding keytable->lock
7376	 * (dns_keytable_forall)
7377	 */
7378	event = isc_event_allocate(tat->mctx, keytable, NAMED_EVENT_TATSEND,
7379				   tat_send, tat, sizeof(isc_event_t));
7380	isc_task_send(task, &event);
7381}
7382
7383static void
7384tat_timer_tick(isc_task_t *task, isc_event_t *event) {
7385	isc_result_t result;
7386	named_server_t *server = (named_server_t *)event->ev_arg;
7387	struct dotat_arg arg;
7388	dns_view_t *view;
7389	dns_keytable_t *secroots = NULL;
7390
7391	isc_event_free(&event);
7392
7393	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
7394	     view = ISC_LIST_NEXT(view, link))
7395	{
7396		if (!view->trust_anchor_telemetry || !view->enablevalidation) {
7397			continue;
7398		}
7399
7400		result = dns_view_getsecroots(view, &secroots);
7401		if (result != ISC_R_SUCCESS) {
7402			continue;
7403		}
7404
7405		arg.view = view;
7406		arg.task = task;
7407		(void)dns_keytable_forall(secroots, dotat, &arg);
7408		dns_keytable_detach(&secroots);
7409	}
7410}
7411
7412static void
7413pps_timer_tick(isc_task_t *task, isc_event_t *event) {
7414	static unsigned int oldrequests = 0;
7415	unsigned int requests = atomic_load_relaxed(&ns_client_requests);
7416
7417	UNUSED(task);
7418	isc_event_free(&event);
7419
7420	/*
7421	 * Don't worry about wrapping as the overflow result will be right.
7422	 */
7423	dns_pps = (requests - oldrequests) / 1200;
7424	oldrequests = requests;
7425}
7426
7427/*
7428 * Replace the current value of '*field', a dynamically allocated
7429 * string or NULL, with a dynamically allocated copy of the
7430 * null-terminated string pointed to by 'value', or NULL.
7431 */
7432static isc_result_t
7433setstring(named_server_t *server, char **field, const char *value) {
7434	char *copy;
7435
7436	if (value != NULL) {
7437		copy = isc_mem_strdup(server->mctx, value);
7438	} else {
7439		copy = NULL;
7440	}
7441
7442	if (*field != NULL) {
7443		isc_mem_free(server->mctx, *field);
7444	}
7445
7446	*field = copy;
7447	return (ISC_R_SUCCESS);
7448}
7449
7450/*
7451 * Replace the current value of '*field', a dynamically allocated
7452 * string or NULL, with another dynamically allocated string
7453 * or NULL if whether 'obj' is a string or void value, respectively.
7454 */
7455static isc_result_t
7456setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) {
7457	if (cfg_obj_isvoid(obj)) {
7458		return (setstring(server, field, NULL));
7459	} else {
7460		return (setstring(server, field, cfg_obj_asstring(obj)));
7461	}
7462}
7463
7464static void
7465set_limit(const cfg_obj_t **maps, const char *configname,
7466	  const char *description, isc_resource_t resourceid,
7467	  isc_resourcevalue_t defaultvalue) {
7468	const cfg_obj_t *obj = NULL;
7469	const char *resource;
7470	isc_resourcevalue_t value;
7471	isc_result_t result;
7472
7473	if (named_config_get(maps, configname, &obj) != ISC_R_SUCCESS) {
7474		return;
7475	}
7476
7477	if (cfg_obj_isstring(obj)) {
7478		resource = cfg_obj_asstring(obj);
7479		if (strcasecmp(resource, "unlimited") == 0) {
7480			value = ISC_RESOURCE_UNLIMITED;
7481		} else {
7482			INSIST(strcasecmp(resource, "default") == 0);
7483			value = defaultvalue;
7484		}
7485	} else {
7486		value = cfg_obj_asuint64(obj);
7487	}
7488
7489	result = isc_resource_setlimit(resourceid, value);
7490	isc_log_write(
7491		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7492		result == ISC_R_SUCCESS ? ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
7493		"set maximum %s to %" PRIu64 ": %s", description, value,
7494		isc_result_totext(result));
7495}
7496
7497#define SETLIMIT(cfgvar, resource, description)                       \
7498	set_limit(maps, cfgvar, description, isc_resource_##resource, \
7499		  named_g_init##resource)
7500
7501static void
7502set_limits(const cfg_obj_t **maps) {
7503	SETLIMIT("stacksize", stacksize, "stack size");
7504	SETLIMIT("datasize", datasize, "data size");
7505	SETLIMIT("coresize", coresize, "core size");
7506	SETLIMIT("files", openfiles, "open files");
7507}
7508
7509static void
7510portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
7511		 bool positive) {
7512	const cfg_listelt_t *element;
7513
7514	for (element = cfg_list_first(ports); element != NULL;
7515	     element = cfg_list_next(element))
7516	{
7517		const cfg_obj_t *obj = cfg_listelt_value(element);
7518
7519		if (cfg_obj_isuint32(obj)) {
7520			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
7521
7522			if (positive) {
7523				isc_portset_add(portset, port);
7524			} else {
7525				isc_portset_remove(portset, port);
7526			}
7527		} else {
7528			const cfg_obj_t *obj_loport, *obj_hiport;
7529			in_port_t loport, hiport;
7530
7531			obj_loport = cfg_tuple_get(obj, "loport");
7532			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
7533			obj_hiport = cfg_tuple_get(obj, "hiport");
7534			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
7535
7536			if (positive) {
7537				isc_portset_addrange(portset, loport, hiport);
7538			} else {
7539				isc_portset_removerange(portset, loport,
7540							hiport);
7541			}
7542		}
7543	}
7544}
7545
7546static isc_result_t
7547removed(dns_zone_t *zone, void *uap) {
7548	if (dns_zone_getview(zone) != uap) {
7549		return (ISC_R_SUCCESS);
7550	}
7551
7552	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed",
7553		     dns_zonetype_name(dns_zone_gettype(zone)));
7554	return (ISC_R_SUCCESS);
7555}
7556
7557static void
7558cleanup_session_key(named_server_t *server, isc_mem_t *mctx) {
7559	if (server->session_keyfile != NULL) {
7560		isc_file_remove(server->session_keyfile);
7561		isc_mem_free(mctx, server->session_keyfile);
7562		server->session_keyfile = NULL;
7563	}
7564
7565	if (server->session_keyname != NULL) {
7566		if (dns_name_dynamic(server->session_keyname)) {
7567			dns_name_free(server->session_keyname, mctx);
7568		}
7569		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
7570		server->session_keyname = NULL;
7571	}
7572
7573	if (server->sessionkey != NULL) {
7574		dst_key_free(&server->sessionkey);
7575	}
7576
7577	server->session_keyalg = DST_ALG_UNKNOWN;
7578	server->session_keybits = 0;
7579}
7580
7581static isc_result_t
7582generate_session_key(const char *filename, const char *keynamestr,
7583		     const dns_name_t *keyname, const char *algstr,
7584		     unsigned int algtype, uint16_t bits, isc_mem_t *mctx,
7585		     bool first_time, dst_key_t **keyp) {
7586	isc_result_t result = ISC_R_SUCCESS;
7587	dst_key_t *key = NULL;
7588	isc_buffer_t key_txtbuffer;
7589	isc_buffer_t key_rawbuffer;
7590	char key_txtsecret[256];
7591	char key_rawsecret[64];
7592	isc_region_t key_rawregion;
7593	FILE *fp = NULL;
7594
7595	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7596		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7597		      "generating session key for dynamic DNS");
7598
7599	/* generate key */
7600	result = dst_key_generate(keyname, algtype, bits, 1, 0,
7601				  DNS_KEYPROTO_ANY, dns_rdataclass_in, mctx,
7602				  &key, NULL);
7603	if (result != ISC_R_SUCCESS) {
7604		return (result);
7605	}
7606
7607	/*
7608	 * Dump the key to the buffer for later use.
7609	 */
7610	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
7611	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
7612
7613	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
7614	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
7615	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
7616
7617	/* Dump the key to the key file. */
7618	fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time);
7619	if (fp == NULL) {
7620		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7621			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7622			      "could not create %s", filename);
7623		result = ISC_R_NOPERM;
7624		goto cleanup;
7625	}
7626
7627	fprintf(fp,
7628		"key \"%s\" {\n"
7629		"\talgorithm %s;\n"
7630		"\tsecret \"%.*s\";\n};\n",
7631		keynamestr, algstr, (int)isc_buffer_usedlength(&key_txtbuffer),
7632		(char *)isc_buffer_base(&key_txtbuffer));
7633
7634	CHECK(isc_stdio_flush(fp));
7635	result = isc_stdio_close(fp);
7636	fp = NULL;
7637	if (result != ISC_R_SUCCESS) {
7638		goto cleanup;
7639	}
7640
7641	*keyp = key;
7642	return (ISC_R_SUCCESS);
7643
7644cleanup:
7645	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7646		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7647		      "failed to generate session key "
7648		      "for dynamic DNS: %s",
7649		      isc_result_totext(result));
7650	if (fp != NULL) {
7651		(void)isc_stdio_close(fp);
7652		(void)isc_file_remove(filename);
7653	}
7654	if (key != NULL) {
7655		dst_key_free(&key);
7656	}
7657
7658	return (result);
7659}
7660
7661static isc_result_t
7662configure_session_key(const cfg_obj_t **maps, named_server_t *server,
7663		      isc_mem_t *mctx, bool first_time) {
7664	const char *keyfile, *keynamestr, *algstr;
7665	unsigned int algtype;
7666	dns_fixedname_t fname;
7667	dns_name_t *keyname;
7668	const dns_name_t *algname;
7669	isc_buffer_t buffer;
7670	uint16_t bits;
7671	const cfg_obj_t *obj;
7672	bool need_deleteold = false;
7673	bool need_createnew = false;
7674	isc_result_t result;
7675
7676	obj = NULL;
7677	result = named_config_get(maps, "session-keyfile", &obj);
7678	if (result == ISC_R_SUCCESS) {
7679		if (cfg_obj_isvoid(obj)) {
7680			keyfile = NULL; /* disable it */
7681		} else {
7682			keyfile = cfg_obj_asstring(obj);
7683		}
7684	} else {
7685		keyfile = named_g_defaultsessionkeyfile;
7686	}
7687
7688	obj = NULL;
7689	result = named_config_get(maps, "session-keyname", &obj);
7690	INSIST(result == ISC_R_SUCCESS);
7691	keynamestr = cfg_obj_asstring(obj);
7692	isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
7693	isc_buffer_add(&buffer, strlen(keynamestr));
7694	keyname = dns_fixedname_initname(&fname);
7695	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
7696	if (result != ISC_R_SUCCESS) {
7697		return (result);
7698	}
7699
7700	obj = NULL;
7701	result = named_config_get(maps, "session-keyalg", &obj);
7702	INSIST(result == ISC_R_SUCCESS);
7703	algstr = cfg_obj_asstring(obj);
7704	algname = NULL;
7705	result = named_config_getkeyalgorithm2(algstr, &algname, &algtype,
7706					       &bits);
7707	if (result != ISC_R_SUCCESS) {
7708		const char *s = " (keeping current key)";
7709
7710		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7711			    "session-keyalg: "
7712			    "unsupported or unknown algorithm '%s'%s",
7713			    algstr, server->session_keyfile != NULL ? s : "");
7714		return (result);
7715	}
7716
7717	/* See if we need to (re)generate a new key. */
7718	if (keyfile == NULL) {
7719		if (server->session_keyfile != NULL) {
7720			need_deleteold = true;
7721		}
7722	} else if (server->session_keyfile == NULL) {
7723		need_createnew = true;
7724	} else if (strcmp(keyfile, server->session_keyfile) != 0 ||
7725		   !dns_name_equal(server->session_keyname, keyname) ||
7726		   server->session_keyalg != algtype ||
7727		   server->session_keybits != bits)
7728	{
7729		need_deleteold = true;
7730		need_createnew = true;
7731	}
7732
7733	if (need_deleteold) {
7734		INSIST(server->session_keyfile != NULL);
7735		INSIST(server->session_keyname != NULL);
7736		INSIST(server->sessionkey != NULL);
7737
7738		cleanup_session_key(server, mctx);
7739	}
7740
7741	if (need_createnew) {
7742		INSIST(server->sessionkey == NULL);
7743		INSIST(server->session_keyfile == NULL);
7744		INSIST(server->session_keyname == NULL);
7745		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
7746		INSIST(server->session_keybits == 0);
7747
7748		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
7749		dns_name_init(server->session_keyname, NULL);
7750		dns_name_dup(keyname, mctx, server->session_keyname);
7751
7752		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
7753
7754		server->session_keyalg = algtype;
7755		server->session_keybits = bits;
7756
7757		CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
7758					   algtype, bits, mctx, first_time,
7759					   &server->sessionkey));
7760	}
7761
7762	return (result);
7763
7764cleanup:
7765	cleanup_session_key(server, mctx);
7766	return (result);
7767}
7768
7769#ifndef HAVE_LMDB
7770static isc_result_t
7771count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7772	isc_result_t result;
7773
7774	/* The new zone file may not exist. That is OK. */
7775	if (!isc_file_exists(view->new_zone_file)) {
7776		*num_zonesp = 0;
7777		return (ISC_R_SUCCESS);
7778	}
7779
7780	/*
7781	 * In the case of NZF files, we also parse the configuration in
7782	 * the file at this stage.
7783	 *
7784	 * This may be called in multiple views, so we reset
7785	 * the parser each time.
7786	 */
7787	cfg_parser_reset(named_g_addparser);
7788	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
7789				&cfg_type_addzoneconf, &nzcfg->nzf_config);
7790	if (result == ISC_R_SUCCESS) {
7791		int num_zones;
7792
7793		num_zones = count_zones(nzcfg->nzf_config);
7794		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7795			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7796			      "NZF file '%s' contains %d zones",
7797			      view->new_zone_file, num_zones);
7798		if (num_zonesp != NULL) {
7799			*num_zonesp = num_zones;
7800		}
7801	} else {
7802		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7803			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7804			      "Error parsing NZF file '%s': %s",
7805			      view->new_zone_file, isc_result_totext(result));
7806	}
7807
7808	return (result);
7809}
7810
7811#else /* HAVE_LMDB */
7812
7813static isc_result_t
7814count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7815	isc_result_t result;
7816	int n;
7817
7818	UNUSED(nzcfg);
7819
7820	REQUIRE(num_zonesp != NULL);
7821
7822	LOCK(&view->new_zone_lock);
7823
7824	CHECK(migrate_nzf(view));
7825
7826	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7827		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7828		      "loading NZD zone count from '%s' "
7829		      "for view '%s'",
7830		      view->new_zone_db, view->name);
7831
7832	CHECK(nzd_count(view, &n));
7833
7834	*num_zonesp = n;
7835
7836	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7837		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7838		      "NZD database '%s' contains %d zones", view->new_zone_db,
7839		      n);
7840
7841cleanup:
7842	if (result != ISC_R_SUCCESS) {
7843		*num_zonesp = 0;
7844	}
7845
7846	UNLOCK(&view->new_zone_lock);
7847
7848	return (ISC_R_SUCCESS);
7849}
7850
7851#endif /* HAVE_LMDB */
7852
7853static isc_result_t
7854setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7855	       cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx,
7856	       int *num_zones) {
7857	isc_result_t result = ISC_R_SUCCESS;
7858	bool allow = false;
7859	ns_cfgctx_t *nzcfg = NULL;
7860	const cfg_obj_t *maps[4];
7861	const cfg_obj_t *options = NULL, *voptions = NULL;
7862	const cfg_obj_t *nz = NULL;
7863	const cfg_obj_t *nzdir = NULL;
7864	const char *dir = NULL;
7865	const cfg_obj_t *obj = NULL;
7866	int i = 0;
7867	uint64_t mapsize = 0ULL;
7868
7869	REQUIRE(config != NULL);
7870
7871	if (vconfig != NULL) {
7872		voptions = cfg_tuple_get(vconfig, "options");
7873	}
7874	if (voptions != NULL) {
7875		maps[i++] = voptions;
7876	}
7877	result = cfg_map_get(config, "options", &options);
7878	if (result == ISC_R_SUCCESS) {
7879		maps[i++] = options;
7880	}
7881	maps[i++] = named_g_defaults;
7882	maps[i] = NULL;
7883
7884	result = named_config_get(maps, "allow-new-zones", &nz);
7885	if (result == ISC_R_SUCCESS) {
7886		allow = cfg_obj_asboolean(nz);
7887	}
7888	result = named_config_get(maps, "new-zones-directory", &nzdir);
7889	if (result == ISC_R_SUCCESS) {
7890		dir = cfg_obj_asstring(nzdir);
7891		result = isc_file_isdirectory(dir);
7892		if (result != ISC_R_SUCCESS) {
7893			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
7894				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7895				      "invalid new-zones-directory %s: %s", dir,
7896				      isc_result_totext(result));
7897			return (result);
7898		}
7899		if (!isc_file_isdirwritable(dir)) {
7900			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7901				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7902				      "new-zones-directory '%s' "
7903				      "is not writable",
7904				      dir);
7905			return (ISC_R_NOPERM);
7906		}
7907
7908		dns_view_setnewzonedir(view, dir);
7909	}
7910
7911#ifdef HAVE_LMDB
7912	result = named_config_get(maps, "lmdb-mapsize", &obj);
7913	if (result == ISC_R_SUCCESS && obj != NULL) {
7914		mapsize = cfg_obj_asuint64(obj);
7915		if (mapsize < (1ULL << 20)) { /* 1 megabyte */
7916			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7917				    "'lmdb-mapsize "
7918				    "%" PRId64 "' "
7919				    "is too small",
7920				    mapsize);
7921			return (ISC_R_FAILURE);
7922		} else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
7923			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7924				    "'lmdb-mapsize "
7925				    "%" PRId64 "' "
7926				    "is too large",
7927				    mapsize);
7928			return (ISC_R_FAILURE);
7929		}
7930	}
7931#else  /* ifdef HAVE_LMDB */
7932	UNUSED(obj);
7933#endif /* HAVE_LMDB */
7934
7935	/*
7936	 * A non-empty catalog-zones statement implies allow-new-zones
7937	 */
7938	if (!allow) {
7939		const cfg_obj_t *cz = NULL;
7940		result = named_config_get(maps, "catalog-zones", &cz);
7941		if (result == ISC_R_SUCCESS) {
7942			const cfg_listelt_t *e =
7943				cfg_list_first(cfg_tuple_get(cz, "zone list"));
7944			if (e != NULL) {
7945				allow = true;
7946			}
7947		}
7948	}
7949
7950	if (!allow) {
7951		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7952		if (num_zones != NULL) {
7953			*num_zones = 0;
7954		}
7955		return (ISC_R_SUCCESS);
7956	}
7957
7958	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
7959
7960	/*
7961	 * We attach the parser that was used for config as well
7962	 * as the one that will be used for added zones, to avoid
7963	 * a shutdown race later.
7964	 */
7965	memset(nzcfg, 0, sizeof(*nzcfg));
7966	cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
7967	cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
7968	isc_mem_attach(view->mctx, &nzcfg->mctx);
7969	cfg_aclconfctx_attach(actx, &nzcfg->actx);
7970
7971	result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy,
7972				      mapsize);
7973	if (result != ISC_R_SUCCESS) {
7974		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7975		return (result);
7976	}
7977
7978	cfg_obj_attach(config, &nzcfg->config);
7979	if (vconfig != NULL) {
7980		cfg_obj_attach(vconfig, &nzcfg->vconfig);
7981	}
7982
7983	result = count_newzones(view, nzcfg, num_zones);
7984	return (result);
7985}
7986
7987static void
7988configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
7989			     dns_view_t *view) {
7990	const char *zname;
7991	dns_fixedname_t fixorigin;
7992	dns_name_t *origin;
7993	isc_result_t result2;
7994	dns_view_t *pview = NULL;
7995	dns_zone_t *zone = NULL;
7996
7997	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
7998	origin = dns_fixedname_initname(&fixorigin);
7999
8000	result2 = dns_name_fromstring(origin, zname, 0, NULL);
8001	if (result2 != ISC_R_SUCCESS) {
8002		return;
8003	}
8004
8005	result2 = dns_viewlist_find(&named_g_server->viewlist, view->name,
8006				    view->rdclass, &pview);
8007	if (result2 != ISC_R_SUCCESS) {
8008		return;
8009	}
8010
8011	result2 = dns_view_findzone(pview, origin, &zone);
8012	if (result2 != ISC_R_SUCCESS) {
8013		dns_view_detach(&pview);
8014		return;
8015	}
8016
8017	if (result == ISC_R_SUCCESS) {
8018		dns_zone_setviewcommit(zone);
8019	} else {
8020		dns_zone_setviewrevert(zone);
8021	}
8022
8023	dns_zone_detach(&zone);
8024	dns_view_detach(&pview);
8025}
8026
8027#ifndef HAVE_LMDB
8028
8029static isc_result_t
8030configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
8031		   isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
8032	isc_result_t result;
8033	ns_cfgctx_t *nzctx;
8034	const cfg_obj_t *zonelist;
8035	const cfg_listelt_t *element;
8036
8037	nzctx = view->new_zone_config;
8038	if (nzctx == NULL || nzctx->nzf_config == NULL) {
8039		return (ISC_R_SUCCESS);
8040	}
8041
8042	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8043		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8044		      "loading additional zones for view '%s'", view->name);
8045
8046	zonelist = NULL;
8047	cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
8048
8049	for (element = cfg_list_first(zonelist); element != NULL;
8050	     element = cfg_list_next(element))
8051	{
8052		const cfg_obj_t *zconfig = cfg_listelt_value(element);
8053		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
8054				     &named_g_server->viewlist,
8055				     &named_g_server->kasplist, actx, true,
8056				     false, false));
8057	}
8058
8059	result = ISC_R_SUCCESS;
8060
8061cleanup:
8062	for (element = cfg_list_first(zonelist); element != NULL;
8063	     element = cfg_list_next(element))
8064	{
8065		const cfg_obj_t *zconfig = cfg_listelt_value(element);
8066		configure_zone_setviewcommit(result, zconfig, view);
8067	}
8068
8069	return (result);
8070}
8071
8072#else /* HAVE_LMDB */
8073
8074static isc_result_t
8075data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text,
8076	    cfg_obj_t **zoneconfig) {
8077	isc_result_t result;
8078	const char *zone_name;
8079	size_t zone_name_len;
8080	const char *zone_config;
8081	size_t zone_config_len;
8082	cfg_obj_t *zoneconf = NULL;
8083	char bufname[DNS_NAME_FORMATSIZE];
8084
8085	REQUIRE(view != NULL);
8086	REQUIRE(key != NULL);
8087	REQUIRE(data != NULL);
8088	REQUIRE(text != NULL);
8089	REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
8090
8091	if (*text == NULL) {
8092		isc_buffer_allocate(view->mctx, text, 256);
8093	} else {
8094		isc_buffer_clear(*text);
8095	}
8096
8097	zone_name = (const char *)key->mv_data;
8098	zone_name_len = key->mv_size;
8099	INSIST(zone_name != NULL && zone_name_len > 0);
8100
8101	zone_config = (const char *)data->mv_data;
8102	zone_config_len = data->mv_size;
8103	INSIST(zone_config != NULL && zone_config_len > 0);
8104
8105	/* zone zonename { config; }; */
8106	result = isc_buffer_reserve(text, 6 + zone_name_len + 2 +
8107						  zone_config_len + 2);
8108	if (result != ISC_R_SUCCESS) {
8109		goto cleanup;
8110	}
8111
8112	CHECK(putstr(text, "zone \""));
8113	CHECK(putmem(text, (const void *)zone_name, zone_name_len));
8114	CHECK(putstr(text, "\" "));
8115	CHECK(putmem(text, (const void *)zone_config, zone_config_len));
8116	CHECK(putstr(text, ";\n"));
8117
8118	snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len,
8119		 zone_name);
8120
8121	cfg_parser_reset(named_g_addparser);
8122	result = cfg_parse_buffer(named_g_addparser, *text, bufname, 0,
8123				  &cfg_type_addzoneconf, 0, &zoneconf);
8124	if (result != ISC_R_SUCCESS) {
8125		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8126			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8127			      "parsing config for zone '%.*s' in "
8128			      "NZD database '%s' failed",
8129			      (int)zone_name_len, zone_name, view->new_zone_db);
8130		goto cleanup;
8131	}
8132
8133	*zoneconfig = zoneconf;
8134	zoneconf = NULL;
8135	result = ISC_R_SUCCESS;
8136
8137cleanup:
8138	if (zoneconf != NULL) {
8139		cfg_obj_destroy(named_g_addparser, &zoneconf);
8140	}
8141
8142	return (result);
8143}
8144
8145/*%
8146 * Prototype for a callback which can be used with for_all_newzone_cfgs().
8147 */
8148typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
8149					 cfg_obj_t *config, cfg_obj_t *vconfig,
8150					 isc_mem_t *mctx, dns_view_t *view,
8151					 cfg_aclconfctx_t *actx);
8152
8153/*%
8154 * For each zone found in a NZD opened by the caller, create an object
8155 * representing its configuration and invoke "callback" with the created
8156 * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all
8157 * these are non-global variables required to invoke configure_zone()).
8158 * Immediately interrupt processing if an error is encountered while
8159 * transforming NZD data into a zone configuration object or if "callback"
8160 * returns an error.
8161 *
8162 * Caller must hold 'view->new_zone_lock'.
8163 */
8164static isc_result_t
8165for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
8166		     cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8167		     cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi) {
8168	const cfg_obj_t *zconfig, *zlist;
8169	isc_result_t result = ISC_R_SUCCESS;
8170	cfg_obj_t *zconfigobj = NULL;
8171	isc_buffer_t *text = NULL;
8172	MDB_cursor *cursor = NULL;
8173	MDB_val data, key;
8174	int status;
8175
8176	status = mdb_cursor_open(txn, dbi, &cursor);
8177	if (status != MDB_SUCCESS) {
8178		return (ISC_R_FAILURE);
8179	}
8180
8181	for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
8182	     status == MDB_SUCCESS;
8183	     status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
8184	{
8185		/*
8186		 * Create a configuration object from data fetched from NZD.
8187		 */
8188		result = data_to_cfg(view, &key, &data, &text, &zconfigobj);
8189		if (result != ISC_R_SUCCESS) {
8190			break;
8191		}
8192
8193		/*
8194		 * Extract zone configuration from configuration object.
8195		 */
8196		zlist = NULL;
8197		result = cfg_map_get(zconfigobj, "zone", &zlist);
8198		if (result != ISC_R_SUCCESS) {
8199			break;
8200		} else if (!cfg_obj_islist(zlist)) {
8201			result = ISC_R_FAILURE;
8202			break;
8203		}
8204		zconfig = cfg_listelt_value(cfg_list_first(zlist));
8205
8206		/*
8207		 * Invoke callback.
8208		 */
8209		result = callback(zconfig, config, vconfig, mctx, view, actx);
8210		if (result != ISC_R_SUCCESS) {
8211			break;
8212		}
8213
8214		/*
8215		 * Destroy the configuration object created in this iteration.
8216		 */
8217		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8218	}
8219
8220	if (text != NULL) {
8221		isc_buffer_free(&text);
8222	}
8223	if (zconfigobj != NULL) {
8224		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8225	}
8226	mdb_cursor_close(cursor);
8227
8228	return (result);
8229}
8230
8231/*%
8232 * Attempt to configure a zone found in NZD and return the result.
8233 */
8234static isc_result_t
8235configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
8236		  cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8237		  cfg_aclconfctx_t *actx) {
8238	return (configure_zone(
8239		config, zconfig, vconfig, mctx, view, &named_g_server->viewlist,
8240		&named_g_server->kasplist, actx, true, false, false));
8241}
8242
8243/*%
8244 * Revert new view assignment for a zone found in NZD.
8245 */
8246static isc_result_t
8247configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config,
8248			 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8249			 cfg_aclconfctx_t *actx) {
8250	UNUSED(config);
8251	UNUSED(vconfig);
8252	UNUSED(mctx);
8253	UNUSED(actx);
8254
8255	configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view);
8256
8257	return (ISC_R_SUCCESS);
8258}
8259
8260static isc_result_t
8261configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
8262		   isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
8263	isc_result_t result;
8264	MDB_txn *txn = NULL;
8265	MDB_dbi dbi;
8266
8267	if (view->new_zone_config == NULL) {
8268		return (ISC_R_SUCCESS);
8269	}
8270
8271	LOCK(&view->new_zone_lock);
8272
8273	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
8274	if (result != ISC_R_SUCCESS) {
8275		UNLOCK(&view->new_zone_lock);
8276		return (ISC_R_SUCCESS);
8277	}
8278
8279	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8280		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8281		      "loading NZD configs from '%s' "
8282		      "for view '%s'",
8283		      view->new_zone_db, view->name);
8284
8285	result = for_all_newzone_cfgs(configure_newzone, config, vconfig, mctx,
8286				      view, actx, txn, dbi);
8287	if (result != ISC_R_SUCCESS) {
8288		/*
8289		 * An error was encountered while attempting to configure zones
8290		 * found in NZD.  As this error may have been caused by a
8291		 * configure_zone() failure, try restoring a sane configuration
8292		 * by reattaching all zones found in NZD to the old view.  If
8293		 * this also fails, too bad, there is nothing more we can do in
8294		 * terms of trying to make things right.
8295		 */
8296		(void)for_all_newzone_cfgs(configure_newzone_revert, config,
8297					   vconfig, mctx, view, actx, txn, dbi);
8298	}
8299
8300	(void)nzd_close(&txn, false);
8301
8302	UNLOCK(&view->new_zone_lock);
8303
8304	return (result);
8305}
8306
8307static isc_result_t
8308get_newzone_config(dns_view_t *view, const char *zonename,
8309		   cfg_obj_t **zoneconfig) {
8310	isc_result_t result;
8311	int status;
8312	cfg_obj_t *zoneconf = NULL;
8313	isc_buffer_t *text = NULL;
8314	MDB_txn *txn = NULL;
8315	MDB_dbi dbi;
8316	MDB_val key, data;
8317	char zname[DNS_NAME_FORMATSIZE];
8318	dns_fixedname_t fname;
8319	dns_name_t *name;
8320	isc_buffer_t b;
8321
8322	INSIST(zoneconfig != NULL && *zoneconfig == NULL);
8323
8324	LOCK(&view->new_zone_lock);
8325
8326	CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
8327
8328	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8329		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8330		      "loading NZD config from '%s' "
8331		      "for zone '%s'",
8332		      view->new_zone_db, zonename);
8333
8334	/* Normalize zone name */
8335	isc_buffer_constinit(&b, zonename, strlen(zonename));
8336	isc_buffer_add(&b, strlen(zonename));
8337	name = dns_fixedname_initname(&fname);
8338	CHECK(dns_name_fromtext(name, &b, dns_rootname, DNS_NAME_DOWNCASE,
8339				NULL));
8340	dns_name_format(name, zname, sizeof(zname));
8341
8342	key.mv_data = zname;
8343	key.mv_size = strlen(zname);
8344
8345	status = mdb_get(txn, dbi, &key, &data);
8346	if (status != MDB_SUCCESS) {
8347		CHECK(ISC_R_FAILURE);
8348	}
8349
8350	CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
8351
8352	*zoneconfig = zoneconf;
8353	zoneconf = NULL;
8354	result = ISC_R_SUCCESS;
8355
8356cleanup:
8357	(void)nzd_close(&txn, false);
8358
8359	UNLOCK(&view->new_zone_lock);
8360
8361	if (zoneconf != NULL) {
8362		cfg_obj_destroy(named_g_addparser, &zoneconf);
8363	}
8364	if (text != NULL) {
8365		isc_buffer_free(&text);
8366	}
8367
8368	return (result);
8369}
8370
8371#endif /* HAVE_LMDB */
8372
8373static int
8374count_zones(const cfg_obj_t *conf) {
8375	const cfg_obj_t *zonelist = NULL;
8376	const cfg_listelt_t *element;
8377	int n = 0;
8378
8379	REQUIRE(conf != NULL);
8380
8381	cfg_map_get(conf, "zone", &zonelist);
8382	for (element = cfg_list_first(zonelist); element != NULL;
8383	     element = cfg_list_next(element))
8384	{
8385		n++;
8386	}
8387
8388	return (n);
8389}
8390
8391static isc_result_t
8392check_lockfile(named_server_t *server, const cfg_obj_t *config,
8393	       bool first_time) {
8394	isc_result_t result;
8395	const char *filename = NULL;
8396	const cfg_obj_t *maps[3];
8397	const cfg_obj_t *options;
8398	const cfg_obj_t *obj;
8399	int i;
8400
8401	i = 0;
8402	options = NULL;
8403	result = cfg_map_get(config, "options", &options);
8404	if (result == ISC_R_SUCCESS) {
8405		maps[i++] = options;
8406	}
8407	maps[i++] = named_g_defaults;
8408	maps[i] = NULL;
8409
8410	obj = NULL;
8411	(void)named_config_get(maps, "lock-file", &obj);
8412
8413	if (!first_time) {
8414		if (obj != NULL && cfg_obj_isstring(obj) &&
8415		    server->lockfile != NULL && !named_g_forcelock &&
8416		    strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
8417		{
8418			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8419				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8420				      "changing 'lock-file' "
8421				      "has no effect until the "
8422				      "server is restarted");
8423		}
8424
8425		return (ISC_R_SUCCESS);
8426	}
8427
8428	if (obj != NULL) {
8429		if (named_g_forcelock) {
8430			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8431				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8432				      "'lock-file' has no effect "
8433				      "because the server was run with -X");
8434			if (named_g_defaultlockfile != NULL) {
8435				server->lockfile = isc_mem_strdup(
8436					server->mctx, named_g_defaultlockfile);
8437			}
8438		} else if (cfg_obj_isvoid(obj)) {
8439			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8440				      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
8441				      "skipping lock-file check");
8442		} else if (cfg_obj_isstring(obj)) {
8443			filename = cfg_obj_asstring(obj);
8444			server->lockfile = isc_mem_strdup(server->mctx,
8445							  filename);
8446		}
8447	} else if (named_g_forcelock && named_g_defaultlockfile != NULL) {
8448		server->lockfile = isc_mem_strdup(server->mctx,
8449						  named_g_defaultlockfile);
8450	}
8451
8452	if (server->lockfile == NULL) {
8453		return (ISC_R_SUCCESS);
8454	}
8455
8456	if (named_os_issingleton(server->lockfile)) {
8457		return (ISC_R_SUCCESS);
8458	}
8459
8460	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8461		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8462		      "could not lock %s; another named "
8463		      "process may be running",
8464		      server->lockfile);
8465	return (ISC_R_FAILURE);
8466}
8467
8468static isc_result_t
8469load_configuration(const char *filename, named_server_t *server,
8470		   bool first_time) {
8471	cfg_obj_t *config = NULL, *bindkeys = NULL;
8472	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
8473	const cfg_listelt_t *element;
8474	const cfg_obj_t *builtin_views;
8475	const cfg_obj_t *maps[3];
8476	const cfg_obj_t *obj;
8477	const cfg_obj_t *options;
8478	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
8479	const cfg_obj_t *kasps;
8480	dns_kasp_t *kasp = NULL;
8481	dns_kasp_t *kasp_next = NULL;
8482	dns_kasp_t *default_kasp = NULL;
8483	dns_kasplist_t tmpkasplist, kasplist;
8484	const cfg_obj_t *views;
8485	dns_view_t *view = NULL;
8486	dns_view_t *view_next = NULL;
8487	dns_viewlist_t tmpviewlist;
8488	dns_viewlist_t viewlist, builtin_viewlist;
8489	in_port_t listen_port, udpport_low, udpport_high;
8490	int i, backlog;
8491	int num_zones = 0;
8492	bool exclusive = false;
8493	isc_interval_t interval;
8494	isc_logconfig_t *logc = NULL;
8495	isc_portset_t *v4portset = NULL;
8496	isc_portset_t *v6portset = NULL;
8497	isc_result_t result, tresult;
8498	uint32_t heartbeat_interval;
8499	uint32_t interface_interval;
8500	uint32_t udpsize;
8501	uint32_t transfer_message_size;
8502	uint32_t recv_tcp_buffer_size;
8503	uint32_t send_tcp_buffer_size;
8504	uint32_t recv_udp_buffer_size;
8505	uint32_t send_udp_buffer_size;
8506	named_cache_t *nsc;
8507	named_cachelist_t cachelist, tmpcachelist;
8508	ns_altsecret_t *altsecret;
8509	ns_altsecretlist_t altsecrets, tmpaltsecrets;
8510	uint32_t softquota = 0;
8511	uint32_t max;
8512	uint64_t initial, idle, keepalive, advertised;
8513	bool loadbalancesockets;
8514	dns_aclenv_t *env =
8515		ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
8516
8517	ISC_LIST_INIT(kasplist);
8518	ISC_LIST_INIT(viewlist);
8519	ISC_LIST_INIT(builtin_viewlist);
8520	ISC_LIST_INIT(cachelist);
8521	ISC_LIST_INIT(altsecrets);
8522
8523	/* Create the ACL configuration context */
8524	if (named_g_aclconfctx != NULL) {
8525		cfg_aclconfctx_detach(&named_g_aclconfctx);
8526	}
8527	CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx));
8528
8529	/*
8530	 * Shut down all dyndb instances.
8531	 */
8532	dns_dyndb_cleanup(false);
8533
8534	/*
8535	 * Parse the global default pseudo-config file.
8536	 */
8537	if (first_time) {
8538		result = named_config_parsedefaults(named_g_parser,
8539						    &named_g_config);
8540		if (result != ISC_R_SUCCESS) {
8541			named_main_earlyfatal("unable to load "
8542					      "internal defaults: %s",
8543					      isc_result_totext(result));
8544		}
8545		RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
8546					  &named_g_defaults) == ISC_R_SUCCESS);
8547	}
8548
8549	/*
8550	 * Parse the configuration file using the new config code.
8551	 */
8552	config = NULL;
8553	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8554		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8555		      "loading configuration from '%s'", filename);
8556	CHECK(cfg_parser_create(named_g_mctx, named_g_lctx, &conf_parser));
8557	cfg_parser_setcallback(conf_parser, directory_callback, NULL);
8558	result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf,
8559				&config);
8560
8561	CHECK(result);
8562
8563	/*
8564	 * Check the validity of the configuration.
8565	 *
8566	 * (Ignore plugin parameters for now; they will be
8567	 * checked later when the modules are actually loaded and
8568	 * registered.)
8569	 */
8570	CHECK(bind9_check_namedconf(config, false, false, named_g_lctx,
8571				    named_g_mctx));
8572
8573	/* Let's recreate the TLS context cache */
8574	if (server->tlsctx_server_cache != NULL) {
8575		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
8576	}
8577
8578	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_server_cache);
8579
8580	if (server->tlsctx_client_cache != NULL) {
8581		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
8582	}
8583
8584	isc_tlsctx_cache_create(named_g_mctx, &server->tlsctx_client_cache);
8585
8586	dns_zonemgr_set_tlsctx_cache(server->zonemgr,
8587				     server->tlsctx_client_cache);
8588
8589	/*
8590	 * Fill in the maps array, used for resolving defaults.
8591	 */
8592	i = 0;
8593	options = NULL;
8594	result = cfg_map_get(config, "options", &options);
8595	if (result == ISC_R_SUCCESS) {
8596		maps[i++] = options;
8597	}
8598	maps[i++] = named_g_defaults;
8599	maps[i] = NULL;
8600
8601#if HAVE_LIBNGHTTP2
8602	obj = NULL;
8603	result = named_config_get(maps, "http-port", &obj);
8604	INSIST(result == ISC_R_SUCCESS);
8605	named_g_httpport = (in_port_t)cfg_obj_asuint32(obj);
8606
8607	obj = NULL;
8608	result = named_config_get(maps, "https-port", &obj);
8609	INSIST(result == ISC_R_SUCCESS);
8610	named_g_httpsport = (in_port_t)cfg_obj_asuint32(obj);
8611
8612	obj = NULL;
8613	result = named_config_get(maps, "http-listener-clients", &obj);
8614	INSIST(result == ISC_R_SUCCESS);
8615	named_g_http_listener_clients = cfg_obj_asuint32(obj);
8616
8617	obj = NULL;
8618	result = named_config_get(maps, "http-streams-per-connection", &obj);
8619	INSIST(result == ISC_R_SUCCESS);
8620	named_g_http_streams_per_conn = cfg_obj_asuint32(obj);
8621#endif
8622
8623	/*
8624	 * If bind.keys exists, load it.  If "dnssec-validation auto"
8625	 * is turned on, the root key found there will be used as a
8626	 * default trust anchor.
8627	 */
8628	obj = NULL;
8629	result = named_config_get(maps, "bindkeys-file", &obj);
8630	INSIST(result == ISC_R_SUCCESS);
8631	CHECKM(setstring(server, &server->bindkeysfile, cfg_obj_asstring(obj)),
8632	       "strdup");
8633	INSIST(server->bindkeysfile != NULL);
8634
8635	if (access(server->bindkeysfile, R_OK) == 0) {
8636		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8637			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8638			      "reading built-in trust anchors "
8639			      "from file '%s'",
8640			      server->bindkeysfile);
8641
8642		CHECK(cfg_parser_create(named_g_mctx, named_g_lctx,
8643					&bindkeys_parser));
8644
8645		result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
8646					&cfg_type_bindkeys, &bindkeys);
8647		if (result != ISC_R_SUCCESS) {
8648			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8649				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8650				      "unable to parse '%s' error '%s'; using "
8651				      "built-in keys instead",
8652				      server->bindkeysfile,
8653				      isc_result_totext(result));
8654		}
8655	} else {
8656		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8657			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8658			      "unable to open '%s'; using built-in keys "
8659			      "instead",
8660			      server->bindkeysfile);
8661	}
8662
8663	/* Ensure exclusive access to configuration data. */
8664	if (!exclusive) {
8665		result = isc_task_beginexclusive(server->task);
8666		RUNTIME_CHECK(result == ISC_R_SUCCESS);
8667		exclusive = true;
8668	}
8669
8670	/*
8671	 * Set process limits, which (usually) needs to be done as root.
8672	 */
8673	set_limits(maps);
8674
8675	/*
8676	 * Check the process lockfile.
8677	 */
8678	CHECK(check_lockfile(server, config, first_time));
8679
8680#if defined(HAVE_GEOIP2)
8681	/*
8682	 * Release any previously opened GeoIP2 databases.
8683	 */
8684	named_geoip_unload();
8685
8686	/*
8687	 * Initialize GeoIP databases from the configured location.
8688	 * This should happen before configuring any ACLs, so that we
8689	 * know what databases are available and can reject any GeoIP
8690	 * ACLs that can't work.
8691	 */
8692	obj = NULL;
8693	result = named_config_get(maps, "geoip-directory", &obj);
8694	INSIST(result == ISC_R_SUCCESS);
8695	if (cfg_obj_isstring(obj)) {
8696		char *dir;
8697		DE_CONST(cfg_obj_asstring(obj), dir);
8698		named_geoip_load(dir);
8699	}
8700	named_g_aclconfctx->geoip = named_g_geoip;
8701#endif /* HAVE_GEOIP2 */
8702
8703	/*
8704	 * Configure various server options.
8705	 */
8706	configure_server_quota(maps, "transfers-out",
8707			       &server->sctx->xfroutquota);
8708	configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
8709	configure_server_quota(maps, "recursive-clients",
8710			       &server->sctx->recursionquota);
8711	configure_server_quota(maps, "update-quota", &server->sctx->updquota);
8712
8713	max = isc_quota_getmax(&server->sctx->recursionquota);
8714	if (max > 1000) {
8715		unsigned margin = ISC_MAX(100, named_g_cpus + 1);
8716		if (margin + 100 > max) {
8717			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8718				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8719				      "'recursive-clients %d' too low when "
8720				      "running with %d worker threads",
8721				      max, named_g_cpus);
8722			CHECK(ISC_R_RANGE);
8723		}
8724		softquota = max - margin;
8725	} else {
8726		softquota = (max * 90) / 100;
8727	}
8728
8729	isc_quota_soft(&server->sctx->recursionquota, softquota);
8730
8731	/*
8732	 * Set "blackhole". Only legal at options level; there is
8733	 * no default.
8734	 */
8735	CHECK(configure_view_acl(NULL, config, NULL, "blackhole", NULL,
8736				 named_g_aclconfctx, named_g_mctx,
8737				 &server->sctx->blackholeacl));
8738	if (server->sctx->blackholeacl != NULL) {
8739		dns_dispatchmgr_setblackhole(named_g_dispatchmgr,
8740					     server->sctx->blackholeacl);
8741	}
8742
8743	/*
8744	 * Set "keep-response-order". Only legal at options or
8745	 * global defaults level.
8746	 */
8747	CHECK(configure_view_acl(NULL, config, named_g_config,
8748				 "keep-response-order", NULL,
8749				 named_g_aclconfctx, named_g_mctx,
8750				 &server->sctx->keepresporder));
8751
8752	obj = NULL;
8753	result = named_config_get(maps, "match-mapped-addresses", &obj);
8754	INSIST(result == ISC_R_SUCCESS);
8755	env->match_mapped = cfg_obj_asboolean(obj);
8756
8757	CHECKM(named_statschannels_configure(named_g_server, config,
8758					     named_g_aclconfctx),
8759	       "configuring statistics server(s)");
8760
8761	/*
8762	 * Configure the network manager
8763	 */
8764	obj = NULL;
8765	result = named_config_get(maps, "tcp-initial-timeout", &obj);
8766	INSIST(result == ISC_R_SUCCESS);
8767	initial = cfg_obj_asuint32(obj) * 100;
8768	if (initial > MAX_INITIAL_TIMEOUT) {
8769		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8770			    "tcp-initial-timeout value is out of range: "
8771			    "lowering to %" PRIu32,
8772			    MAX_INITIAL_TIMEOUT / 100);
8773		initial = MAX_INITIAL_TIMEOUT;
8774	} else if (initial < MIN_INITIAL_TIMEOUT) {
8775		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8776			    "tcp-initial-timeout value is out of range: "
8777			    "raising to %" PRIu32,
8778			    MIN_INITIAL_TIMEOUT / 100);
8779		initial = MIN_INITIAL_TIMEOUT;
8780	}
8781
8782	obj = NULL;
8783	result = named_config_get(maps, "tcp-idle-timeout", &obj);
8784	INSIST(result == ISC_R_SUCCESS);
8785	idle = cfg_obj_asuint32(obj) * 100;
8786	if (idle > MAX_IDLE_TIMEOUT) {
8787		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8788			    "tcp-idle-timeout value is out of range: "
8789			    "lowering to %" PRIu32,
8790			    MAX_IDLE_TIMEOUT / 100);
8791		idle = MAX_IDLE_TIMEOUT;
8792	} else if (idle < MIN_IDLE_TIMEOUT) {
8793		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8794			    "tcp-idle-timeout value is out of range: "
8795			    "raising to %" PRIu32,
8796			    MIN_IDLE_TIMEOUT / 100);
8797		idle = MIN_IDLE_TIMEOUT;
8798	}
8799
8800	obj = NULL;
8801	result = named_config_get(maps, "tcp-keepalive-timeout", &obj);
8802	INSIST(result == ISC_R_SUCCESS);
8803	keepalive = cfg_obj_asuint32(obj) * 100;
8804	if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
8805		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8806			    "tcp-keepalive-timeout value is out of range: "
8807			    "lowering to %" PRIu32,
8808			    MAX_KEEPALIVE_TIMEOUT / 100);
8809		keepalive = MAX_KEEPALIVE_TIMEOUT;
8810	} else if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
8811		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8812			    "tcp-keepalive-timeout value is out of range: "
8813			    "raising to %" PRIu32,
8814			    MIN_KEEPALIVE_TIMEOUT / 100);
8815		keepalive = MIN_KEEPALIVE_TIMEOUT;
8816	}
8817
8818	obj = NULL;
8819	result = named_config_get(maps, "tcp-advertised-timeout", &obj);
8820	INSIST(result == ISC_R_SUCCESS);
8821	advertised = cfg_obj_asuint32(obj) * 100;
8822	if (advertised > MAX_ADVERTISED_TIMEOUT) {
8823		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8824			    "tcp-advertized-timeout value is out of range: "
8825			    "lowering to %" PRIu32,
8826			    MAX_ADVERTISED_TIMEOUT / 100);
8827		advertised = MAX_ADVERTISED_TIMEOUT;
8828	}
8829
8830	isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
8831			   advertised);
8832
8833#define CAP_IF_NOT_ZERO(v, min, max) \
8834	if (v > 0 && v < min) {      \
8835		v = min;             \
8836	} else if (v > max) {        \
8837		v = max;             \
8838	}
8839
8840	/* Set the kernel send and receive buffer sizes */
8841	obj = NULL;
8842	result = named_config_get(maps, "tcp-receive-buffer", &obj);
8843	INSIST(result == ISC_R_SUCCESS);
8844	recv_tcp_buffer_size = cfg_obj_asuint32(obj);
8845	CAP_IF_NOT_ZERO(recv_tcp_buffer_size, 4096, INT32_MAX);
8846
8847	obj = NULL;
8848	result = named_config_get(maps, "tcp-send-buffer", &obj);
8849	INSIST(result == ISC_R_SUCCESS);
8850	send_tcp_buffer_size = cfg_obj_asuint32(obj);
8851	CAP_IF_NOT_ZERO(send_tcp_buffer_size, 4096, INT32_MAX);
8852
8853	obj = NULL;
8854	result = named_config_get(maps, "udp-receive-buffer", &obj);
8855	INSIST(result == ISC_R_SUCCESS);
8856	recv_udp_buffer_size = cfg_obj_asuint32(obj);
8857	CAP_IF_NOT_ZERO(recv_udp_buffer_size, 4096, INT32_MAX);
8858
8859	obj = NULL;
8860	result = named_config_get(maps, "udp-send-buffer", &obj);
8861	INSIST(result == ISC_R_SUCCESS);
8862	send_udp_buffer_size = cfg_obj_asuint32(obj);
8863	CAP_IF_NOT_ZERO(send_udp_buffer_size, 4096, INT32_MAX);
8864
8865	isc_nm_setnetbuffers(named_g_netmgr, recv_tcp_buffer_size,
8866			     send_tcp_buffer_size, recv_udp_buffer_size,
8867			     send_udp_buffer_size);
8868
8869#undef CAP_IF_NOT_ZERO
8870
8871	/*
8872	 * Configure sets of UDP query source ports.
8873	 */
8874	CHECKM(isc_portset_create(named_g_mctx, &v4portset), "creating UDP "
8875							     "port set");
8876	CHECKM(isc_portset_create(named_g_mctx, &v6portset), "creating UDP "
8877							     "port set");
8878
8879	usev4ports = NULL;
8880	usev6ports = NULL;
8881	avoidv4ports = NULL;
8882	avoidv6ports = NULL;
8883
8884	(void)named_config_get(maps, "use-v4-udp-ports", &usev4ports);
8885	if (usev4ports != NULL) {
8886		portset_fromconf(v4portset, usev4ports, true);
8887	} else {
8888		CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
8889					       &udpport_high),
8890		       "get the default UDP/IPv4 port range");
8891		if (udpport_low == udpport_high) {
8892			isc_portset_add(v4portset, udpport_low);
8893		} else {
8894			isc_portset_addrange(v4portset, udpport_low,
8895					     udpport_high);
8896		}
8897		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) {
8898			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8899				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8900				      "using default UDP/IPv4 port range: "
8901				      "[%d, %d]",
8902				      udpport_low, udpport_high);
8903		}
8904	}
8905	(void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
8906	if (avoidv4ports != NULL) {
8907		portset_fromconf(v4portset, avoidv4ports, false);
8908	}
8909
8910	(void)named_config_get(maps, "use-v6-udp-ports", &usev6ports);
8911	if (usev6ports != NULL) {
8912		portset_fromconf(v6portset, usev6ports, true);
8913	} else {
8914		CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
8915					       &udpport_high),
8916		       "get the default UDP/IPv6 port range");
8917		if (udpport_low == udpport_high) {
8918			isc_portset_add(v6portset, udpport_low);
8919		} else {
8920			isc_portset_addrange(v6portset, udpport_low,
8921					     udpport_high);
8922		}
8923		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) {
8924			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8925				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8926				      "using default UDP/IPv6 port range: "
8927				      "[%d, %d]",
8928				      udpport_low, udpport_high);
8929		}
8930	}
8931	(void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
8932	if (avoidv6ports != NULL) {
8933		portset_fromconf(v6portset, avoidv6ports, false);
8934	}
8935
8936	dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset,
8937				      v6portset);
8938
8939	/*
8940	 * Set the EDNS UDP size when we don't match a view.
8941	 */
8942	obj = NULL;
8943	result = named_config_get(maps, "edns-udp-size", &obj);
8944	INSIST(result == ISC_R_SUCCESS);
8945	udpsize = cfg_obj_asuint32(obj);
8946	if (udpsize < 512) {
8947		udpsize = 512;
8948	}
8949	if (udpsize > 4096) {
8950		udpsize = 4096;
8951	}
8952	server->sctx->udpsize = (uint16_t)udpsize;
8953
8954	/* Set the transfer message size for TCP */
8955	obj = NULL;
8956	result = named_config_get(maps, "transfer-message-size", &obj);
8957	INSIST(result == ISC_R_SUCCESS);
8958	transfer_message_size = cfg_obj_asuint32(obj);
8959	if (transfer_message_size < 512) {
8960		transfer_message_size = 512;
8961	} else if (transfer_message_size > 65535) {
8962		transfer_message_size = 65535;
8963	}
8964	server->sctx->transfer_tcp_message_size =
8965		(uint16_t)transfer_message_size;
8966
8967	/*
8968	 * Configure the zone manager.
8969	 */
8970	obj = NULL;
8971	result = named_config_get(maps, "transfers-in", &obj);
8972	INSIST(result == ISC_R_SUCCESS);
8973	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
8974
8975	obj = NULL;
8976	result = named_config_get(maps, "transfers-per-ns", &obj);
8977	INSIST(result == ISC_R_SUCCESS);
8978	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
8979
8980	obj = NULL;
8981	result = named_config_get(maps, "notify-rate", &obj);
8982	INSIST(result == ISC_R_SUCCESS);
8983	dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
8984
8985	obj = NULL;
8986	result = named_config_get(maps, "startup-notify-rate", &obj);
8987	INSIST(result == ISC_R_SUCCESS);
8988	dns_zonemgr_setstartupnotifyrate(server->zonemgr,
8989					 cfg_obj_asuint32(obj));
8990
8991	obj = NULL;
8992	result = named_config_get(maps, "serial-query-rate", &obj);
8993	INSIST(result == ISC_R_SUCCESS);
8994	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
8995
8996	/*
8997	 * Determine which port to use for listening for incoming connections.
8998	 */
8999	if (named_g_port != 0) {
9000		listen_port = named_g_port;
9001	} else {
9002		CHECKM(named_config_getport(config, "port", &listen_port),
9003		       "port");
9004	}
9005
9006	/*
9007	 * Find the listen queue depth.
9008	 */
9009	obj = NULL;
9010	result = named_config_get(maps, "tcp-listen-queue", &obj);
9011	INSIST(result == ISC_R_SUCCESS);
9012	backlog = cfg_obj_asuint32(obj);
9013	if ((backlog > 0) && (backlog < 10)) {
9014		backlog = 10;
9015	}
9016	ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
9017
9018	obj = NULL;
9019	result = named_config_get(maps, "reuseport", &obj);
9020	INSIST(result == ISC_R_SUCCESS);
9021	loadbalancesockets = cfg_obj_asboolean(obj);
9022#if HAVE_SO_REUSEPORT_LB
9023	if (first_time) {
9024		isc_nm_setloadbalancesockets(named_g_netmgr,
9025					     cfg_obj_asboolean(obj));
9026	} else if (loadbalancesockets !=
9027		   isc_nm_getloadbalancesockets(named_g_netmgr))
9028	{
9029		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
9030			    "changing reuseport value requires server restart");
9031	}
9032#else
9033	if (loadbalancesockets) {
9034		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
9035			    "reuseport has no effect on this system");
9036	}
9037#endif
9038
9039	/*
9040	 * Configure the interface manager according to the "listen-on"
9041	 * statement.
9042	 */
9043	{
9044		const cfg_obj_t *clistenon = NULL;
9045		ns_listenlist_t *listenon = NULL;
9046
9047		clistenon = NULL;
9048		/*
9049		 * Even though listen-on is present in the default
9050		 * configuration, this way is easier.
9051		 */
9052		if (options != NULL) {
9053			(void)cfg_map_get(options, "listen-on", &clistenon);
9054		}
9055		if (clistenon != NULL) {
9056			CHECK(listenlist_fromconfig(
9057				clistenon, config, named_g_aclconfctx,
9058				named_g_mctx, AF_INET,
9059				server->tlsctx_server_cache, &listenon));
9060		} else {
9061			/*
9062			 * Not specified, use default.
9063			 */
9064			CHECK(ns_listenlist_default(named_g_mctx, listen_port,
9065						    true, AF_INET, &listenon));
9066		}
9067		if (listenon != NULL) {
9068			ns_interfacemgr_setlistenon4(server->interfacemgr,
9069						     listenon);
9070			ns_listenlist_detach(&listenon);
9071		}
9072	}
9073	/*
9074	 * Ditto for IPv6.
9075	 */
9076	{
9077		const cfg_obj_t *clistenon = NULL;
9078		ns_listenlist_t *listenon = NULL;
9079
9080		if (options != NULL) {
9081			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
9082		}
9083		if (clistenon != NULL) {
9084			CHECK(listenlist_fromconfig(
9085				clistenon, config, named_g_aclconfctx,
9086				named_g_mctx, AF_INET6,
9087				server->tlsctx_server_cache, &listenon));
9088		} else {
9089			/*
9090			 * Not specified, use default.
9091			 */
9092			CHECK(ns_listenlist_default(named_g_mctx, listen_port,
9093						    true, AF_INET6, &listenon));
9094		}
9095		if (listenon != NULL) {
9096			ns_interfacemgr_setlistenon6(server->interfacemgr,
9097						     listenon);
9098			ns_listenlist_detach(&listenon);
9099		}
9100	}
9101
9102	/*
9103	 * Rescan the interface list to pick up changes in the
9104	 * listen-on option.  It's important that we do this before we try
9105	 * to configure the query source, since the dispatcher we use might
9106	 * be shared with an interface.
9107	 */
9108	result = ns_interfacemgr_scan(server->interfacemgr, true, true);
9109
9110	/*
9111	 * Check that named is able to TCP listen on at least one
9112	 * interface. Otherwise, another named process could be running
9113	 * and we should fail.
9114	 */
9115	if (first_time && (result == ISC_R_ADDRINUSE)) {
9116		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9117			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9118			      "unable to listen on any configured interfaces");
9119		result = ISC_R_FAILURE;
9120		goto cleanup;
9121	}
9122
9123	/*
9124	 * Arrange for further interface scanning to occur periodically
9125	 * as specified by the "interface-interval" option.
9126	 */
9127	obj = NULL;
9128	result = named_config_get(maps, "interface-interval", &obj);
9129	INSIST(result == ISC_R_SUCCESS);
9130	interface_interval = cfg_obj_asduration(obj);
9131	if (interface_interval == 0) {
9132		CHECK(isc_timer_reset(server->interface_timer,
9133				      isc_timertype_inactive, NULL, NULL,
9134				      true));
9135	} else if (server->interface_interval != interface_interval) {
9136		isc_interval_set(&interval, interface_interval, 0);
9137		CHECK(isc_timer_reset(server->interface_timer,
9138				      isc_timertype_ticker, NULL, &interval,
9139				      false));
9140	}
9141	server->interface_interval = interface_interval;
9142
9143	/*
9144	 * Enable automatic interface scans.
9145	 */
9146	obj = NULL;
9147	result = named_config_get(maps, "automatic-interface-scan", &obj);
9148	INSIST(result == ISC_R_SUCCESS);
9149	server->sctx->interface_auto = cfg_obj_asboolean(obj);
9150
9151	/*
9152	 * Configure the dialup heartbeat timer.
9153	 */
9154	obj = NULL;
9155	result = named_config_get(maps, "heartbeat-interval", &obj);
9156	INSIST(result == ISC_R_SUCCESS);
9157	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
9158	if (heartbeat_interval == 0) {
9159		CHECK(isc_timer_reset(server->heartbeat_timer,
9160				      isc_timertype_inactive, NULL, NULL,
9161				      true));
9162	} else if (server->heartbeat_interval != heartbeat_interval) {
9163		isc_interval_set(&interval, heartbeat_interval, 0);
9164		CHECK(isc_timer_reset(server->heartbeat_timer,
9165				      isc_timertype_ticker, NULL, &interval,
9166				      false));
9167	}
9168	server->heartbeat_interval = heartbeat_interval;
9169
9170	isc_interval_set(&interval, 1200, 0);
9171	CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
9172			      &interval, false));
9173
9174	isc_interval_set(&interval, named_g_tat_interval, 0);
9175	CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker, NULL,
9176			      &interval, false));
9177
9178	/*
9179	 * Write the PID file.
9180	 */
9181	obj = NULL;
9182	if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) {
9183		if (cfg_obj_isvoid(obj)) {
9184			named_os_writepidfile(NULL, first_time);
9185		} else {
9186			named_os_writepidfile(cfg_obj_asstring(obj),
9187					      first_time);
9188		}
9189	} else {
9190		named_os_writepidfile(named_g_defaultpidfile, first_time);
9191	}
9192
9193	/*
9194	 * Configure the server-wide session key.  This must be done before
9195	 * configure views because zone configuration may need to know
9196	 * session-keyname.
9197	 *
9198	 * Failure of session key generation isn't fatal at this time; if it
9199	 * turns out that a session key is really needed but doesn't exist,
9200	 * we'll treat it as a fatal error then.
9201	 */
9202	(void)configure_session_key(maps, server, named_g_mctx, first_time);
9203
9204	/*
9205	 * Create the built-in kasp policies ("default", "insecure").
9206	 */
9207	kasps = NULL;
9208	(void)cfg_map_get(named_g_config, "dnssec-policy", &kasps);
9209	for (element = cfg_list_first(kasps); element != NULL;
9210	     element = cfg_list_next(element))
9211	{
9212		cfg_obj_t *kconfig = cfg_listelt_value(element);
9213
9214		kasp = NULL;
9215		CHECK(cfg_kasp_fromconfig(kconfig, default_kasp, named_g_mctx,
9216					  named_g_lctx, &kasplist, &kasp));
9217		INSIST(kasp != NULL);
9218		dns_kasp_freeze(kasp);
9219
9220		/* Insist that the first built-in policy is the default one. */
9221		if (default_kasp == NULL) {
9222			INSIST(strcmp(dns_kasp_getname(kasp), "default") == 0);
9223			dns_kasp_attach(kasp, &default_kasp);
9224		}
9225
9226		dns_kasp_detach(&kasp);
9227	}
9228	INSIST(default_kasp != NULL);
9229
9230	/*
9231	 * Create the DNSSEC key and signing policies (KASP).
9232	 */
9233	kasps = NULL;
9234	(void)cfg_map_get(config, "dnssec-policy", &kasps);
9235	for (element = cfg_list_first(kasps); element != NULL;
9236	     element = cfg_list_next(element))
9237	{
9238		cfg_obj_t *kconfig = cfg_listelt_value(element);
9239		kasp = NULL;
9240		CHECK(cfg_kasp_fromconfig(kconfig, default_kasp, named_g_mctx,
9241					  named_g_lctx, &kasplist, &kasp));
9242		INSIST(kasp != NULL);
9243		dns_kasp_freeze(kasp);
9244		dns_kasp_detach(&kasp);
9245	}
9246
9247	dns_kasp_detach(&default_kasp);
9248	tmpkasplist = server->kasplist;
9249	server->kasplist = kasplist;
9250	kasplist = tmpkasplist;
9251
9252	/*
9253	 * Configure the views.
9254	 */
9255	views = NULL;
9256	(void)cfg_map_get(config, "view", &views);
9257
9258	/*
9259	 * Create the views and count all the configured zones in
9260	 * order to correctly size the zone manager's task table.
9261	 * (We only count zones for configured views; the built-in
9262	 * "bind" view can be ignored as it only adds a negligible
9263	 * number of zones.)
9264	 *
9265	 * If we're allowing new zones, we need to be able to find the
9266	 * new zone file and count those as well.  So we setup the new
9267	 * zone configuration context, but otherwise view configuration
9268	 * waits until after the zone manager's task list has been sized.
9269	 */
9270	for (element = cfg_list_first(views); element != NULL;
9271	     element = cfg_list_next(element))
9272	{
9273		cfg_obj_t *vconfig = cfg_listelt_value(element);
9274		const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
9275		int nzf_num_zones;
9276
9277		view = NULL;
9278
9279		CHECK(create_view(vconfig, &viewlist, &view));
9280		INSIST(view != NULL);
9281
9282		num_zones += count_zones(voptions);
9283
9284		CHECK(setup_newzones(view, config, vconfig, conf_parser,
9285				     named_g_aclconfctx, &nzf_num_zones));
9286		num_zones += nzf_num_zones;
9287
9288		dns_view_detach(&view);
9289	}
9290
9291	/*
9292	 * If there were no explicit views then we do the default
9293	 * view here.
9294	 */
9295	if (views == NULL) {
9296		int nzf_num_zones;
9297
9298		CHECK(create_view(NULL, &viewlist, &view));
9299		INSIST(view != NULL);
9300
9301		num_zones = count_zones(config);
9302
9303		CHECK(setup_newzones(view, config, NULL, conf_parser,
9304				     named_g_aclconfctx, &nzf_num_zones));
9305		num_zones += nzf_num_zones;
9306
9307		dns_view_detach(&view);
9308	}
9309
9310	/*
9311	 * Zones have been counted; set the zone manager task pool size.
9312	 */
9313	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9314		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9315		      "sizing zone task pool based on %d zones", num_zones);
9316	CHECK(dns_zonemgr_setsize(named_g_server->zonemgr, num_zones));
9317
9318	/*
9319	 * Configure and freeze all explicit views.  Explicit
9320	 * views that have zones were already created at parsing
9321	 * time, but views with no zones must be created here.
9322	 */
9323	for (element = cfg_list_first(views); element != NULL;
9324	     element = cfg_list_next(element))
9325	{
9326		cfg_obj_t *vconfig = cfg_listelt_value(element);
9327
9328		view = NULL;
9329		CHECK(find_view(vconfig, &viewlist, &view));
9330		CHECK(configure_view(view, &viewlist, config, vconfig,
9331				     &cachelist, &server->kasplist, bindkeys,
9332				     named_g_mctx, named_g_aclconfctx, true));
9333		dns_view_freeze(view);
9334		dns_view_detach(&view);
9335	}
9336
9337	/*
9338	 * Make sure we have a default view if and only if there
9339	 * were no explicit views.
9340	 */
9341	if (views == NULL) {
9342		view = NULL;
9343		CHECK(find_view(NULL, &viewlist, &view));
9344		CHECK(configure_view(view, &viewlist, config, NULL, &cachelist,
9345				     &server->kasplist, bindkeys, named_g_mctx,
9346				     named_g_aclconfctx, true));
9347		dns_view_freeze(view);
9348		dns_view_detach(&view);
9349	}
9350
9351	/*
9352	 * Create (or recreate) the built-in views.
9353	 */
9354	builtin_views = NULL;
9355	RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) ==
9356		      ISC_R_SUCCESS);
9357	for (element = cfg_list_first(builtin_views); element != NULL;
9358	     element = cfg_list_next(element))
9359	{
9360		cfg_obj_t *vconfig = cfg_listelt_value(element);
9361
9362		CHECK(create_view(vconfig, &builtin_viewlist, &view));
9363		CHECK(configure_view(view, &viewlist, config, vconfig,
9364				     &cachelist, &server->kasplist, bindkeys,
9365				     named_g_mctx, named_g_aclconfctx, false));
9366		dns_view_freeze(view);
9367		dns_view_detach(&view);
9368		view = NULL;
9369	}
9370
9371	/* Now combine the two viewlists into one */
9372	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9373
9374	/*
9375	 * Commit any dns_zone_setview() calls on all zones in the new
9376	 * view.
9377	 */
9378	for (view = ISC_LIST_HEAD(viewlist); view != NULL;
9379	     view = ISC_LIST_NEXT(view, link))
9380	{
9381		dns_view_setviewcommit(view);
9382	}
9383
9384	/* Swap our new view list with the production one. */
9385	tmpviewlist = server->viewlist;
9386	server->viewlist = viewlist;
9387	viewlist = tmpviewlist;
9388
9389	/* Make the view list available to each of the views */
9390	view = ISC_LIST_HEAD(server->viewlist);
9391	while (view != NULL) {
9392		view->viewlist = &server->viewlist;
9393		view = ISC_LIST_NEXT(view, link);
9394	}
9395
9396	/* Swap our new cache list with the production one. */
9397	tmpcachelist = server->cachelist;
9398	server->cachelist = cachelist;
9399	cachelist = tmpcachelist;
9400
9401	/* Load the TKEY information from the configuration. */
9402	if (options != NULL) {
9403		dns_tkeyctx_t *t = NULL;
9404		CHECKM(named_tkeyctx_fromconfig(options, named_g_mctx, &t),
9405		       "configuring TKEY");
9406		if (server->sctx->tkeyctx != NULL) {
9407			dns_tkeyctx_destroy(&server->sctx->tkeyctx);
9408		}
9409		server->sctx->tkeyctx = t;
9410	}
9411
9412	/*
9413	 * Bind the control port(s).
9414	 */
9415	CHECKM(named_controls_configure(named_g_server->controls, config,
9416					named_g_aclconfctx),
9417	       "binding control channel(s)");
9418
9419#ifdef HAVE_LMDB
9420	/*
9421	 * If we're using LMDB, we may have created newzones databases
9422	 * as root, making it impossible to reopen them later after
9423	 * switching to a new userid. We close them now, and reopen
9424	 * after relinquishing privileges them.
9425	 */
9426	if (first_time) {
9427		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9428		     view = ISC_LIST_NEXT(view, link))
9429		{
9430			nzd_env_close(view);
9431		}
9432	}
9433#endif /* HAVE_LMDB */
9434
9435	/*
9436	 * Relinquish root privileges.
9437	 */
9438	if (first_time) {
9439		named_os_changeuser();
9440	}
9441
9442#if 0
9443	/*
9444	 * Check that the working directory is writable.
9445	 */
9446	if (!isc_file_isdirwritable(".")) {
9447		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9448			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9449			      "the working directory is not writable");
9450		result = ISC_R_NOPERM;
9451		goto cleanup;
9452	}
9453#endif
9454
9455#ifdef HAVE_LMDB
9456	/*
9457	 * Reopen NZD databases.
9458	 */
9459	if (first_time) {
9460		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9461		     view = ISC_LIST_NEXT(view, link))
9462		{
9463			nzd_env_reopen(view);
9464		}
9465	}
9466#endif /* HAVE_LMDB */
9467
9468	/*
9469	 * Configure the logging system.
9470	 *
9471	 * Do this after changing UID to make sure that any log
9472	 * files specified in named.conf get created by the
9473	 * unprivileged user, not root.
9474	 */
9475	if (named_g_logstderr) {
9476		const cfg_obj_t *logobj = NULL;
9477
9478		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9479			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9480			      "not using config file logging "
9481			      "statement for logging due to "
9482			      "-g option");
9483
9484		(void)cfg_map_get(config, "logging", &logobj);
9485		if (logobj != NULL) {
9486			result = named_logconfig(NULL, logobj);
9487			if (result != ISC_R_SUCCESS) {
9488				isc_log_write(
9489					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9490					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9491					"checking logging configuration "
9492					"failed: %s",
9493					isc_result_totext(result));
9494				goto cleanup;
9495			}
9496		}
9497	} else {
9498		const cfg_obj_t *logobj = NULL;
9499
9500		isc_logconfig_create(named_g_lctx, &logc);
9501
9502		logobj = NULL;
9503		(void)cfg_map_get(config, "logging", &logobj);
9504		if (logobj != NULL) {
9505			CHECKM(named_logconfig(logc, logobj),
9506			       "configuring logging");
9507		} else {
9508			named_log_setdefaultchannels(logc);
9509			named_log_setdefaultsslkeylogfile(logc);
9510			CHECKM(named_log_setunmatchedcategory(logc),
9511			       "setting up default 'category unmatched'");
9512			CHECKM(named_log_setdefaultcategory(logc),
9513			       "setting up default 'category default'");
9514		}
9515
9516		isc_logconfig_use(named_g_lctx, logc);
9517		logc = NULL;
9518
9519		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9520			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9521			      "now using logging configuration from "
9522			      "config file");
9523	}
9524
9525	/*
9526	 * Set the default value of the query logging flag depending
9527	 * whether a "queries" category has been defined.  This is
9528	 * a disgusting hack, but we need to do this for BIND 8
9529	 * compatibility.
9530	 */
9531	if (first_time) {
9532		const cfg_obj_t *logobj = NULL;
9533		const cfg_obj_t *categories = NULL;
9534
9535		obj = NULL;
9536		if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
9537			ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES,
9538					    cfg_obj_asboolean(obj));
9539		} else {
9540			(void)cfg_map_get(config, "logging", &logobj);
9541			if (logobj != NULL) {
9542				(void)cfg_map_get(logobj, "category",
9543						  &categories);
9544			}
9545			if (categories != NULL) {
9546				for (element = cfg_list_first(categories);
9547				     element != NULL;
9548				     element = cfg_list_next(element))
9549				{
9550					const cfg_obj_t *catobj;
9551					const char *str;
9552
9553					obj = cfg_listelt_value(element);
9554					catobj = cfg_tuple_get(obj, "name");
9555					str = cfg_obj_asstring(catobj);
9556					if (strcasecmp(str, "queries") == 0) {
9557						ns_server_setoption(
9558							server->sctx,
9559							NS_SERVER_LOGQUERIES,
9560							true);
9561					}
9562				}
9563			}
9564		}
9565	}
9566
9567	obj = NULL;
9568	if (options != NULL &&
9569	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
9570	{
9571		named_g_memstatistics = cfg_obj_asboolean(obj);
9572	} else {
9573		named_g_memstatistics =
9574			((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
9575	}
9576
9577	obj = NULL;
9578	if (named_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
9579	{
9580		named_main_setmemstats(cfg_obj_asstring(obj));
9581	} else if (named_g_memstatistics) {
9582		named_main_setmemstats("named.memstats");
9583	} else {
9584		named_main_setmemstats(NULL);
9585	}
9586
9587	obj = NULL;
9588	result = named_config_get(maps, "statistics-file", &obj);
9589	INSIST(result == ISC_R_SUCCESS);
9590	CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
9591	       "strdup");
9592
9593	obj = NULL;
9594	result = named_config_get(maps, "dump-file", &obj);
9595	INSIST(result == ISC_R_SUCCESS);
9596	CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
9597	       "strdup");
9598
9599	obj = NULL;
9600	result = named_config_get(maps, "secroots-file", &obj);
9601	INSIST(result == ISC_R_SUCCESS);
9602	CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
9603	       "strdup");
9604
9605	obj = NULL;
9606	result = named_config_get(maps, "recursing-file", &obj);
9607	INSIST(result == ISC_R_SUCCESS);
9608	CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
9609	       "strdup");
9610
9611	obj = NULL;
9612	result = named_config_get(maps, "version", &obj);
9613	if (result == ISC_R_SUCCESS) {
9614		CHECKM(setoptstring(server, &server->version, obj), "strdup");
9615		server->version_set = true;
9616	} else {
9617		server->version_set = false;
9618	}
9619
9620	obj = NULL;
9621	result = named_config_get(maps, "hostname", &obj);
9622	if (result == ISC_R_SUCCESS) {
9623		CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
9624		server->hostname_set = true;
9625	} else {
9626		server->hostname_set = false;
9627	}
9628
9629	obj = NULL;
9630	result = named_config_get(maps, "server-id", &obj);
9631	server->sctx->usehostname = false;
9632	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
9633		/* The parser translates "hostname" to true */
9634		server->sctx->usehostname = true;
9635		result = ns_server_setserverid(server->sctx, NULL);
9636	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
9637		/* Found a quoted string */
9638		result = ns_server_setserverid(server->sctx,
9639					       cfg_obj_asstring(obj));
9640	} else {
9641		result = ns_server_setserverid(server->sctx, NULL);
9642	}
9643	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9644
9645	obj = NULL;
9646	result = named_config_get(maps, "flush-zones-on-shutdown", &obj);
9647	if (result == ISC_R_SUCCESS) {
9648		server->flushonshutdown = cfg_obj_asboolean(obj);
9649	} else {
9650		server->flushonshutdown = false;
9651	}
9652
9653	obj = NULL;
9654	result = named_config_get(maps, "answer-cookie", &obj);
9655	INSIST(result == ISC_R_SUCCESS);
9656	server->sctx->answercookie = cfg_obj_asboolean(obj);
9657
9658	obj = NULL;
9659	result = named_config_get(maps, "cookie-algorithm", &obj);
9660	INSIST(result == ISC_R_SUCCESS);
9661	if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
9662		server->sctx->cookiealg = ns_cookiealg_siphash24;
9663	} else if (strcasecmp(cfg_obj_asstring(obj), "aes") == 0) {
9664		server->sctx->cookiealg = ns_cookiealg_aes;
9665	} else {
9666		UNREACHABLE();
9667	}
9668
9669	obj = NULL;
9670	result = named_config_get(maps, "cookie-secret", &obj);
9671	if (result == ISC_R_SUCCESS) {
9672		const char *str;
9673		bool first = true;
9674		isc_buffer_t b;
9675		unsigned int usedlength;
9676		unsigned int expectedlength;
9677
9678		for (element = cfg_list_first(obj); element != NULL;
9679		     element = cfg_list_next(element))
9680		{
9681			obj = cfg_listelt_value(element);
9682			str = cfg_obj_asstring(obj);
9683
9684			if (first) {
9685				memset(server->sctx->secret, 0,
9686				       sizeof(server->sctx->secret));
9687				isc_buffer_init(&b, server->sctx->secret,
9688						sizeof(server->sctx->secret));
9689				result = isc_hex_decodestring(str, &b);
9690				if (result != ISC_R_SUCCESS &&
9691				    result != ISC_R_NOSPACE)
9692				{
9693					goto cleanup;
9694				}
9695				first = false;
9696			} else {
9697				altsecret = isc_mem_get(server->sctx->mctx,
9698							sizeof(*altsecret));
9699				isc_buffer_init(&b, altsecret->secret,
9700						sizeof(altsecret->secret));
9701				result = isc_hex_decodestring(str, &b);
9702				if (result != ISC_R_SUCCESS &&
9703				    result != ISC_R_NOSPACE)
9704				{
9705					isc_mem_put(server->sctx->mctx,
9706						    altsecret,
9707						    sizeof(*altsecret));
9708					goto cleanup;
9709				}
9710				ISC_LIST_INITANDAPPEND(altsecrets, altsecret,
9711						       link);
9712			}
9713
9714			usedlength = isc_buffer_usedlength(&b);
9715			switch (server->sctx->cookiealg) {
9716			case ns_cookiealg_siphash24:
9717				expectedlength = ISC_SIPHASH24_KEY_LENGTH;
9718				if (usedlength != expectedlength) {
9719					CHECKM(ISC_R_RANGE, "SipHash-2-4 "
9720							    "cookie-secret "
9721							    "must be 128 bits");
9722				}
9723				break;
9724			case ns_cookiealg_aes:
9725				expectedlength = ISC_AES128_KEYLENGTH;
9726				if (usedlength != expectedlength) {
9727					CHECKM(ISC_R_RANGE, "AES cookie-secret "
9728							    "must be 128 bits");
9729				}
9730				break;
9731			}
9732		}
9733	} else {
9734		isc_nonce_buf(server->sctx->secret,
9735			      sizeof(server->sctx->secret));
9736	}
9737
9738	/*
9739	 * Swap altsecrets lists.
9740	 */
9741	tmpaltsecrets = server->sctx->altsecrets;
9742	server->sctx->altsecrets = altsecrets;
9743	altsecrets = tmpaltsecrets;
9744
9745	(void)named_server_loadnta(server);
9746
9747#ifdef USE_DNSRPS
9748	/*
9749	 * Start and connect to the DNS Response Policy Service
9750	 * daemon, dnsrpzd, for each view that uses DNSRPS.
9751	 */
9752	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9753	     view = ISC_LIST_NEXT(view, link))
9754	{
9755		result = dns_dnsrps_connect(view->rpzs);
9756		if (result != ISC_R_SUCCESS) {
9757			view = NULL;
9758			goto cleanup;
9759		}
9760	}
9761#endif /* ifdef USE_DNSRPS */
9762
9763	result = ISC_R_SUCCESS;
9764
9765cleanup:
9766	if (logc != NULL) {
9767		isc_logconfig_destroy(&logc);
9768	}
9769
9770	if (v4portset != NULL) {
9771		isc_portset_destroy(named_g_mctx, &v4portset);
9772	}
9773
9774	if (v6portset != NULL) {
9775		isc_portset_destroy(named_g_mctx, &v6portset);
9776	}
9777
9778	if (conf_parser != NULL) {
9779		if (config != NULL) {
9780			cfg_obj_destroy(conf_parser, &config);
9781		}
9782		cfg_parser_destroy(&conf_parser);
9783	}
9784
9785	if (bindkeys_parser != NULL) {
9786		if (bindkeys != NULL) {
9787			cfg_obj_destroy(bindkeys_parser, &bindkeys);
9788		}
9789		cfg_parser_destroy(&bindkeys_parser);
9790	}
9791
9792	if (view != NULL) {
9793		dns_view_detach(&view);
9794	}
9795
9796	if (kasp != NULL) {
9797		dns_kasp_detach(&kasp);
9798	}
9799
9800	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9801
9802	/*
9803	 * This cleans up either the old production view list
9804	 * or our temporary list depending on whether they
9805	 * were swapped above or not.
9806	 */
9807	for (view = ISC_LIST_HEAD(viewlist); view != NULL; view = view_next) {
9808		view_next = ISC_LIST_NEXT(view, link);
9809		ISC_LIST_UNLINK(viewlist, view, link);
9810		if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
9811		{
9812			dns_view_setviewrevert(view);
9813			(void)dns_zt_apply(view->zonetable, isc_rwlocktype_read,
9814					   false, NULL, removed, view);
9815		}
9816		dns_view_detach(&view);
9817	}
9818
9819	/*
9820	 * Same cleanup for kasp list.
9821	 */
9822	for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
9823		kasp_next = ISC_LIST_NEXT(kasp, link);
9824		ISC_LIST_UNLINK(kasplist, kasp, link);
9825		dns_kasp_detach(&kasp);
9826	}
9827
9828	/* Same cleanup for cache list. */
9829	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
9830		ISC_LIST_UNLINK(cachelist, nsc, link);
9831		dns_cache_detach(&nsc->cache);
9832		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9833	}
9834
9835	/* Cleanup for altsecrets list. */
9836	while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) {
9837		ISC_LIST_UNLINK(altsecrets, altsecret, link);
9838		isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret));
9839	}
9840
9841	/*
9842	 * Record the time of most recent configuration
9843	 */
9844	tresult = isc_time_now(&named_g_configtime);
9845	if (tresult != ISC_R_SUCCESS) {
9846		named_main_earlyfatal("isc_time_now() failed: %s",
9847				      isc_result_totext(result));
9848	}
9849
9850	/* Relinquish exclusive access to configuration data. */
9851	if (exclusive) {
9852		isc_task_endexclusive(server->task);
9853	}
9854
9855	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9856		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9857		      "load_configuration: %s", isc_result_totext(result));
9858
9859	return (result);
9860}
9861
9862static isc_result_t
9863view_loaded(void *arg) {
9864	isc_result_t result;
9865	ns_zoneload_t *zl = (ns_zoneload_t *)arg;
9866
9867	/*
9868	 * Force zone maintenance.  Do this after loading
9869	 * so that we know when we need to force AXFR of
9870	 * secondary zones whose master files are missing.
9871	 *
9872	 * We use the zoneload reference counter to let us
9873	 * know when all views are finished.
9874	 */
9875	if (isc_refcount_decrement(&zl->refs) == 1) {
9876		named_server_t *server = zl->server;
9877		bool reconfig = zl->reconfig;
9878		dns_view_t *view = NULL;
9879
9880		isc_refcount_destroy(&zl->refs);
9881		isc_mem_put(server->mctx, zl, sizeof(*zl));
9882
9883		/*
9884		 * To maintain compatibility with log parsing tools that might
9885		 * be looking for this string after "rndc reconfig", we keep it
9886		 * as it is
9887		 */
9888		if (reconfig) {
9889			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9890				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9891				      "any newly configured zones are now "
9892				      "loaded");
9893		} else {
9894			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9895				      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9896				      "all zones loaded");
9897		}
9898
9899		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9900		     view = ISC_LIST_NEXT(view, link))
9901		{
9902			if (view->managed_keys != NULL) {
9903				result = dns_zone_synckeyzone(
9904					view->managed_keys);
9905				if (result != ISC_R_SUCCESS) {
9906					isc_log_write(
9907						named_g_lctx,
9908						DNS_LOGCATEGORY_DNSSEC,
9909						DNS_LOGMODULE_DNSSEC,
9910						ISC_LOG_ERROR,
9911						"failed to initialize "
9912						"managed-keys for view %s "
9913						"(%s): DNSSEC validation is "
9914						"at risk",
9915						view->name,
9916						isc_result_totext(result));
9917				}
9918			}
9919		}
9920
9921		CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
9922			   "forcing zone maintenance");
9923
9924		named_os_started();
9925
9926#ifdef HAVE_FIPS_MODE
9927		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9928			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9929			      "FIPS mode is %s",
9930			      FIPS_mode() ? "enabled" : "disabled");
9931#endif /* ifdef HAVE_FIPS_MODE */
9932		atomic_store(&server->reload_status, NAMED_RELOAD_DONE);
9933
9934		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9935			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9936			      "running");
9937	}
9938
9939	return (ISC_R_SUCCESS);
9940}
9941
9942static isc_result_t
9943load_zones(named_server_t *server, bool init, bool reconfig) {
9944	isc_result_t result;
9945	isc_taskmgr_t *taskmgr = dns_zonemgr_gettaskmgr(server->zonemgr);
9946	ns_zoneload_t *zl = NULL;
9947	dns_view_t *view = NULL;
9948
9949	zl = isc_mem_get(server->mctx, sizeof(*zl));
9950	zl->server = server;
9951	zl->reconfig = reconfig;
9952
9953	result = isc_task_beginexclusive(server->task);
9954	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9955
9956	isc_refcount_init(&zl->refs, 1);
9957
9958	/*
9959	 * Schedule zones to be loaded from disk.
9960	 */
9961	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9962	     view = ISC_LIST_NEXT(view, link))
9963	{
9964		if (view->managed_keys != NULL) {
9965			result = dns_zone_load(view->managed_keys, false);
9966			if (result != ISC_R_SUCCESS &&
9967			    result != DNS_R_UPTODATE &&
9968			    result != DNS_R_CONTINUE)
9969			{
9970				goto cleanup;
9971			}
9972		}
9973		if (view->redirect != NULL) {
9974			result = dns_zone_load(view->redirect, false);
9975			if (result != ISC_R_SUCCESS &&
9976			    result != DNS_R_UPTODATE &&
9977			    result != DNS_R_CONTINUE)
9978			{
9979				goto cleanup;
9980			}
9981		}
9982
9983		/*
9984		 * 'dns_view_asyncload' calls view_loaded if there are no
9985		 * zones.
9986		 */
9987		isc_refcount_increment(&zl->refs);
9988		result = dns_view_asyncload(view, reconfig, view_loaded, zl);
9989		if (result != ISC_R_SUCCESS) {
9990			isc_refcount_decrement1(&zl->refs);
9991			goto cleanup;
9992		}
9993	}
9994
9995cleanup:
9996	if (isc_refcount_decrement(&zl->refs) == 1) {
9997		isc_refcount_destroy(&zl->refs);
9998		isc_mem_put(server->mctx, zl, sizeof(*zl));
9999	}
10000
10001	if (init) {
10002		/*
10003		 * If we're setting up the server for the first time, set
10004		 * the task manager into privileged mode; this ensures
10005		 * that no other tasks will begin to run until after zone
10006		 * loading is complete. We won't return from exclusive mode
10007		 * until the loading is finished; we can then drop out of
10008		 * privileged mode.
10009		 *
10010		 * We do *not* want to do this in the case of reload or
10011		 * reconfig, as loading a large zone could cause the server
10012		 * to be inactive for too long a time.
10013		 */
10014		isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
10015		isc_task_endexclusive(server->task);
10016		isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal);
10017	} else {
10018		isc_task_endexclusive(server->task);
10019	}
10020
10021	return (result);
10022}
10023
10024static void
10025run_server(isc_task_t *task, isc_event_t *event) {
10026	isc_result_t result;
10027	named_server_t *server = (named_server_t *)event->ev_arg;
10028	dns_geoip_databases_t *geoip;
10029
10030	INSIST(task == server->task);
10031
10032	isc_event_free(&event);
10033
10034	CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_netmgr,
10035					  &named_g_dispatchmgr),
10036		   "creating dispatch manager");
10037
10038	dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
10039
10040#if defined(HAVE_GEOIP2)
10041	geoip = named_g_geoip;
10042#else  /* if defined(HAVE_GEOIP2) */
10043	geoip = NULL;
10044#endif /* if defined(HAVE_GEOIP2) */
10045
10046	CHECKFATAL(ns_interfacemgr_create(named_g_mctx, server->sctx,
10047					  named_g_taskmgr, named_g_timermgr,
10048					  named_g_netmgr, named_g_dispatchmgr,
10049					  server->task, geoip, named_g_cpus,
10050					  true, &server->interfacemgr),
10051		   "creating interface manager");
10052
10053	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
10054				    NULL, NULL, server->task,
10055				    interface_timer_tick, server,
10056				    &server->interface_timer),
10057		   "creating interface timer");
10058
10059	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
10060				    NULL, NULL, server->task,
10061				    heartbeat_timer_tick, server,
10062				    &server->heartbeat_timer),
10063		   "creating heartbeat timer");
10064
10065	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
10066				    NULL, NULL, server->task, tat_timer_tick,
10067				    server, &server->tat_timer),
10068		   "creating trust anchor telemetry timer");
10069
10070	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
10071				    NULL, NULL, server->task, pps_timer_tick,
10072				    server, &server->pps_timer),
10073		   "creating pps timer");
10074
10075	CHECKFATAL(
10076		cfg_parser_create(named_g_mctx, named_g_lctx, &named_g_parser),
10077		"creating default configuration parser");
10078
10079	CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx,
10080				     &named_g_addparser),
10081		   "creating additional configuration parser");
10082
10083	CHECKFATAL(load_configuration(named_g_conffile, server, true),
10084		   "loading configuration");
10085
10086	CHECKFATAL(load_zones(server, true, false), "loading zones");
10087#ifdef ENABLE_AFL
10088	named_g_run_done = true;
10089#endif /* ifdef ENABLE_AFL */
10090}
10091
10092void
10093named_server_flushonshutdown(named_server_t *server, bool flush) {
10094	REQUIRE(NAMED_SERVER_VALID(server));
10095
10096	server->flushonshutdown = flush;
10097}
10098
10099static void
10100shutdown_server(isc_task_t *task, isc_event_t *event) {
10101	isc_result_t result;
10102	dns_view_t *view, *view_next = NULL;
10103	dns_kasp_t *kasp, *kasp_next = NULL;
10104	named_server_t *server = (named_server_t *)event->ev_arg;
10105	bool flush = server->flushonshutdown;
10106	named_cache_t *nsc;
10107
10108	UNUSED(task);
10109	INSIST(task == server->task);
10110
10111	/*
10112	 * We need to shutdown the interface before going
10113	 * exclusive (which would pause the netmgr).
10114	 */
10115	ns_interfacemgr_shutdown(server->interfacemgr);
10116
10117	result = isc_task_beginexclusive(server->task);
10118	RUNTIME_CHECK(result == ISC_R_SUCCESS);
10119
10120	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10121		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "shutting down%s",
10122		      flush ? ": flushing changes" : "");
10123
10124	named_statschannels_shutdown(server);
10125	named_controls_shutdown(server->controls);
10126	end_reserved_dispatches(server, true);
10127	cleanup_session_key(server, server->mctx);
10128
10129	if (named_g_aclconfctx != NULL) {
10130		cfg_aclconfctx_detach(&named_g_aclconfctx);
10131	}
10132
10133	cfg_obj_destroy(named_g_parser, &named_g_config);
10134	cfg_parser_destroy(&named_g_parser);
10135	cfg_parser_destroy(&named_g_addparser);
10136
10137	(void)named_server_saventa(server);
10138
10139	for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL;
10140	     kasp = kasp_next)
10141	{
10142		kasp_next = ISC_LIST_NEXT(kasp, link);
10143		ISC_LIST_UNLINK(server->kasplist, kasp, link);
10144		dns_kasp_detach(&kasp);
10145	}
10146
10147	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
10148	     view = view_next)
10149	{
10150		view_next = ISC_LIST_NEXT(view, link);
10151		ISC_LIST_UNLINK(server->viewlist, view, link);
10152		if (flush) {
10153			dns_view_flushanddetach(&view);
10154		} else {
10155			dns_view_detach(&view);
10156		}
10157	}
10158
10159	/*
10160	 * Shut down all dyndb instances.
10161	 */
10162	dns_dyndb_cleanup(true);
10163
10164	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
10165		ISC_LIST_UNLINK(server->cachelist, nsc, link);
10166		dns_cache_detach(&nsc->cache);
10167		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
10168	}
10169
10170	isc_timer_destroy(&server->interface_timer);
10171	isc_timer_destroy(&server->heartbeat_timer);
10172	isc_timer_destroy(&server->pps_timer);
10173	isc_timer_destroy(&server->tat_timer);
10174
10175	ns_interfacemgr_detach(&server->interfacemgr);
10176
10177	dns_dispatchmgr_detach(&named_g_dispatchmgr);
10178
10179	dns_zonemgr_shutdown(server->zonemgr);
10180
10181	if (named_g_sessionkey != NULL) {
10182		dns_tsigkey_detach(&named_g_sessionkey);
10183		dns_name_free(&named_g_sessionkeyname, server->mctx);
10184	}
10185#if defined(HAVE_GEOIP2)
10186	named_geoip_shutdown();
10187#endif /* HAVE_GEOIP2 */
10188
10189	dns_db_detach(&server->in_roothints);
10190
10191	isc_task_endexclusive(server->task);
10192
10193	isc_task_detach(&server->task);
10194
10195	isc_event_free(&event);
10196}
10197
10198/*%
10199 * Find a view that matches the source and destination addresses of a query.
10200 */
10201static isc_result_t
10202get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
10203		  dns_message_t *message, dns_aclenv_t *env,
10204		  isc_result_t *sigresult, dns_view_t **viewp) {
10205	dns_view_t *view;
10206
10207	REQUIRE(message != NULL);
10208	REQUIRE(sigresult != NULL);
10209	REQUIRE(viewp != NULL && *viewp == NULL);
10210
10211	for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
10212	     view = ISC_LIST_NEXT(view, link))
10213	{
10214		if (message->rdclass == view->rdclass ||
10215		    message->rdclass == dns_rdataclass_any)
10216		{
10217			const dns_name_t *tsig = NULL;
10218
10219			*sigresult = dns_message_rechecksig(message, view);
10220			if (*sigresult == ISC_R_SUCCESS) {
10221				dns_tsigkey_t *tsigkey;
10222
10223				tsigkey = message->tsigkey;
10224				tsig = dns_tsigkey_identity(tsigkey);
10225			}
10226
10227			if (dns_acl_allowed(srcaddr, tsig, view->matchclients,
10228					    env) &&
10229			    dns_acl_allowed(destaddr, tsig,
10230					    view->matchdestinations, env) &&
10231			    !(view->matchrecursiveonly &&
10232			      (message->flags & DNS_MESSAGEFLAG_RD) == 0))
10233			{
10234				dns_view_attach(view, viewp);
10235				return (ISC_R_SUCCESS);
10236			}
10237		}
10238	}
10239
10240	return (ISC_R_NOTFOUND);
10241}
10242
10243void
10244named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
10245	isc_result_t result;
10246	named_server_t *server = isc_mem_get(mctx, sizeof(*server));
10247
10248	*server = (named_server_t){
10249		.mctx = mctx,
10250		.statsfile = isc_mem_strdup(mctx, "named.stats"),
10251		.bindkeysfile = isc_mem_strdup(mctx, named_g_defaultbindkeys),
10252		.dumpfile = isc_mem_strdup(mctx, "named_dump.db"),
10253		.secrootsfile = isc_mem_strdup(mctx, "named.secroots"),
10254		.recfile = isc_mem_strdup(mctx, "named.recursing"),
10255	};
10256
10257#ifdef USE_DNSRPS
10258	CHECKFATAL(dns_dnsrps_server_create(), "initializing RPZ service "
10259					       "interface");
10260#endif /* ifdef USE_DNSRPS */
10261
10262	/* Initialize server data structures. */
10263	ISC_LIST_INIT(server->kasplist);
10264	ISC_LIST_INIT(server->viewlist);
10265
10266	/* Must be first. */
10267	CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine), "initializing "
10268							       "DST");
10269
10270	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
10271				     &server->in_roothints),
10272		   "setting up root hints");
10273
10274	atomic_init(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10275
10276	/*
10277	 * Setup the server task, which is responsible for coordinating
10278	 * startup and shutdown of the server, as well as all exclusive
10279	 * tasks.
10280	 */
10281	CHECKFATAL(isc_task_create_bound(named_g_taskmgr, 0, &server->task, 0),
10282		   "creating server task");
10283	isc_task_setname(server->task, "server", server);
10284	isc_taskmgr_setexcltask(named_g_taskmgr, server->task);
10285
10286	CHECKFATAL(ns_server_create(mctx, get_matching_view, &server->sctx),
10287		   "creating server context");
10288
10289#if defined(HAVE_GEOIP2)
10290	/*
10291	 * GeoIP must be initialized before the interface
10292	 * manager (which includes the ACL environment)
10293	 * is created.
10294	 */
10295	named_geoip_init();
10296#endif /* HAVE_GEOIP2 */
10297
10298#ifdef ENABLE_AFL
10299	server->sctx->fuzztype = named_g_fuzz_type;
10300	server->sctx->fuzznotify = named_fuzz_notify;
10301#endif /* ifdef ENABLE_AFL */
10302
10303	CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
10304		   "isc_task_onshutdown");
10305	CHECKFATAL(
10306		isc_app_onrun(named_g_mctx, server->task, run_server, server),
10307		"isc_app_onrun");
10308
10309	CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr,
10310				      named_g_timermgr, named_g_netmgr,
10311				      &server->zonemgr),
10312		   "dns_zonemgr_create");
10313	CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_"
10314							       "setsize");
10315
10316	CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
10317				    isc_sockstatscounter_max),
10318		   "isc_stats_create");
10319	isc_nm_setstats(named_g_netmgr, server->sockstats);
10320
10321	CHECKFATAL(isc_stats_create(named_g_mctx, &server->zonestats,
10322				    dns_zonestatscounter_max),
10323		   "dns_stats_create (zone)");
10324
10325	CHECKFATAL(isc_stats_create(named_g_mctx, &server->resolverstats,
10326				    dns_resstatscounter_max),
10327		   "dns_stats_create (resolver)");
10328
10329	CHECKFATAL(named_controls_create(server, &server->controls),
10330		   "named_controls_create");
10331
10332	ISC_LIST_INIT(server->dispatches);
10333
10334	ISC_LIST_INIT(server->statschannels);
10335
10336	ISC_LIST_INIT(server->cachelist);
10337
10338	server->magic = NAMED_SERVER_MAGIC;
10339
10340	*serverp = server;
10341}
10342
10343void
10344named_server_destroy(named_server_t **serverp) {
10345	named_server_t *server = *serverp;
10346	REQUIRE(NAMED_SERVER_VALID(server));
10347
10348#ifdef HAVE_DNSTAP
10349	if (server->dtenv != NULL) {
10350		dns_dt_detach(&server->dtenv);
10351	}
10352#endif /* HAVE_DNSTAP */
10353
10354#ifdef USE_DNSRPS
10355	dns_dnsrps_server_destroy();
10356#endif /* ifdef USE_DNSRPS */
10357
10358	named_controls_destroy(&server->controls);
10359
10360	isc_stats_detach(&server->zonestats);
10361	isc_stats_detach(&server->sockstats);
10362	isc_stats_detach(&server->resolverstats);
10363
10364	if (server->sctx != NULL) {
10365		ns_server_detach(&server->sctx);
10366	}
10367
10368	isc_mem_free(server->mctx, server->statsfile);
10369	isc_mem_free(server->mctx, server->bindkeysfile);
10370	isc_mem_free(server->mctx, server->dumpfile);
10371	isc_mem_free(server->mctx, server->secrootsfile);
10372	isc_mem_free(server->mctx, server->recfile);
10373
10374	if (server->version != NULL) {
10375		isc_mem_free(server->mctx, server->version);
10376	}
10377	if (server->hostname != NULL) {
10378		isc_mem_free(server->mctx, server->hostname);
10379	}
10380	if (server->lockfile != NULL) {
10381		isc_mem_free(server->mctx, server->lockfile);
10382	}
10383
10384	if (server->zonemgr != NULL) {
10385		dns_zonemgr_detach(&server->zonemgr);
10386	}
10387
10388	dst_lib_destroy();
10389
10390	INSIST(ISC_LIST_EMPTY(server->kasplist));
10391	INSIST(ISC_LIST_EMPTY(server->viewlist));
10392	INSIST(ISC_LIST_EMPTY(server->cachelist));
10393
10394	if (server->tlsctx_server_cache != NULL) {
10395		isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
10396	}
10397
10398	if (server->tlsctx_client_cache != NULL) {
10399		isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
10400	}
10401
10402	server->magic = 0;
10403	isc_mem_put(server->mctx, server, sizeof(*server));
10404	*serverp = NULL;
10405}
10406
10407static void
10408fatal(named_server_t *server, const char *msg, isc_result_t result) {
10409	if (server != NULL && server->task != NULL) {
10410		/*
10411		 * Prevent races between the OpenSSL on_exit registered
10412		 * function and any other OpenSSL calls from other tasks
10413		 * by requesting exclusive access to the task manager.
10414		 */
10415		(void)isc_task_beginexclusive(server->task);
10416	}
10417	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10418		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, "%s: %s", msg,
10419		      isc_result_totext(result));
10420	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10421		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
10422		      "exiting (due to fatal error)");
10423	named_os_shutdown();
10424	exit(1);
10425}
10426
10427static void
10428start_reserved_dispatches(named_server_t *server) {
10429	REQUIRE(NAMED_SERVER_VALID(server));
10430
10431	server->dispatchgen++;
10432}
10433
10434static void
10435end_reserved_dispatches(named_server_t *server, bool all) {
10436	named_dispatch_t *dispatch, *nextdispatch;
10437
10438	REQUIRE(NAMED_SERVER_VALID(server));
10439
10440	for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10441	     dispatch = nextdispatch)
10442	{
10443		nextdispatch = ISC_LIST_NEXT(dispatch, link);
10444		if (!all && server->dispatchgen == dispatch->dispatchgen) {
10445			continue;
10446		}
10447		ISC_LIST_UNLINK(server->dispatches, dispatch, link);
10448		dns_dispatch_detach(&dispatch->dispatch);
10449		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10450	}
10451}
10452
10453void
10454named_add_reserved_dispatch(named_server_t *server,
10455			    const isc_sockaddr_t *addr) {
10456	named_dispatch_t *dispatch;
10457	in_port_t port;
10458	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
10459	isc_result_t result;
10460
10461	REQUIRE(NAMED_SERVER_VALID(server));
10462
10463	port = isc_sockaddr_getport(addr);
10464	if (port == 0 || port >= 1024) {
10465		return;
10466	}
10467
10468	for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10469	     dispatch = ISC_LIST_NEXT(dispatch, link))
10470	{
10471		if (isc_sockaddr_equal(&dispatch->addr, addr)) {
10472			break;
10473		}
10474	}
10475	if (dispatch != NULL) {
10476		dispatch->dispatchgen = server->dispatchgen;
10477		return;
10478	}
10479
10480	dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
10481
10482	dispatch->addr = *addr;
10483	dispatch->dispatchgen = server->dispatchgen;
10484	dispatch->dispatch = NULL;
10485
10486	result = dns_dispatch_createudp(named_g_dispatchmgr, &dispatch->addr,
10487					&dispatch->dispatch);
10488	if (result != ISC_R_SUCCESS) {
10489		goto cleanup;
10490	}
10491
10492	ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
10493
10494	return;
10495
10496cleanup:
10497	isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10498	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
10499	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10500		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
10501		      "unable to create dispatch for reserved port %s: %s",
10502		      addrbuf, isc_result_totext(result));
10503}
10504
10505static isc_result_t
10506loadconfig(named_server_t *server) {
10507	isc_result_t result;
10508	start_reserved_dispatches(server);
10509	result = load_configuration(named_g_conffile, server, false);
10510	if (result == ISC_R_SUCCESS) {
10511		end_reserved_dispatches(server, false);
10512		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10513			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10514			      "reloading configuration succeeded");
10515	} else {
10516		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10517			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10518			      "reloading configuration failed: %s",
10519			      isc_result_totext(result));
10520		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10521	}
10522
10523	return (result);
10524}
10525
10526static isc_result_t
10527reload(named_server_t *server) {
10528	isc_result_t result;
10529
10530	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10531
10532	CHECK(loadconfig(server));
10533
10534	result = load_zones(server, false, false);
10535	if (result == ISC_R_SUCCESS) {
10536		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10537			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10538			      "reloading zones succeeded");
10539	} else {
10540		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10541			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10542			      "reloading zones failed: %s",
10543			      isc_result_totext(result));
10544		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10545	}
10546cleanup:
10547	return (result);
10548}
10549
10550/*
10551 * Handle a reload event (from SIGHUP).
10552 */
10553static void
10554named_server_reload(isc_task_t *task, isc_event_t *event) {
10555	named_server_t *server = (named_server_t *)event->ev_sender;
10556
10557	INSIST(task == server->task);
10558	UNUSED(task);
10559
10560	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10561		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10562		      "received SIGHUP signal to reload zones");
10563	(void)reload(server);
10564
10565	isc_event_free(&event);
10566}
10567
10568void
10569named_server_reloadwanted(named_server_t *server) {
10570	isc_event_t *event = isc_event_allocate(
10571		named_g_mctx, server, NAMED_EVENT_RELOAD, named_server_reload,
10572		NULL, sizeof(isc_event_t));
10573	isc_task_send(server->task, &event);
10574}
10575
10576void
10577named_server_scan_interfaces(named_server_t *server) {
10578	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10579		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
10580		      "automatic interface rescan");
10581
10582	ns_interfacemgr_scan(server->interfacemgr, true, false);
10583}
10584
10585/*
10586 * Get the next token from lexer 'lex'.
10587 *
10588 * NOTE: the token value for string tokens always uses the same pointer
10589 * value.  Multiple calls to this function on the same lexer will always
10590 * return either that value (lex->data) or NULL. It is necessary to copy
10591 * the token into local storage if it needs to be referenced after the next
10592 * call to next_token().
10593 */
10594static char *
10595next_token(isc_lex_t *lex, isc_buffer_t **text) {
10596	isc_result_t result;
10597	isc_token_t token;
10598
10599	token.type = isc_tokentype_unknown;
10600	result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING,
10601				  &token);
10602
10603	switch (result) {
10604	case ISC_R_NOMORE:
10605		(void)isc_lex_close(lex);
10606		break;
10607	case ISC_R_SUCCESS:
10608		if (token.type == isc_tokentype_eof) {
10609			(void)isc_lex_close(lex);
10610		}
10611		break;
10612	case ISC_R_NOSPACE:
10613		if (text != NULL) {
10614			(void)putstr(text, "token too large");
10615			(void)putnull(text);
10616		}
10617		return (NULL);
10618	default:
10619		if (text != NULL) {
10620			(void)putstr(text, isc_result_totext(result));
10621			(void)putnull(text);
10622		}
10623		return (NULL);
10624	}
10625
10626	if (token.type == isc_tokentype_string ||
10627	    token.type == isc_tokentype_qstring)
10628	{
10629		return (token.value.as_textregion.base);
10630	}
10631
10632	return (NULL);
10633}
10634
10635/*
10636 * Find the zone specified in the control channel command, if any.
10637 * If a zone is specified, point '*zonep' at it, otherwise
10638 * set '*zonep' to NULL, and f 'zonename' is not NULL, copy
10639 * the zone name into it (N.B. 'zonename' must have space to hold
10640 * a full DNS name).
10641 *
10642 * If 'zonetxt' is set, the caller has already pulled a token
10643 * off the command line that is to be used as the zone name. (This
10644 * is sometimes done when it's necessary to check for an optional
10645 * argument before the zone name, as in "rndc sync [-clean] zone".)
10646 */
10647static isc_result_t
10648zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
10649	       dns_zone_t **zonep, char *zonename, isc_buffer_t **text,
10650	       bool skip) {
10651	char *ptr;
10652	char *classtxt;
10653	const char *viewtxt = NULL;
10654	dns_fixedname_t fname;
10655	dns_name_t *name;
10656	isc_result_t result;
10657	dns_view_t *view = NULL;
10658	dns_rdataclass_t rdclass;
10659	char problem[DNS_NAME_FORMATSIZE + 500] = "";
10660	char zonebuf[DNS_NAME_FORMATSIZE];
10661	bool redirect = false;
10662
10663	REQUIRE(zonep != NULL && *zonep == NULL);
10664
10665	if (skip) {
10666		/* Skip the command name. */
10667		ptr = next_token(lex, text);
10668		if (ptr == NULL) {
10669			return (ISC_R_UNEXPECTEDEND);
10670		}
10671	}
10672
10673	/* Look for the zone name. */
10674	if (zonetxt == NULL) {
10675		zonetxt = next_token(lex, text);
10676	}
10677	if (zonetxt == NULL) {
10678		return (ISC_R_SUCCESS);
10679	}
10680
10681	/* Copy zonetxt because it'll be overwritten by next_token() */
10682	/* To locate a zone named "-redirect" use "-redirect." */
10683	if (strcmp(zonetxt, "-redirect") == 0) {
10684		redirect = true;
10685		strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE);
10686	} else {
10687		strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE);
10688	}
10689	if (zonename != NULL) {
10690		strlcpy(zonename, redirect ? "." : zonetxt,
10691			DNS_NAME_FORMATSIZE);
10692	}
10693
10694	name = dns_fixedname_initname(&fname);
10695	CHECK(dns_name_fromstring(name, zonebuf, 0, NULL));
10696
10697	/* Look for the optional class name. */
10698	classtxt = next_token(lex, text);
10699	if (classtxt != NULL) {
10700		isc_textregion_t r;
10701		r.base = classtxt;
10702		r.length = strlen(classtxt);
10703		CHECK(dns_rdataclass_fromtext(&rdclass, &r));
10704
10705		/* Look for the optional view name. */
10706		viewtxt = next_token(lex, text);
10707	} else {
10708		rdclass = dns_rdataclass_in;
10709	}
10710
10711	if (viewtxt == NULL) {
10712		if (redirect) {
10713			result = dns_viewlist_find(&server->viewlist,
10714						   "_default",
10715						   dns_rdataclass_in, &view);
10716			if (result != ISC_R_SUCCESS || view->redirect == NULL) {
10717				result = ISC_R_NOTFOUND;
10718				snprintf(problem, sizeof(problem),
10719					 "redirect zone not found in "
10720					 "_default view");
10721			} else {
10722				dns_zone_attach(view->redirect, zonep);
10723				result = ISC_R_SUCCESS;
10724			}
10725		} else {
10726			result = dns_viewlist_findzone(&server->viewlist, name,
10727						       (classtxt == NULL),
10728						       rdclass, zonep);
10729			if (result == ISC_R_NOTFOUND) {
10730				snprintf(problem, sizeof(problem),
10731					 "no matching zone '%s' in any view",
10732					 zonebuf);
10733			} else if (result == ISC_R_MULTIPLE) {
10734				snprintf(problem, sizeof(problem),
10735					 "zone '%s' was found in multiple "
10736					 "views",
10737					 zonebuf);
10738			}
10739		}
10740	} else {
10741		result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass,
10742					   &view);
10743		if (result != ISC_R_SUCCESS) {
10744			snprintf(problem, sizeof(problem),
10745				 "no matching view '%s'", viewtxt);
10746			goto report;
10747		}
10748
10749		if (redirect) {
10750			if (view->redirect != NULL) {
10751				dns_zone_attach(view->redirect, zonep);
10752				result = ISC_R_SUCCESS;
10753			} else {
10754				result = ISC_R_NOTFOUND;
10755			}
10756		} else {
10757			result = dns_zt_find(view->zonetable, name, 0, NULL,
10758					     zonep);
10759		}
10760		if (result != ISC_R_SUCCESS) {
10761			snprintf(problem, sizeof(problem),
10762				 "no matching zone '%s' in view '%s'", zonebuf,
10763				 viewtxt);
10764		}
10765	}
10766
10767	/* Partial match? */
10768	if (result != ISC_R_SUCCESS && *zonep != NULL) {
10769		dns_zone_detach(zonep);
10770	}
10771	if (result == DNS_R_PARTIALMATCH) {
10772		result = ISC_R_NOTFOUND;
10773	}
10774report:
10775	if (result != ISC_R_SUCCESS) {
10776		isc_result_t tresult;
10777
10778		tresult = putstr(text, problem);
10779		if (tresult == ISC_R_SUCCESS) {
10780			(void)putnull(text);
10781		}
10782	}
10783
10784cleanup:
10785	if (view != NULL) {
10786		dns_view_detach(&view);
10787	}
10788
10789	return (result);
10790}
10791
10792/*
10793 * Act on a "retransfer" command from the command channel.
10794 */
10795isc_result_t
10796named_server_retransfercommand(named_server_t *server, isc_lex_t *lex,
10797			       isc_buffer_t **text) {
10798	isc_result_t result;
10799	dns_zone_t *zone = NULL;
10800	dns_zone_t *raw = NULL;
10801	dns_zonetype_t type;
10802
10803	REQUIRE(text != NULL);
10804
10805	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10806	if (result != ISC_R_SUCCESS) {
10807		return (result);
10808	}
10809	if (zone == NULL) {
10810		return (ISC_R_UNEXPECTEDEND);
10811	}
10812	dns_zone_getraw(zone, &raw);
10813	if (raw != NULL) {
10814		dns_zone_detach(&zone);
10815		dns_zone_attach(raw, &zone);
10816		dns_zone_detach(&raw);
10817	}
10818	type = dns_zone_gettype(zone);
10819	if (type == dns_zone_secondary || type == dns_zone_mirror ||
10820	    type == dns_zone_stub ||
10821	    (type == dns_zone_redirect &&
10822	     dns_zone_getredirecttype(zone) == dns_zone_secondary))
10823	{
10824		dns_zone_forcereload(zone);
10825	} else {
10826		(void)putstr(text, "retransfer: inappropriate zone type: ");
10827		(void)putstr(text, dns_zonetype_name(type));
10828		if (type == dns_zone_redirect) {
10829			type = dns_zone_getredirecttype(zone);
10830			(void)putstr(text, "(");
10831			(void)putstr(text, dns_zonetype_name(type));
10832			(void)putstr(text, ")");
10833		}
10834		(void)putnull(text);
10835		result = ISC_R_FAILURE;
10836	}
10837	dns_zone_detach(&zone);
10838	return (result);
10839}
10840
10841/*
10842 * Act on a "reload" command from the command channel.
10843 */
10844isc_result_t
10845named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
10846			   isc_buffer_t **text) {
10847	isc_result_t result;
10848	dns_zone_t *zone = NULL;
10849	dns_zonetype_t type;
10850	const char *msg = NULL;
10851
10852	REQUIRE(text != NULL);
10853
10854	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10855	if (result != ISC_R_SUCCESS) {
10856		return (result);
10857	}
10858	if (zone == NULL) {
10859		result = reload(server);
10860		if (result == ISC_R_SUCCESS) {
10861			msg = "server reload successful";
10862		}
10863	} else {
10864		type = dns_zone_gettype(zone);
10865		if (type == dns_zone_secondary || type == dns_zone_mirror ||
10866		    type == dns_zone_stub)
10867		{
10868			dns_zone_refresh(zone);
10869			dns_zone_detach(&zone);
10870			msg = "zone refresh queued";
10871		} else {
10872			result = dns_zone_load(zone, false);
10873			dns_zone_detach(&zone);
10874			switch (result) {
10875			case ISC_R_SUCCESS:
10876				msg = "zone reload successful";
10877				break;
10878			case DNS_R_CONTINUE:
10879				msg = "zone reload queued";
10880				result = ISC_R_SUCCESS;
10881				break;
10882			case DNS_R_UPTODATE:
10883				msg = "zone reload up-to-date";
10884				result = ISC_R_SUCCESS;
10885				break;
10886			default:
10887				/* failure message will be generated by rndc */
10888				break;
10889			}
10890		}
10891	}
10892	if (msg != NULL) {
10893		(void)putstr(text, msg);
10894		(void)putnull(text);
10895	}
10896	return (result);
10897}
10898
10899/*
10900 * Act on a "reconfig" command from the command channel.
10901 */
10902isc_result_t
10903named_server_reconfigcommand(named_server_t *server) {
10904	isc_result_t result;
10905	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10906
10907	CHECK(loadconfig(server));
10908
10909	result = load_zones(server, false, true);
10910	if (result == ISC_R_SUCCESS) {
10911		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10912			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10913			      "scheduled loading new zones");
10914	} else {
10915		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10916			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10917			      "loading new zones failed: %s",
10918			      isc_result_totext(result));
10919		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10920	}
10921cleanup:
10922	return (result);
10923}
10924
10925/*
10926 * Act on a "notify" command from the command channel.
10927 */
10928isc_result_t
10929named_server_notifycommand(named_server_t *server, isc_lex_t *lex,
10930			   isc_buffer_t **text) {
10931	isc_result_t result;
10932	dns_zone_t *zone = NULL;
10933	const char msg[] = "zone notify queued";
10934
10935	REQUIRE(text != NULL);
10936
10937	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10938	if (result != ISC_R_SUCCESS) {
10939		return (result);
10940	}
10941	if (zone == NULL) {
10942		return (ISC_R_UNEXPECTEDEND);
10943	}
10944
10945	dns_zone_notify(zone);
10946	dns_zone_detach(&zone);
10947	(void)putstr(text, msg);
10948	(void)putnull(text);
10949
10950	return (ISC_R_SUCCESS);
10951}
10952
10953/*
10954 * Act on a "refresh" command from the command channel.
10955 */
10956isc_result_t
10957named_server_refreshcommand(named_server_t *server, isc_lex_t *lex,
10958			    isc_buffer_t **text) {
10959	isc_result_t result;
10960	dns_zone_t *zone = NULL, *raw = NULL;
10961	const char msg1[] = "zone refresh queued";
10962	const char msg2[] = "not a secondary, mirror, or stub zone";
10963	dns_zonetype_t type;
10964
10965	REQUIRE(text != NULL);
10966
10967	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10968	if (result != ISC_R_SUCCESS) {
10969		return (result);
10970	}
10971	if (zone == NULL) {
10972		return (ISC_R_UNEXPECTEDEND);
10973	}
10974
10975	dns_zone_getraw(zone, &raw);
10976	if (raw != NULL) {
10977		dns_zone_detach(&zone);
10978		dns_zone_attach(raw, &zone);
10979		dns_zone_detach(&raw);
10980	}
10981
10982	type = dns_zone_gettype(zone);
10983	if (type == dns_zone_secondary || type == dns_zone_mirror ||
10984	    type == dns_zone_stub)
10985	{
10986		dns_zone_refresh(zone);
10987		dns_zone_detach(&zone);
10988		(void)putstr(text, msg1);
10989		(void)putnull(text);
10990		return (ISC_R_SUCCESS);
10991	}
10992
10993	dns_zone_detach(&zone);
10994	(void)putstr(text, msg2);
10995	(void)putnull(text);
10996	return (ISC_R_FAILURE);
10997}
10998
10999isc_result_t
11000named_server_togglequerylog(named_server_t *server, isc_lex_t *lex) {
11001	bool prev, value;
11002	char *ptr;
11003
11004	/* Skip the command name. */
11005	ptr = next_token(lex, NULL);
11006	if (ptr == NULL) {
11007		return (ISC_R_UNEXPECTEDEND);
11008	}
11009
11010	prev = ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES);
11011
11012	ptr = next_token(lex, NULL);
11013	if (ptr == NULL) {
11014		value = !prev;
11015	} else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
11016		   !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
11017	{
11018		value = true;
11019	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
11020		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
11021	{
11022		value = false;
11023	} else {
11024		return (DNS_R_SYNTAX);
11025	}
11026
11027	if (value == prev) {
11028		return (ISC_R_SUCCESS);
11029	}
11030
11031	ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES, value);
11032
11033	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11034		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11035		      "query logging is now %s", value ? "on" : "off");
11036	return (ISC_R_SUCCESS);
11037}
11038
11039static isc_result_t
11040listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
11041		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
11042		      isc_tlsctx_cache_t *tlsctx_cache,
11043		      ns_listenlist_t **target) {
11044	isc_result_t result;
11045	const cfg_listelt_t *element;
11046	ns_listenlist_t *dlist = NULL;
11047
11048	REQUIRE(target != NULL && *target == NULL);
11049
11050	result = ns_listenlist_create(mctx, &dlist);
11051	if (result != ISC_R_SUCCESS) {
11052		return (result);
11053	}
11054
11055	for (element = cfg_list_first(listenlist); element != NULL;
11056	     element = cfg_list_next(element))
11057	{
11058		ns_listenelt_t *delt = NULL;
11059		const cfg_obj_t *listener = cfg_listelt_value(element);
11060		result = listenelt_fromconfig(listener, config, actx, mctx,
11061					      family, tlsctx_cache, &delt);
11062		if (result != ISC_R_SUCCESS) {
11063			goto cleanup;
11064		}
11065		ISC_LIST_APPEND(dlist->elts, delt, link);
11066	}
11067	*target = dlist;
11068	return (ISC_R_SUCCESS);
11069
11070cleanup:
11071	ns_listenlist_detach(&dlist);
11072	return (result);
11073}
11074
11075static const cfg_obj_t *
11076find_maplist(const cfg_obj_t *config, const char *listname, const char *name) {
11077	isc_result_t result;
11078	const cfg_obj_t *maplist = NULL;
11079	const cfg_listelt_t *elt = NULL;
11080
11081	REQUIRE(config != NULL);
11082	REQUIRE(name != NULL);
11083
11084	result = cfg_map_get(config, listname, &maplist);
11085	if (result != ISC_R_SUCCESS) {
11086		return (NULL);
11087	}
11088
11089	for (elt = cfg_list_first(maplist); elt != NULL;
11090	     elt = cfg_list_next(elt))
11091	{
11092		const cfg_obj_t *map = cfg_listelt_value(elt);
11093		if (strcasecmp(cfg_obj_asstring(cfg_map_getname(map)), name) ==
11094		    0)
11095		{
11096			return (map);
11097		}
11098	}
11099
11100	return (NULL);
11101}
11102
11103/*
11104 * Create a listen list from the corresponding configuration
11105 * data structure.
11106 */
11107static isc_result_t
11108listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
11109		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
11110		     isc_tlsctx_cache_t *tlsctx_cache,
11111		     ns_listenelt_t **target) {
11112	isc_result_t result;
11113	const cfg_obj_t *ltup = NULL;
11114	const cfg_obj_t *tlsobj = NULL, *httpobj = NULL;
11115	const cfg_obj_t *portobj = NULL;
11116	const cfg_obj_t *http_server = NULL;
11117	in_port_t port = 0;
11118	const char *key = NULL, *cert = NULL, *ca_file = NULL,
11119		   *dhparam_file = NULL, *ciphers = NULL;
11120	bool tls_prefer_server_ciphers = false,
11121	     tls_prefer_server_ciphers_set = false;
11122	bool tls_session_tickets = false, tls_session_tickets_set = false;
11123	bool do_tls = false, no_tls = false, http = false;
11124	ns_listenelt_t *delt = NULL;
11125	uint32_t tls_protos = 0;
11126	ns_listen_tls_params_t tls_params = { 0 };
11127	const char *tlsname = NULL;
11128
11129	REQUIRE(target != NULL && *target == NULL);
11130
11131	ltup = cfg_tuple_get(listener, "tuple");
11132	RUNTIME_CHECK(ltup != NULL);
11133
11134	tlsobj = cfg_tuple_get(ltup, "tls");
11135	if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) {
11136		tlsname = cfg_obj_asstring(tlsobj);
11137
11138		if (strcasecmp(tlsname, "none") == 0) {
11139			no_tls = true;
11140		} else if (strcasecmp(tlsname, "ephemeral") == 0) {
11141			do_tls = true;
11142		} else {
11143			const cfg_obj_t *keyobj = NULL, *certobj = NULL,
11144					*ca_obj = NULL, *dhparam_obj = NULL;
11145			const cfg_obj_t *tlsmap = NULL;
11146			const cfg_obj_t *tls_proto_list = NULL;
11147			const cfg_obj_t *ciphers_obj = NULL;
11148			const cfg_obj_t *prefer_server_ciphers_obj = NULL;
11149			const cfg_obj_t *session_tickets_obj = NULL;
11150
11151			do_tls = true;
11152
11153			tlsmap = find_maplist(config, "tls", tlsname);
11154			if (tlsmap == NULL) {
11155				cfg_obj_log(tlsobj, named_g_lctx, ISC_LOG_ERROR,
11156					    "tls '%s' is not defined",
11157					    cfg_obj_asstring(tlsobj));
11158				return (ISC_R_FAILURE);
11159			}
11160
11161			CHECK(cfg_map_get(tlsmap, "key-file", &keyobj));
11162			key = cfg_obj_asstring(keyobj);
11163
11164			CHECK(cfg_map_get(tlsmap, "cert-file", &certobj));
11165			cert = cfg_obj_asstring(certobj);
11166
11167			if (cfg_map_get(tlsmap, "ca-file", &ca_obj) ==
11168			    ISC_R_SUCCESS)
11169			{
11170				ca_file = cfg_obj_asstring(ca_obj);
11171			}
11172
11173			if (cfg_map_get(tlsmap, "protocols", &tls_proto_list) ==
11174			    ISC_R_SUCCESS)
11175			{
11176				const cfg_listelt_t *proto = NULL;
11177				INSIST(tls_proto_list != NULL);
11178				for (proto = cfg_list_first(tls_proto_list);
11179				     proto != 0; proto = cfg_list_next(proto))
11180				{
11181					const cfg_obj_t *tls_proto_obj =
11182						cfg_listelt_value(proto);
11183					const char *tls_sver =
11184						cfg_obj_asstring(tls_proto_obj);
11185					const isc_tls_protocol_version_t ver =
11186						isc_tls_protocol_name_to_version(
11187							tls_sver);
11188
11189					INSIST(ver !=
11190					       ISC_TLS_PROTO_VER_UNDEFINED);
11191					INSIST(isc_tls_protocol_supported(ver));
11192					tls_protos |= ver;
11193				}
11194			}
11195
11196			if (cfg_map_get(tlsmap, "dhparam-file", &dhparam_obj) ==
11197			    ISC_R_SUCCESS)
11198			{
11199				dhparam_file = cfg_obj_asstring(dhparam_obj);
11200			}
11201
11202			if (cfg_map_get(tlsmap, "ciphers", &ciphers_obj) ==
11203			    ISC_R_SUCCESS)
11204			{
11205				ciphers = cfg_obj_asstring(ciphers_obj);
11206			}
11207
11208			if (cfg_map_get(tlsmap, "prefer-server-ciphers",
11209					&prefer_server_ciphers_obj) ==
11210			    ISC_R_SUCCESS)
11211			{
11212				tls_prefer_server_ciphers = cfg_obj_asboolean(
11213					prefer_server_ciphers_obj);
11214				tls_prefer_server_ciphers_set = true;
11215			}
11216
11217			if (cfg_map_get(tlsmap, "session-tickets",
11218					&session_tickets_obj) == ISC_R_SUCCESS)
11219			{
11220				tls_session_tickets =
11221					cfg_obj_asboolean(session_tickets_obj);
11222				tls_session_tickets_set = true;
11223			}
11224		}
11225	}
11226
11227	tls_params = (ns_listen_tls_params_t){
11228		.name = tlsname,
11229		.key = key,
11230		.cert = cert,
11231		.ca_file = ca_file,
11232		.protocols = tls_protos,
11233		.dhparam_file = dhparam_file,
11234		.ciphers = ciphers,
11235		.prefer_server_ciphers = tls_prefer_server_ciphers,
11236		.prefer_server_ciphers_set = tls_prefer_server_ciphers_set,
11237		.session_tickets = tls_session_tickets,
11238		.session_tickets_set = tls_session_tickets_set
11239	};
11240
11241	httpobj = cfg_tuple_get(ltup, "http");
11242	if (httpobj != NULL && cfg_obj_isstring(httpobj)) {
11243		const char *httpname = cfg_obj_asstring(httpobj);
11244
11245		if (!do_tls && !no_tls) {
11246			return (ISC_R_FAILURE);
11247		}
11248
11249		http_server = find_maplist(config, "http", httpname);
11250		if (http_server == NULL && strcasecmp(httpname, "default") != 0)
11251		{
11252			cfg_obj_log(httpobj, named_g_lctx, ISC_LOG_ERROR,
11253				    "http '%s' is not defined",
11254				    cfg_obj_asstring(httpobj));
11255			return (ISC_R_FAILURE);
11256		}
11257
11258		http = true;
11259	}
11260
11261	portobj = cfg_tuple_get(ltup, "port");
11262	if (!cfg_obj_isuint32(portobj)) {
11263		if (http && do_tls) {
11264			if (named_g_httpsport != 0) {
11265				port = named_g_httpsport;
11266			} else {
11267				result = named_config_getport(
11268					config, "https-port", &port);
11269				if (result != ISC_R_SUCCESS) {
11270					return (result);
11271				}
11272			}
11273		} else if (http && !do_tls) {
11274			if (named_g_httpport != 0) {
11275				port = named_g_httpport;
11276			} else {
11277				result = named_config_getport(
11278					config, "http-port", &port);
11279				if (result != ISC_R_SUCCESS) {
11280					return (result);
11281				}
11282			}
11283		} else if (do_tls) {
11284			if (named_g_tlsport != 0) {
11285				port = named_g_tlsport;
11286			} else {
11287				result = named_config_getport(
11288					config, "tls-port", &port);
11289				if (result != ISC_R_SUCCESS) {
11290					return (result);
11291				}
11292			}
11293		} else {
11294			if (named_g_port != 0) {
11295				port = named_g_port;
11296			} else {
11297				result = named_config_getport(config, "port",
11298							      &port);
11299				if (result != ISC_R_SUCCESS) {
11300					return (result);
11301				}
11302			}
11303		}
11304	} else {
11305		if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
11306			return (ISC_R_RANGE);
11307		}
11308		port = (in_port_t)cfg_obj_asuint32(portobj);
11309	}
11310
11311#ifdef HAVE_LIBNGHTTP2
11312	if (http) {
11313		CHECK(listenelt_http(http_server, family, do_tls, &tls_params,
11314				     tlsctx_cache, port, mctx, &delt));
11315	}
11316#endif /* HAVE_LIBNGHTTP2 */
11317
11318	if (!http) {
11319		CHECK(ns_listenelt_create(mctx, port, NULL, family, do_tls,
11320					  &tls_params, tlsctx_cache, &delt));
11321	}
11322
11323	result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"), config,
11324				     named_g_lctx, actx, mctx, 0, family,
11325				     &delt->acl);
11326	if (result != ISC_R_SUCCESS) {
11327		ns_listenelt_destroy(delt);
11328		return (result);
11329	}
11330	*target = delt;
11331
11332cleanup:
11333	return (result);
11334}
11335
11336#ifdef HAVE_LIBNGHTTP2
11337static isc_result_t
11338listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls,
11339	       const ns_listen_tls_params_t *tls_params,
11340	       isc_tlsctx_cache_t *tlsctx_cache, in_port_t port,
11341	       isc_mem_t *mctx, ns_listenelt_t **target) {
11342	isc_result_t result = ISC_R_SUCCESS;
11343	ns_listenelt_t *delt = NULL;
11344	char **endpoints = NULL;
11345	const cfg_obj_t *eplist = NULL;
11346	const cfg_listelt_t *elt = NULL;
11347	size_t len = 1, i = 0;
11348	uint32_t max_clients = named_g_http_listener_clients;
11349	uint32_t max_streams = named_g_http_streams_per_conn;
11350
11351	REQUIRE(target != NULL && *target == NULL);
11352
11353	if (tls) {
11354		INSIST(tls_params != NULL);
11355		INSIST((tls_params->key == NULL) == (tls_params->cert == NULL));
11356	}
11357
11358	if (port == 0) {
11359		port = tls ? named_g_httpsport : named_g_httpport;
11360	}
11361
11362	/*
11363	 * If "default" was used, we set up the default endpoint
11364	 * of "/dns-query".
11365	 */
11366	if (http != NULL) {
11367		const cfg_obj_t *cfg_max_clients = NULL;
11368		const cfg_obj_t *cfg_max_streams = NULL;
11369
11370		if (cfg_map_get(http, "endpoints", &eplist) == ISC_R_SUCCESS) {
11371			INSIST(eplist != NULL);
11372			len = cfg_list_length(eplist, false);
11373		}
11374
11375		if (cfg_map_get(http, "listener-clients", &cfg_max_clients) ==
11376		    ISC_R_SUCCESS)
11377		{
11378			INSIST(cfg_max_clients != NULL);
11379			max_clients = cfg_obj_asuint32(cfg_max_clients);
11380		}
11381
11382		if (cfg_map_get(http, "streams-per-connection",
11383				&cfg_max_streams) == ISC_R_SUCCESS)
11384		{
11385			INSIST(cfg_max_streams != NULL);
11386			max_streams = cfg_obj_asuint32(cfg_max_streams);
11387		}
11388	}
11389
11390	endpoints = isc_mem_allocate(mctx, sizeof(endpoints[0]) * len);
11391
11392	if (http != NULL && eplist != NULL) {
11393		for (elt = cfg_list_first(eplist); elt != NULL;
11394		     elt = cfg_list_next(elt))
11395		{
11396			const cfg_obj_t *ep = cfg_listelt_value(elt);
11397			const char *path = cfg_obj_asstring(ep);
11398			endpoints[i++] = isc_mem_strdup(mctx, path);
11399		}
11400	} else {
11401		endpoints[i++] = isc_mem_strdup(mctx, ISC_NM_HTTP_DEFAULT_PATH);
11402	}
11403
11404	INSIST(i == len);
11405
11406	result = ns_listenelt_create_http(mctx, port, NULL, family, tls,
11407					  tls_params, tlsctx_cache, endpoints,
11408					  len, max_clients, max_streams, &delt);
11409	if (result != ISC_R_SUCCESS) {
11410		goto error;
11411	}
11412
11413	*target = delt;
11414
11415	return (result);
11416error:
11417	if (delt != NULL) {
11418		ns_listenelt_destroy(delt);
11419	}
11420	return (result);
11421}
11422#endif /* HAVE_LIBNGHTTP2 */
11423
11424isc_result_t
11425named_server_dumpstats(named_server_t *server) {
11426	isc_result_t result;
11427	FILE *fp = NULL;
11428
11429	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
11430		"could not open statistics dump file", server->statsfile);
11431
11432	result = named_stats_dump(server, fp);
11433
11434cleanup:
11435	if (fp != NULL) {
11436		(void)isc_stdio_close(fp);
11437	}
11438	if (result == ISC_R_SUCCESS) {
11439		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11440			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11441			      "dumpstats complete");
11442	} else {
11443		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11444			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11445			      "dumpstats failed: %s",
11446			      isc_result_totext(result));
11447	}
11448	return (result);
11449}
11450
11451static isc_result_t
11452add_zone_tolist(dns_zone_t *zone, void *uap) {
11453	struct dumpcontext *dctx = uap;
11454	struct zonelistentry *zle;
11455
11456	zle = isc_mem_get(dctx->mctx, sizeof *zle);
11457	zle->zone = NULL;
11458	dns_zone_attach(zone, &zle->zone);
11459	ISC_LINK_INIT(zle, link);
11460	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
11461	return (ISC_R_SUCCESS);
11462}
11463
11464static isc_result_t
11465add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
11466	struct viewlistentry *vle;
11467	isc_result_t result = ISC_R_SUCCESS;
11468
11469	/*
11470	 * Prevent duplicate views.
11471	 */
11472	for (vle = ISC_LIST_HEAD(dctx->viewlist); vle != NULL;
11473	     vle = ISC_LIST_NEXT(vle, link))
11474	{
11475		if (vle->view == view) {
11476			return (ISC_R_SUCCESS);
11477		}
11478	}
11479
11480	vle = isc_mem_get(dctx->mctx, sizeof *vle);
11481	vle->view = NULL;
11482	dns_view_attach(view, &vle->view);
11483	ISC_LINK_INIT(vle, link);
11484	ISC_LIST_INIT(vle->zonelist);
11485	ISC_LIST_APPEND(dctx->viewlist, vle, link);
11486	if (dctx->dumpzones) {
11487		result = dns_zt_apply(view->zonetable, isc_rwlocktype_read,
11488				      true, NULL, add_zone_tolist, dctx);
11489	}
11490	return (result);
11491}
11492
11493static void
11494dumpcontext_destroy(struct dumpcontext *dctx) {
11495	struct viewlistentry *vle;
11496	struct zonelistentry *zle;
11497
11498	vle = ISC_LIST_HEAD(dctx->viewlist);
11499	while (vle != NULL) {
11500		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
11501		zle = ISC_LIST_HEAD(vle->zonelist);
11502		while (zle != NULL) {
11503			ISC_LIST_UNLINK(vle->zonelist, zle, link);
11504			dns_zone_detach(&zle->zone);
11505			isc_mem_put(dctx->mctx, zle, sizeof *zle);
11506			zle = ISC_LIST_HEAD(vle->zonelist);
11507		}
11508		dns_view_detach(&vle->view);
11509		isc_mem_put(dctx->mctx, vle, sizeof *vle);
11510		vle = ISC_LIST_HEAD(dctx->viewlist);
11511	}
11512	if (dctx->version != NULL) {
11513		dns_db_closeversion(dctx->db, &dctx->version, false);
11514	}
11515	if (dctx->db != NULL) {
11516		dns_db_detach(&dctx->db);
11517	}
11518	if (dctx->cache != NULL) {
11519		dns_db_detach(&dctx->cache);
11520	}
11521	if (dctx->task != NULL) {
11522		isc_task_detach(&dctx->task);
11523	}
11524	if (dctx->fp != NULL) {
11525		(void)isc_stdio_close(dctx->fp);
11526	}
11527	if (dctx->mdctx != NULL) {
11528		dns_dumpctx_detach(&dctx->mdctx);
11529	}
11530	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
11531}
11532
11533static void
11534dumpdone(void *arg, isc_result_t result) {
11535	struct dumpcontext *dctx = arg;
11536	char buf[1024 + 32];
11537	const dns_master_style_t *style;
11538
11539	if (result != ISC_R_SUCCESS) {
11540		goto cleanup;
11541	}
11542	if (dctx->mdctx != NULL) {
11543		dns_dumpctx_detach(&dctx->mdctx);
11544	}
11545	if (dctx->view == NULL) {
11546		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
11547		if (dctx->view == NULL) {
11548			goto done;
11549		}
11550		INSIST(dctx->zone == NULL);
11551	} else {
11552		goto resume;
11553	}
11554nextview:
11555	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
11556resume:
11557	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
11558		fprintf(dctx->fp, ";\n; Cache of view '%s' is shared as '%s'\n",
11559			dctx->view->view->name,
11560			dns_cache_getname(dctx->view->view->cache));
11561	} else if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache)
11562	{
11563		if (dctx->dumpexpired) {
11564			style = &dns_master_style_cache_with_expired;
11565		} else {
11566			style = &dns_master_style_cache;
11567		}
11568		/* start cache dump */
11569		if (dctx->view->view->cachedb != NULL) {
11570			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11571		}
11572		if (dctx->cache != NULL) {
11573			fprintf(dctx->fp,
11574				";\n; Cache dump of view '%s' (cache %s)\n;\n",
11575				dctx->view->view->name,
11576				dns_cache_getname(dctx->view->view->cache));
11577			result = dns_master_dumptostreamasync(
11578				dctx->mctx, dctx->cache, NULL, style, dctx->fp,
11579				dctx->task, dumpdone, dctx, &dctx->mdctx);
11580			if (result == DNS_R_CONTINUE) {
11581				return;
11582			}
11583			if (result == ISC_R_NOTIMPLEMENTED) {
11584				fprintf(dctx->fp, "; %s\n",
11585					isc_result_totext(result));
11586			} else if (result != ISC_R_SUCCESS) {
11587				goto cleanup;
11588			}
11589		}
11590	}
11591
11592	if ((dctx->dumpadb || dctx->dumpbad || dctx->dumpfail) &&
11593	    dctx->cache == NULL && dctx->view->view->cachedb != NULL)
11594	{
11595		dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11596	}
11597
11598	if (dctx->cache != NULL) {
11599		if (dctx->dumpadb) {
11600			dns_adb_dump(dctx->view->view->adb, dctx->fp);
11601		}
11602		if (dctx->dumpbad) {
11603			dns_resolver_printbadcache(dctx->view->view->resolver,
11604						   dctx->fp);
11605		}
11606		if (dctx->dumpfail) {
11607			dns_badcache_print(dctx->view->view->failcache,
11608					   "SERVFAIL cache", dctx->fp);
11609		}
11610		dns_db_detach(&dctx->cache);
11611	}
11612	if (dctx->dumpzones) {
11613		style = &dns_master_style_full;
11614	nextzone:
11615		if (dctx->version != NULL) {
11616			dns_db_closeversion(dctx->db, &dctx->version, false);
11617		}
11618		if (dctx->db != NULL) {
11619			dns_db_detach(&dctx->db);
11620		}
11621		if (dctx->zone == NULL) {
11622			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
11623		} else {
11624			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
11625		}
11626		if (dctx->zone != NULL) {
11627			/* start zone dump */
11628			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
11629			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
11630			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
11631			if (result != ISC_R_SUCCESS) {
11632				fprintf(dctx->fp, "; %s\n",
11633					isc_result_totext(result));
11634				goto nextzone;
11635			}
11636			dns_db_currentversion(dctx->db, &dctx->version);
11637			result = dns_master_dumptostreamasync(
11638				dctx->mctx, dctx->db, dctx->version, style,
11639				dctx->fp, dctx->task, dumpdone, dctx,
11640				&dctx->mdctx);
11641			if (result == DNS_R_CONTINUE) {
11642				return;
11643			}
11644			if (result == ISC_R_NOTIMPLEMENTED) {
11645				fprintf(dctx->fp, "; %s\n",
11646					isc_result_totext(result));
11647				result = ISC_R_SUCCESS;
11648				POST(result);
11649				goto nextzone;
11650			}
11651			if (result != ISC_R_SUCCESS) {
11652				goto cleanup;
11653			}
11654		}
11655	}
11656	if (dctx->view != NULL) {
11657		dctx->view = ISC_LIST_NEXT(dctx->view, link);
11658		if (dctx->view != NULL) {
11659			goto nextview;
11660		}
11661	}
11662done:
11663	fprintf(dctx->fp, "; Dump complete\n");
11664	result = isc_stdio_flush(dctx->fp);
11665	if (result == ISC_R_SUCCESS) {
11666		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11667			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11668			      "dumpdb complete");
11669	}
11670cleanup:
11671	if (result != ISC_R_SUCCESS) {
11672		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11673			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11674			      "dumpdb failed: %s", isc_result_totext(result));
11675	}
11676	dumpcontext_destroy(dctx);
11677}
11678
11679isc_result_t
11680named_server_dumpdb(named_server_t *server, isc_lex_t *lex,
11681		    isc_buffer_t **text) {
11682	struct dumpcontext *dctx = NULL;
11683	dns_view_t *view;
11684	isc_result_t result;
11685	char *ptr;
11686	const char *sep;
11687	bool found;
11688
11689	REQUIRE(text != NULL);
11690
11691	/* Skip the command name. */
11692	ptr = next_token(lex, NULL);
11693	if (ptr == NULL) {
11694		return (ISC_R_UNEXPECTEDEND);
11695	}
11696
11697	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
11698
11699	dctx->mctx = server->mctx;
11700	dctx->dumpcache = true;
11701	dctx->dumpadb = true;
11702	dctx->dumpbad = true;
11703	dctx->dumpexpired = false;
11704	dctx->dumpfail = true;
11705	dctx->dumpzones = false;
11706	dctx->fp = NULL;
11707	ISC_LIST_INIT(dctx->viewlist);
11708	dctx->view = NULL;
11709	dctx->zone = NULL;
11710	dctx->cache = NULL;
11711	dctx->mdctx = NULL;
11712	dctx->db = NULL;
11713	dctx->cache = NULL;
11714	dctx->task = NULL;
11715	dctx->version = NULL;
11716	isc_task_attach(server->task, &dctx->task);
11717
11718	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
11719		"could not open dump file", server->dumpfile);
11720
11721	ptr = next_token(lex, NULL);
11722	sep = (ptr == NULL) ? "" : ": ";
11723	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11724		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11725		      "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : "");
11726
11727	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
11728		/* also dump zones */
11729		dctx->dumpzones = true;
11730		ptr = next_token(lex, NULL);
11731	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
11732		/* this is the default */
11733		ptr = next_token(lex, NULL);
11734	} else if (ptr != NULL && strcmp(ptr, "-expired") == 0) {
11735		/* this is the same as -cache but includes expired data */
11736		dctx->dumpexpired = true;
11737		ptr = next_token(lex, NULL);
11738	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
11739		/* only dump zones, suppress caches */
11740		dctx->dumpadb = false;
11741		dctx->dumpbad = false;
11742		dctx->dumpcache = false;
11743		dctx->dumpfail = false;
11744		dctx->dumpzones = true;
11745		ptr = next_token(lex, NULL);
11746	} else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
11747		/* only dump adb, suppress other caches */
11748		dctx->dumpbad = false;
11749		dctx->dumpcache = false;
11750		dctx->dumpfail = false;
11751		ptr = next_token(lex, NULL);
11752	} else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
11753		/* only dump badcache, suppress other caches */
11754		dctx->dumpadb = false;
11755		dctx->dumpcache = false;
11756		dctx->dumpfail = false;
11757		ptr = next_token(lex, NULL);
11758	} else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
11759		/* only dump servfail cache, suppress other caches */
11760		dctx->dumpadb = false;
11761		dctx->dumpbad = false;
11762		dctx->dumpcache = false;
11763		ptr = next_token(lex, NULL);
11764	}
11765
11766nextview:
11767	found = false;
11768	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11769	     view = ISC_LIST_NEXT(view, link))
11770	{
11771		if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11772			continue;
11773		}
11774		found = true;
11775		CHECK(add_view_tolist(dctx, view));
11776	}
11777	if (ptr != NULL) {
11778		if (!found) {
11779			CHECK(putstr(text, "view '"));
11780			CHECK(putstr(text, ptr));
11781			CHECK(putstr(text, "' not found"));
11782			CHECK(putnull(text));
11783			result = ISC_R_NOTFOUND;
11784			dumpdone(dctx, result);
11785			return (result);
11786		}
11787		ptr = next_token(lex, NULL);
11788		if (ptr != NULL) {
11789			goto nextview;
11790		}
11791	}
11792	dumpdone(dctx, ISC_R_SUCCESS);
11793	return (ISC_R_SUCCESS);
11794
11795cleanup:
11796	dumpcontext_destroy(dctx);
11797	return (result);
11798}
11799
11800isc_result_t
11801named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex,
11802			  isc_buffer_t **text) {
11803	dns_view_t *view;
11804	dns_keytable_t *secroots = NULL;
11805	dns_ntatable_t *ntatable = NULL;
11806	isc_result_t result;
11807	char *ptr;
11808	FILE *fp = NULL;
11809	isc_time_t now;
11810	char tbuf[64];
11811	unsigned int used = isc_buffer_usedlength(*text);
11812	bool first = true;
11813
11814	REQUIRE(text != NULL);
11815
11816	/* Skip the command name. */
11817	ptr = next_token(lex, text);
11818	if (ptr == NULL) {
11819		return (ISC_R_UNEXPECTEDEND);
11820	}
11821
11822	/* "-" here means print the output instead of dumping to file */
11823	ptr = next_token(lex, text);
11824	if (ptr != NULL && strcmp(ptr, "-") == 0) {
11825		ptr = next_token(lex, text);
11826	} else {
11827		result = isc_stdio_open(server->secrootsfile, "w", &fp);
11828		if (result != ISC_R_SUCCESS) {
11829			(void)putstr(text, "could not open ");
11830			(void)putstr(text, server->secrootsfile);
11831			CHECKMF(result, "could not open secroots dump file",
11832				server->secrootsfile);
11833		}
11834	}
11835
11836	TIME_NOW(&now);
11837	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
11838	CHECK(putstr(text, "secure roots as of "));
11839	CHECK(putstr(text, tbuf));
11840	CHECK(putstr(text, ":\n"));
11841	used = isc_buffer_usedlength(*text);
11842
11843	do {
11844		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11845		     view = ISC_LIST_NEXT(view, link))
11846		{
11847			if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11848				continue;
11849			}
11850			if (secroots != NULL) {
11851				dns_keytable_detach(&secroots);
11852			}
11853			result = dns_view_getsecroots(view, &secroots);
11854			if (result == ISC_R_NOTFOUND) {
11855				result = ISC_R_SUCCESS;
11856				continue;
11857			}
11858			if (first || used != isc_buffer_usedlength(*text)) {
11859				CHECK(putstr(text, "\n"));
11860				first = false;
11861			}
11862			CHECK(putstr(text, " Start view "));
11863			CHECK(putstr(text, view->name));
11864			CHECK(putstr(text, "\n   Secure roots:\n\n"));
11865			used = isc_buffer_usedlength(*text);
11866			CHECK(dns_keytable_totext(secroots, text));
11867
11868			if (ntatable != NULL) {
11869				dns_ntatable_detach(&ntatable);
11870			}
11871			result = dns_view_getntatable(view, &ntatable);
11872			if (result == ISC_R_NOTFOUND) {
11873				result = ISC_R_SUCCESS;
11874				continue;
11875			}
11876			if (used != isc_buffer_usedlength(*text)) {
11877				CHECK(putstr(text, "\n"));
11878			}
11879			CHECK(putstr(text, "   Negative trust anchors:\n\n"));
11880			used = isc_buffer_usedlength(*text);
11881			CHECK(dns_ntatable_totext(ntatable, NULL, text));
11882		}
11883
11884		if (ptr != NULL) {
11885			ptr = next_token(lex, text);
11886		}
11887	} while (ptr != NULL);
11888
11889cleanup:
11890	if (secroots != NULL) {
11891		dns_keytable_detach(&secroots);
11892	}
11893	if (ntatable != NULL) {
11894		dns_ntatable_detach(&ntatable);
11895	}
11896
11897	if (fp != NULL) {
11898		if (used != isc_buffer_usedlength(*text)) {
11899			(void)putstr(text, "\n");
11900		}
11901		fprintf(fp, "%.*s", (int)isc_buffer_usedlength(*text),
11902			(char *)isc_buffer_base(*text));
11903		isc_buffer_clear(*text);
11904		(void)isc_stdio_close(fp);
11905	} else if (isc_buffer_usedlength(*text) > 0) {
11906		(void)putnull(text);
11907	}
11908
11909	if (result == ISC_R_SUCCESS) {
11910		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11911			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11912			      "dumpsecroots complete");
11913	} else {
11914		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11915			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11916			      "dumpsecroots failed: %s",
11917			      isc_result_totext(result));
11918	}
11919	return (result);
11920}
11921
11922isc_result_t
11923named_server_dumprecursing(named_server_t *server) {
11924	FILE *fp = NULL;
11925	dns_view_t *view;
11926	isc_result_t result;
11927
11928	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
11929		"could not open dump file", server->recfile);
11930	fprintf(fp, ";\n; Recursing Queries\n;\n");
11931	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
11932
11933	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11934	     view = ISC_LIST_NEXT(view, link))
11935	{
11936		fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
11937			view->name);
11938		dns_resolver_dumpfetches(view->resolver, isc_statsformat_file,
11939					 fp);
11940	}
11941
11942	fprintf(fp, "; Dump complete\n");
11943
11944cleanup:
11945	if (fp != NULL) {
11946		result = isc_stdio_close(fp);
11947	}
11948	if (result == ISC_R_SUCCESS) {
11949		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11950			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11951			      "dumprecursing complete");
11952	} else {
11953		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11954			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11955			      "dumprecursing failed: %s",
11956			      isc_result_totext(result));
11957	}
11958	return (result);
11959}
11960
11961isc_result_t
11962named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
11963	char *ptr;
11964	char *endp;
11965	long newlevel;
11966
11967	UNUSED(server);
11968
11969	/* Skip the command name. */
11970	ptr = next_token(lex, NULL);
11971	if (ptr == NULL) {
11972		return (ISC_R_UNEXPECTEDEND);
11973	}
11974
11975	/* Look for the new level name. */
11976	ptr = next_token(lex, NULL);
11977	if (ptr == NULL) {
11978		if (named_g_debuglevel < 99) {
11979			named_g_debuglevel++;
11980		}
11981	} else {
11982		newlevel = strtol(ptr, &endp, 10);
11983		if (*endp != '\0' || newlevel < 0 || newlevel > 99) {
11984			return (ISC_R_RANGE);
11985		}
11986		named_g_debuglevel = (unsigned int)newlevel;
11987	}
11988	isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel);
11989	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11990		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11991		      "debug level is now %u", named_g_debuglevel);
11992	return (ISC_R_SUCCESS);
11993}
11994
11995isc_result_t
11996named_server_validation(named_server_t *server, isc_lex_t *lex,
11997			isc_buffer_t **text) {
11998	char *ptr;
11999	dns_view_t *view;
12000	bool changed = false;
12001	isc_result_t result;
12002	bool enable = true, set = true, first = true;
12003
12004	REQUIRE(text != NULL);
12005
12006	/* Skip the command name. */
12007	ptr = next_token(lex, text);
12008	if (ptr == NULL) {
12009		return (ISC_R_UNEXPECTEDEND);
12010	}
12011
12012	/* Find out what we are to do. */
12013	ptr = next_token(lex, text);
12014	if (ptr == NULL) {
12015		return (ISC_R_UNEXPECTEDEND);
12016	}
12017
12018	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
12019	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
12020	{
12021		enable = true;
12022	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
12023		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
12024	{
12025		enable = false;
12026	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
12027		set = false;
12028	} else {
12029		return (DNS_R_SYNTAX);
12030	}
12031
12032	/* Look for the view name. */
12033	ptr = next_token(lex, text);
12034
12035	result = isc_task_beginexclusive(server->task);
12036	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12037	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12038	     view = ISC_LIST_NEXT(view, link))
12039	{
12040		if ((ptr != NULL && strcasecmp(ptr, view->name) != 0) ||
12041		    strcasecmp("_bind", view->name) == 0)
12042		{
12043			continue;
12044		}
12045
12046		if (set) {
12047			CHECK(dns_view_flushcache(view, false));
12048			view->enablevalidation = enable;
12049			changed = true;
12050		} else {
12051			if (!first) {
12052				CHECK(putstr(text, "\n"));
12053			}
12054			CHECK(putstr(text, "DNSSEC validation is "));
12055			CHECK(putstr(text, view->enablevalidation
12056						   ? "enabled"
12057						   : "disabled"));
12058			CHECK(putstr(text, " (view "));
12059			CHECK(putstr(text, view->name));
12060			CHECK(putstr(text, ")"));
12061			first = false;
12062		}
12063	}
12064	CHECK(putnull(text));
12065
12066	if (!set) {
12067		result = ISC_R_SUCCESS;
12068	} else if (changed) {
12069		result = ISC_R_SUCCESS;
12070	} else {
12071		result = ISC_R_FAILURE;
12072	}
12073cleanup:
12074	isc_task_endexclusive(server->task);
12075	return (result);
12076}
12077
12078isc_result_t
12079named_server_flushcache(named_server_t *server, isc_lex_t *lex) {
12080	char *ptr;
12081	dns_view_t *view;
12082	bool flushed;
12083	bool found;
12084	isc_result_t result;
12085	named_cache_t *nsc;
12086
12087	/* Skip the command name. */
12088	ptr = next_token(lex, NULL);
12089	if (ptr == NULL) {
12090		return (ISC_R_UNEXPECTEDEND);
12091	}
12092
12093	/* Look for the view name. */
12094	ptr = next_token(lex, NULL);
12095
12096	result = isc_task_beginexclusive(server->task);
12097	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12098	flushed = true;
12099	found = false;
12100
12101	/*
12102	 * Flushing a cache is tricky when caches are shared by multiple views.
12103	 * We first identify which caches should be flushed in the local cache
12104	 * list, flush these caches, and then update other views that refer to
12105	 * the flushed cache DB.
12106	 */
12107	if (ptr != NULL) {
12108		/*
12109		 * Mark caches that need to be flushed.  This is an O(#view^2)
12110		 * operation in the very worst case, but should be normally
12111		 * much more lightweight because only a few (most typically just
12112		 * one) views will match.
12113		 */
12114		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12115		     view = ISC_LIST_NEXT(view, link))
12116		{
12117			if (strcasecmp(ptr, view->name) != 0) {
12118				continue;
12119			}
12120			found = true;
12121			for (nsc = ISC_LIST_HEAD(server->cachelist);
12122			     nsc != NULL; nsc = ISC_LIST_NEXT(nsc, link))
12123			{
12124				if (nsc->cache == view->cache) {
12125					break;
12126				}
12127			}
12128			INSIST(nsc != NULL);
12129			nsc->needflush = true;
12130		}
12131	} else {
12132		found = true;
12133	}
12134
12135	/* Perform flush */
12136	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12137	     nsc = ISC_LIST_NEXT(nsc, link))
12138	{
12139		if (ptr != NULL && !nsc->needflush) {
12140			continue;
12141		}
12142		nsc->needflush = true;
12143		result = dns_view_flushcache(nsc->primaryview, false);
12144		if (result != ISC_R_SUCCESS) {
12145			flushed = false;
12146			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12147				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12148				      "flushing cache in view '%s' failed: %s",
12149				      nsc->primaryview->name,
12150				      isc_result_totext(result));
12151		}
12152	}
12153
12154	/*
12155	 * Fix up views that share a flushed cache: let the views update the
12156	 * cache DB they're referring to.  This could also be an expensive
12157	 * operation, but should typically be marginal: the inner loop is only
12158	 * necessary for views that share a cache, and if there are many such
12159	 * views the number of shared cache should normally be small.
12160	 * A worst case is that we have n views and n/2 caches, each shared by
12161	 * two views.  Then this will be a O(n^2/4) operation.
12162	 */
12163	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12164	     view = ISC_LIST_NEXT(view, link))
12165	{
12166		if (!dns_view_iscacheshared(view)) {
12167			continue;
12168		}
12169		for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12170		     nsc = ISC_LIST_NEXT(nsc, link))
12171		{
12172			if (!nsc->needflush || nsc->cache != view->cache) {
12173				continue;
12174			}
12175			result = dns_view_flushcache(view, true);
12176			if (result != ISC_R_SUCCESS) {
12177				flushed = false;
12178				isc_log_write(
12179					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12180					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12181					"fixing cache in view '%s' "
12182					"failed: %s",
12183					view->name, isc_result_totext(result));
12184			}
12185		}
12186	}
12187
12188	/* Cleanup the cache list. */
12189	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12190	     nsc = ISC_LIST_NEXT(nsc, link))
12191	{
12192		nsc->needflush = false;
12193	}
12194
12195	if (flushed && found) {
12196		if (ptr != NULL) {
12197			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12198				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12199				      "flushing cache in view '%s' succeeded",
12200				      ptr);
12201		} else {
12202			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12203				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12204				      "flushing caches in all views succeeded");
12205		}
12206		result = ISC_R_SUCCESS;
12207	} else {
12208		if (!found) {
12209			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12210				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12211				      "flushing cache in view '%s' failed: "
12212				      "view not found",
12213				      ptr);
12214			result = ISC_R_NOTFOUND;
12215		} else {
12216			result = ISC_R_FAILURE;
12217		}
12218	}
12219	isc_task_endexclusive(server->task);
12220	return (result);
12221}
12222
12223isc_result_t
12224named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) {
12225	char *ptr, *viewname;
12226	char target[DNS_NAME_FORMATSIZE];
12227	dns_view_t *view;
12228	bool flushed;
12229	bool found;
12230	isc_result_t result;
12231	isc_buffer_t b;
12232	dns_fixedname_t fixed;
12233	dns_name_t *name;
12234
12235	/* Skip the command name. */
12236	ptr = next_token(lex, NULL);
12237	if (ptr == NULL) {
12238		return (ISC_R_UNEXPECTEDEND);
12239	}
12240
12241	/* Find the domain name to flush. */
12242	ptr = next_token(lex, NULL);
12243	if (ptr == NULL) {
12244		return (ISC_R_UNEXPECTEDEND);
12245	}
12246
12247	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
12248	isc_buffer_constinit(&b, target, strlen(target));
12249	isc_buffer_add(&b, strlen(target));
12250	name = dns_fixedname_initname(&fixed);
12251	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
12252	if (result != ISC_R_SUCCESS) {
12253		return (result);
12254	}
12255
12256	/* Look for the view name. */
12257	viewname = next_token(lex, NULL);
12258
12259	result = isc_task_beginexclusive(server->task);
12260	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12261	flushed = true;
12262	found = false;
12263	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12264	     view = ISC_LIST_NEXT(view, link))
12265	{
12266		if (viewname != NULL && strcasecmp(viewname, view->name) != 0) {
12267			continue;
12268		}
12269		found = true;
12270		/*
12271		 * It's a little inefficient to try flushing name for all views
12272		 * if some of the views share a single cache.  But since the
12273		 * operation is lightweight we prefer simplicity here.
12274		 */
12275		result = dns_view_flushnode(view, name, tree);
12276		if (result != ISC_R_SUCCESS) {
12277			flushed = false;
12278			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12279				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12280				      "flushing %s '%s' in cache view '%s' "
12281				      "failed: %s",
12282				      tree ? "tree" : "name", target,
12283				      view->name, isc_result_totext(result));
12284		}
12285	}
12286	if (flushed && found) {
12287		if (viewname != NULL) {
12288			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12289				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12290				      "flushing %s '%s' in cache view '%s' "
12291				      "succeeded",
12292				      tree ? "tree" : "name", target, viewname);
12293		} else {
12294			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12295				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12296				      "flushing %s '%s' in all cache views "
12297				      "succeeded",
12298				      tree ? "tree" : "name", target);
12299		}
12300		result = ISC_R_SUCCESS;
12301	} else {
12302		if (!found) {
12303			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12304				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12305				      "flushing %s '%s' in cache view '%s' "
12306				      "failed: view not found",
12307				      tree ? "tree" : "name", target, viewname);
12308		}
12309		result = ISC_R_FAILURE;
12310	}
12311	isc_task_endexclusive(server->task);
12312	return (result);
12313}
12314
12315isc_result_t
12316named_server_status(named_server_t *server, isc_buffer_t **text) {
12317	isc_result_t result;
12318	unsigned int zonecount, xferrunning, xferdeferred, soaqueries;
12319	unsigned int automatic;
12320	const char *ob = "", *cb = "", *alt = "";
12321	char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
12322	char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
12323	char line[1024], hostname[256];
12324	named_reload_t reload_status;
12325
12326	REQUIRE(text != NULL);
12327
12328	if (named_g_server->version_set) {
12329		ob = " (";
12330		cb = ")";
12331		if (named_g_server->version == NULL) {
12332			alt = "version.bind/txt/ch disabled";
12333		} else {
12334			alt = named_g_server->version;
12335		}
12336	}
12337	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
12338	xferrunning = dns_zonemgr_getcount(server->zonemgr,
12339					   DNS_ZONESTATE_XFERRUNNING);
12340	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
12341					    DNS_ZONESTATE_XFERDEFERRED);
12342	soaqueries = dns_zonemgr_getcount(server->zonemgr,
12343					  DNS_ZONESTATE_SOAQUERY);
12344	automatic = dns_zonemgr_getcount(server->zonemgr,
12345					 DNS_ZONESTATE_AUTOMATIC);
12346
12347	isc_time_formathttptimestamp(&named_g_boottime, boottime,
12348				     sizeof(boottime));
12349	isc_time_formathttptimestamp(&named_g_configtime, configtime,
12350				     sizeof(configtime));
12351
12352	snprintf(line, sizeof(line), "version: %s%s <id:%s>%s%s%s\n",
12353		 PACKAGE_STRING, PACKAGE_DESCRIPTION, PACKAGE_SRCID, ob, alt,
12354		 cb);
12355	CHECK(putstr(text, line));
12356
12357	if (gethostname(hostname, sizeof(hostname)) == 0) {
12358		strlcpy(hostname, "localhost", sizeof(hostname));
12359	}
12360	snprintf(line, sizeof(line), "running on %s: %s\n", hostname,
12361		 named_os_uname());
12362	CHECK(putstr(text, line));
12363
12364	snprintf(line, sizeof(line), "boot time: %s\n", boottime);
12365	CHECK(putstr(text, line));
12366
12367	snprintf(line, sizeof(line), "last configured: %s\n", configtime);
12368	CHECK(putstr(text, line));
12369
12370	if (named_g_chrootdir != NULL) {
12371		snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n",
12372			 named_g_conffile, named_g_chrootdir, named_g_conffile);
12373	} else {
12374		snprintf(line, sizeof(line), "configuration file: %s\n",
12375			 named_g_conffile);
12376	}
12377	CHECK(putstr(text, line));
12378
12379	snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected);
12380	CHECK(putstr(text, line));
12381
12382	snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
12383	CHECK(putstr(text, line));
12384
12385	snprintf(line, sizeof(line), "UDP listeners per interface: %u\n",
12386		 named_g_udpdisp);
12387	CHECK(putstr(text, line));
12388
12389	snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
12390		 zonecount, automatic);
12391	CHECK(putstr(text, line));
12392
12393	snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel);
12394	CHECK(putstr(text, line));
12395
12396	snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
12397	CHECK(putstr(text, line));
12398
12399	snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
12400	CHECK(putstr(text, line));
12401
12402	snprintf(line, sizeof(line), "soa queries in progress: %u\n",
12403		 soaqueries);
12404	CHECK(putstr(text, line));
12405
12406	snprintf(line, sizeof(line), "query logging is %s\n",
12407		 ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES)
12408			 ? "ON"
12409			 : "OFF");
12410	CHECK(putstr(text, line));
12411
12412	snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
12413		 isc_quota_getused(&server->sctx->recursionquota),
12414		 isc_quota_getsoft(&server->sctx->recursionquota),
12415		 isc_quota_getmax(&server->sctx->recursionquota));
12416	CHECK(putstr(text, line));
12417
12418	snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
12419		 isc_quota_getused(&server->sctx->tcpquota),
12420		 isc_quota_getmax(&server->sctx->tcpquota));
12421	CHECK(putstr(text, line));
12422
12423	snprintf(line, sizeof(line), "TCP high-water: %u\n",
12424		 (unsigned)ns_stats_get_counter(server->sctx->nsstats,
12425						ns_statscounter_tcphighwater));
12426	CHECK(putstr(text, line));
12427
12428	reload_status = atomic_load(&server->reload_status);
12429	if (reload_status != NAMED_RELOAD_DONE) {
12430		snprintf(line, sizeof(line), "reload/reconfig %s\n",
12431			 (reload_status == NAMED_RELOAD_FAILED
12432				  ? "failed"
12433				  : "in progress"));
12434		CHECK(putstr(text, line));
12435	}
12436
12437	CHECK(putstr(text, "server is up and running"));
12438	CHECK(putnull(text));
12439
12440	return (ISC_R_SUCCESS);
12441cleanup:
12442	return (result);
12443}
12444
12445isc_result_t
12446named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) {
12447	isc_result_t result;
12448	char *ptr;
12449	unsigned long count;
12450	unsigned long i;
12451	const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
12452
12453	REQUIRE(text != NULL);
12454
12455	/* Skip the command name. */
12456	ptr = next_token(lex, text);
12457	if (ptr == NULL) {
12458		return (ISC_R_UNEXPECTEDEND);
12459	}
12460
12461	ptr = next_token(lex, text);
12462	if (ptr == NULL) {
12463		count = 26;
12464	} else {
12465		count = strtoul(ptr, NULL, 10);
12466	}
12467
12468	CHECK(isc_buffer_reserve(text, count));
12469	for (i = 0; i < count; i++) {
12470		CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
12471	}
12472
12473	CHECK(putnull(text));
12474
12475cleanup:
12476	return (result);
12477}
12478
12479static isc_result_t
12480delete_keynames(dns_tsig_keyring_t *ring, char *target,
12481		unsigned int *foundkeys) {
12482	char namestr[DNS_NAME_FORMATSIZE];
12483	isc_result_t result;
12484	dns_rbtnodechain_t chain;
12485	dns_name_t foundname;
12486	dns_fixedname_t fixedorigin;
12487	dns_name_t *origin;
12488	dns_rbtnode_t *node;
12489	dns_tsigkey_t *tkey;
12490
12491	dns_name_init(&foundname, NULL);
12492	origin = dns_fixedname_initname(&fixedorigin);
12493
12494again:
12495	dns_rbtnodechain_init(&chain);
12496	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12497	if (result == ISC_R_NOTFOUND) {
12498		dns_rbtnodechain_invalidate(&chain);
12499		return (ISC_R_SUCCESS);
12500	}
12501	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12502		dns_rbtnodechain_invalidate(&chain);
12503		return (result);
12504	}
12505
12506	for (;;) {
12507		node = NULL;
12508		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12509		tkey = node->data;
12510
12511		if (tkey != NULL) {
12512			if (!tkey->generated) {
12513				goto nextkey;
12514			}
12515
12516			dns_name_format(&tkey->name, namestr, sizeof(namestr));
12517			if (strcmp(namestr, target) == 0) {
12518				(*foundkeys)++;
12519				dns_rbtnodechain_invalidate(&chain);
12520				(void)dns_rbt_deletename(ring->keys,
12521							 &tkey->name, false);
12522				goto again;
12523			}
12524		}
12525
12526	nextkey:
12527		result = dns_rbtnodechain_next(&chain, &foundname, origin);
12528		if (result == ISC_R_NOMORE) {
12529			break;
12530		}
12531		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12532			dns_rbtnodechain_invalidate(&chain);
12533			return (result);
12534		}
12535	}
12536
12537	return (ISC_R_SUCCESS);
12538}
12539
12540isc_result_t
12541named_server_tsigdelete(named_server_t *server, isc_lex_t *lex,
12542			isc_buffer_t **text) {
12543	isc_result_t result;
12544	dns_view_t *view;
12545	unsigned int foundkeys = 0;
12546	char *ptr, *viewname;
12547	char target[DNS_NAME_FORMATSIZE];
12548	char fbuf[16];
12549
12550	REQUIRE(text != NULL);
12551
12552	(void)next_token(lex, text); /* skip command name */
12553
12554	ptr = next_token(lex, text);
12555	if (ptr == NULL) {
12556		return (ISC_R_UNEXPECTEDEND);
12557	}
12558	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
12559
12560	viewname = next_token(lex, text);
12561
12562	result = isc_task_beginexclusive(server->task);
12563	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12564	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12565	     view = ISC_LIST_NEXT(view, link))
12566	{
12567		if (viewname == NULL || strcmp(view->name, viewname) == 0) {
12568			RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
12569			result = delete_keynames(view->dynamickeys, target,
12570						 &foundkeys);
12571			RWUNLOCK(&view->dynamickeys->lock,
12572				 isc_rwlocktype_write);
12573			if (result != ISC_R_SUCCESS) {
12574				isc_task_endexclusive(server->task);
12575				return (result);
12576			}
12577		}
12578	}
12579	isc_task_endexclusive(server->task);
12580
12581	snprintf(fbuf, sizeof(fbuf), "%u", foundkeys);
12582
12583	CHECK(putstr(text, fbuf));
12584	CHECK(putstr(text, " tsig keys deleted."));
12585	CHECK(putnull(text));
12586
12587cleanup:
12588	return (result);
12589}
12590
12591static isc_result_t
12592list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t **text,
12593	      unsigned int *foundkeys) {
12594	char namestr[DNS_NAME_FORMATSIZE];
12595	char creatorstr[DNS_NAME_FORMATSIZE];
12596	isc_result_t result;
12597	dns_rbtnodechain_t chain;
12598	dns_name_t foundname;
12599	dns_fixedname_t fixedorigin;
12600	dns_name_t *origin;
12601	dns_rbtnode_t *node;
12602	dns_tsigkey_t *tkey;
12603	const char *viewname;
12604
12605	if (view != NULL) {
12606		viewname = view->name;
12607	} else {
12608		viewname = "(global)";
12609	}
12610
12611	dns_name_init(&foundname, NULL);
12612	origin = dns_fixedname_initname(&fixedorigin);
12613	dns_rbtnodechain_init(&chain);
12614	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12615	if (result == ISC_R_NOTFOUND) {
12616		dns_rbtnodechain_invalidate(&chain);
12617		return (ISC_R_SUCCESS);
12618	}
12619	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12620		dns_rbtnodechain_invalidate(&chain);
12621		return (result);
12622	}
12623
12624	for (;;) {
12625		node = NULL;
12626		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12627		tkey = node->data;
12628
12629		if (tkey != NULL) {
12630			dns_name_format(&tkey->name, namestr, sizeof(namestr));
12631			if (tkey->generated) {
12632				dns_name_format(tkey->creator, creatorstr,
12633						sizeof(creatorstr));
12634				if (*foundkeys != 0) {
12635					CHECK(putstr(text, "\n"));
12636				}
12637				CHECK(putstr(text, "view \""));
12638				CHECK(putstr(text, viewname));
12639				CHECK(putstr(text, "\"; type \"dynamic\"; key "
12640						   "\""));
12641				CHECK(putstr(text, namestr));
12642				CHECK(putstr(text, "\"; creator \""));
12643				CHECK(putstr(text, creatorstr));
12644				CHECK(putstr(text, "\";"));
12645			} else {
12646				if (*foundkeys != 0) {
12647					CHECK(putstr(text, "\n"));
12648				}
12649				CHECK(putstr(text, "view \""));
12650				CHECK(putstr(text, viewname));
12651				CHECK(putstr(text, "\"; type \"static\"; key "
12652						   "\""));
12653				CHECK(putstr(text, namestr));
12654				CHECK(putstr(text, "\";"));
12655			}
12656			(*foundkeys)++;
12657		}
12658		result = dns_rbtnodechain_next(&chain, &foundname, origin);
12659		if (result == ISC_R_NOMORE || result == DNS_R_NEWORIGIN) {
12660			break;
12661		}
12662	}
12663
12664	return (ISC_R_SUCCESS);
12665cleanup:
12666	dns_rbtnodechain_invalidate(&chain);
12667	return (result);
12668}
12669
12670isc_result_t
12671named_server_tsiglist(named_server_t *server, isc_buffer_t **text) {
12672	isc_result_t result = ISC_R_SUCCESS;
12673	dns_view_t *view;
12674	unsigned int foundkeys = 0;
12675
12676	REQUIRE(text != NULL);
12677
12678	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12679	     view = ISC_LIST_NEXT(view, link))
12680	{
12681		RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12682		result = list_keynames(view, view->statickeys, text,
12683				       &foundkeys);
12684		RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12685		if (result != ISC_R_SUCCESS) {
12686			return (result);
12687		}
12688		RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12689		result = list_keynames(view, view->dynamickeys, text,
12690				       &foundkeys);
12691		RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12692		if (result != ISC_R_SUCCESS) {
12693			return (result);
12694		}
12695	}
12696
12697	if (foundkeys == 0) {
12698		CHECK(putstr(text, "no tsig keys found."));
12699	}
12700
12701	if (isc_buffer_usedlength(*text) > 0) {
12702		CHECK(putnull(text));
12703	}
12704
12705cleanup:
12706	return (result);
12707}
12708
12709/*
12710 * Act on a "sign" or "loadkeys" command from the command channel.
12711 */
12712isc_result_t
12713named_server_rekey(named_server_t *server, isc_lex_t *lex,
12714		   isc_buffer_t **text) {
12715	isc_result_t result;
12716	dns_zone_t *zone = NULL;
12717	dns_zonetype_t type;
12718	uint16_t keyopts;
12719	bool fullsign = false;
12720	char *ptr;
12721
12722	REQUIRE(text != NULL);
12723
12724	ptr = next_token(lex, text);
12725	if (ptr == NULL) {
12726		return (ISC_R_UNEXPECTEDEND);
12727	}
12728
12729	if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0) {
12730		fullsign = true;
12731	}
12732
12733	REQUIRE(text != NULL);
12734
12735	result = zone_from_args(server, lex, NULL, &zone, NULL, text, false);
12736	if (result != ISC_R_SUCCESS) {
12737		return (result);
12738	}
12739	if (zone == NULL) {
12740		return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */
12741	}
12742
12743	type = dns_zone_gettype(zone);
12744	if (type != dns_zone_primary) {
12745		dns_zone_detach(&zone);
12746		return (DNS_R_NOTPRIMARY);
12747	}
12748
12749	keyopts = dns_zone_getkeyopts(zone);
12750
12751	/*
12752	 * "rndc loadkeys" requires "auto-dnssec maintain"
12753	 * or a "dnssec-policy".
12754	 */
12755	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) {
12756		result = ISC_R_NOPERM;
12757	} else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) {
12758		result = ISC_R_NOPERM;
12759	} else {
12760		dns_zone_rekey(zone, fullsign);
12761	}
12762
12763	dns_zone_detach(&zone);
12764	return (result);
12765}
12766
12767/*
12768 * Act on a "sync" command from the command channel.
12769 */
12770static isc_result_t
12771synczone(dns_zone_t *zone, void *uap) {
12772	bool cleanup = *(bool *)uap;
12773	isc_result_t result;
12774	dns_zone_t *raw = NULL;
12775	char *journal;
12776
12777	dns_zone_getraw(zone, &raw);
12778	if (raw != NULL) {
12779		synczone(raw, uap);
12780		dns_zone_detach(&raw);
12781	}
12782
12783	result = dns_zone_flush(zone);
12784	if (result != ISC_R_SUCCESS) {
12785		cleanup = false;
12786	}
12787	if (cleanup) {
12788		journal = dns_zone_getjournal(zone);
12789		if (journal != NULL) {
12790			(void)isc_file_remove(journal);
12791		}
12792	}
12793
12794	return (result);
12795}
12796
12797isc_result_t
12798named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
12799	isc_result_t result, tresult;
12800	dns_view_t *view;
12801	dns_zone_t *zone = NULL;
12802	char classstr[DNS_RDATACLASS_FORMATSIZE];
12803	char zonename[DNS_NAME_FORMATSIZE];
12804	const char *vname, *sep, *arg;
12805	bool cleanup = false;
12806
12807	REQUIRE(text != NULL);
12808
12809	(void)next_token(lex, text);
12810
12811	arg = next_token(lex, text);
12812	if (arg != NULL &&
12813	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0))
12814	{
12815		cleanup = true;
12816		arg = next_token(lex, text);
12817	}
12818
12819	REQUIRE(text != NULL);
12820
12821	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
12822	if (result != ISC_R_SUCCESS) {
12823		return (result);
12824	}
12825
12826	if (zone == NULL) {
12827		result = isc_task_beginexclusive(server->task);
12828		RUNTIME_CHECK(result == ISC_R_SUCCESS);
12829		tresult = ISC_R_SUCCESS;
12830		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12831		     view = ISC_LIST_NEXT(view, link))
12832		{
12833			result = dns_zt_apply(view->zonetable,
12834					      isc_rwlocktype_none, false, NULL,
12835					      synczone, &cleanup);
12836			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12837			{
12838				tresult = result;
12839			}
12840		}
12841		isc_task_endexclusive(server->task);
12842		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12843			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12844			      "dumping all zones%s: %s",
12845			      cleanup ? ", removing journal files" : "",
12846			      isc_result_totext(result));
12847		return (tresult);
12848	}
12849
12850	result = isc_task_beginexclusive(server->task);
12851	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12852	result = synczone(zone, &cleanup);
12853	isc_task_endexclusive(server->task);
12854
12855	view = dns_zone_getview(zone);
12856	if (strcmp(view->name, "_default") == 0 ||
12857	    strcmp(view->name, "_bind") == 0)
12858	{
12859		vname = "";
12860		sep = "";
12861	} else {
12862		vname = view->name;
12863		sep = " ";
12864	}
12865	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
12866			      sizeof(classstr));
12867	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
12868	isc_log_write(
12869		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12870		ISC_LOG_INFO, "sync: dumping zone '%s/%s'%s%s%s: %s", zonename,
12871		classstr, sep, vname, cleanup ? ", removing journal file" : "",
12872		isc_result_totext(result));
12873	dns_zone_detach(&zone);
12874	return (result);
12875}
12876
12877/*
12878 * Act on a "freeze" or "thaw" command from the command channel.
12879 */
12880isc_result_t
12881named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex,
12882		    isc_buffer_t **text) {
12883	isc_result_t result, tresult;
12884	dns_zone_t *mayberaw = NULL, *raw = NULL;
12885	dns_zonetype_t type;
12886	char classstr[DNS_RDATACLASS_FORMATSIZE];
12887	char zonename[DNS_NAME_FORMATSIZE];
12888	dns_view_t *view;
12889	const char *vname, *sep;
12890	bool frozen;
12891	const char *msg = NULL;
12892
12893	REQUIRE(text != NULL);
12894
12895	result = zone_from_args(server, lex, NULL, &mayberaw, NULL, text, true);
12896	if (result != ISC_R_SUCCESS) {
12897		return (result);
12898	}
12899	if (mayberaw == NULL) {
12900		result = isc_task_beginexclusive(server->task);
12901		RUNTIME_CHECK(result == ISC_R_SUCCESS);
12902		tresult = ISC_R_SUCCESS;
12903		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12904		     view = ISC_LIST_NEXT(view, link))
12905		{
12906			result = dns_view_freezezones(view, freeze);
12907			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12908			{
12909				tresult = result;
12910			}
12911		}
12912		isc_task_endexclusive(server->task);
12913		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12914			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12915			      "%s all zones: %s",
12916			      freeze ? "freezing" : "thawing",
12917			      isc_result_totext(tresult));
12918		return (tresult);
12919	}
12920	dns_zone_getraw(mayberaw, &raw);
12921	if (raw != NULL) {
12922		dns_zone_detach(&mayberaw);
12923		dns_zone_attach(raw, &mayberaw);
12924		dns_zone_detach(&raw);
12925	}
12926	type = dns_zone_gettype(mayberaw);
12927	if (type != dns_zone_primary) {
12928		dns_zone_detach(&mayberaw);
12929		return (DNS_R_NOTPRIMARY);
12930	}
12931
12932	if (freeze && !dns_zone_isdynamic(mayberaw, true)) {
12933		dns_zone_detach(&mayberaw);
12934		return (DNS_R_NOTDYNAMIC);
12935	}
12936
12937	result = isc_task_beginexclusive(server->task);
12938	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12939	frozen = dns_zone_getupdatedisabled(mayberaw);
12940	if (freeze) {
12941		if (frozen) {
12942			msg = "WARNING: The zone was already frozen.\n"
12943			      "Someone else may be editing it or "
12944			      "it may still be re-loading.";
12945			result = DNS_R_FROZEN;
12946		}
12947		if (result == ISC_R_SUCCESS) {
12948			result = dns_zone_flush(mayberaw);
12949			if (result != ISC_R_SUCCESS) {
12950				msg = "Flushing the zone updates to "
12951				      "disk failed.";
12952			}
12953		}
12954		if (result == ISC_R_SUCCESS) {
12955			dns_zone_setupdatedisabled(mayberaw, freeze);
12956		}
12957	} else {
12958		if (frozen) {
12959			result = dns_zone_loadandthaw(mayberaw);
12960			switch (result) {
12961			case ISC_R_SUCCESS:
12962			case DNS_R_UPTODATE:
12963				msg = "The zone reload and thaw was "
12964				      "successful.";
12965				result = ISC_R_SUCCESS;
12966				break;
12967			case DNS_R_CONTINUE:
12968				msg = "A zone reload and thaw was started.\n"
12969				      "Check the logs to see the result.";
12970				result = ISC_R_SUCCESS;
12971				break;
12972			default:
12973				break;
12974			}
12975		}
12976	}
12977	isc_task_endexclusive(server->task);
12978
12979	if (msg != NULL) {
12980		(void)putstr(text, msg);
12981		(void)putnull(text);
12982	}
12983
12984	view = dns_zone_getview(mayberaw);
12985	if (strcmp(view->name, "_default") == 0 ||
12986	    strcmp(view->name, "_bind") == 0)
12987	{
12988		vname = "";
12989		sep = "";
12990	} else {
12991		vname = view->name;
12992		sep = " ";
12993	}
12994	dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr,
12995			      sizeof(classstr));
12996	dns_name_format(dns_zone_getorigin(mayberaw), zonename,
12997			sizeof(zonename));
12998	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12999		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13000		      "%s zone '%s/%s'%s%s: %s",
13001		      freeze ? "freezing" : "thawing", zonename, classstr, sep,
13002		      vname, isc_result_totext(result));
13003	dns_zone_detach(&mayberaw);
13004	return (result);
13005}
13006
13007#ifdef HAVE_LIBSCF
13008/*
13009 * This function adds a message for rndc to echo if named
13010 * is managed by smf and is also running chroot.
13011 */
13012isc_result_t
13013named_smf_add_message(isc_buffer_t **text) {
13014	REQUIRE(text != NULL);
13015
13016	return (putstr(text, "use svcadm(1M) to manage named"));
13017}
13018#endif /* HAVE_LIBSCF */
13019
13020#ifndef HAVE_LMDB
13021
13022/*
13023 * Emit a comment at the top of the nzf file containing the viewname
13024 * Expects the fp to already be open for writing
13025 */
13026#define HEADER1 "# New zone file for view: "
13027#define HEADER2                                                     \
13028	"\n# This file contains configuration for zones added by\n" \
13029	"# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
13030static isc_result_t
13031add_comment(FILE *fp, const char *viewname) {
13032	isc_result_t result;
13033	CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
13034	CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
13035	CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
13036cleanup:
13037	return (result);
13038}
13039
13040static void
13041dumpzone(void *arg, const char *buf, int len) {
13042	FILE *fp = arg;
13043
13044	(void)isc_stdio_write(buf, len, 1, fp, NULL);
13045}
13046
13047static isc_result_t
13048nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
13049	isc_result_t result;
13050	off_t offset;
13051	FILE *fp = NULL;
13052	bool offsetok = false;
13053
13054	LOCK(&view->new_zone_lock);
13055
13056	CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
13057	CHECK(isc_stdio_seek(fp, 0, SEEK_END));
13058
13059	CHECK(isc_stdio_tell(fp, &offset));
13060	offsetok = true;
13061	if (offset == 0) {
13062		CHECK(add_comment(fp, view->name));
13063	}
13064
13065	CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
13066	cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
13067	CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
13068	CHECK(isc_stdio_flush(fp));
13069	result = isc_stdio_close(fp);
13070	fp = NULL;
13071
13072cleanup:
13073	if (fp != NULL) {
13074		(void)isc_stdio_close(fp);
13075		if (offsetok) {
13076			isc_result_t result2;
13077
13078			result2 = isc_file_truncate(view->new_zone_file,
13079						    offset);
13080			if (result2 != ISC_R_SUCCESS) {
13081				isc_log_write(
13082					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13083					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13084					"Error truncating NZF file '%s' "
13085					"during rollback from append: "
13086					"%s",
13087					view->new_zone_file,
13088					isc_result_totext(result2));
13089			}
13090		}
13091	}
13092	UNLOCK(&view->new_zone_lock);
13093	return (result);
13094}
13095
13096static isc_result_t
13097nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
13098	const cfg_obj_t *zl = NULL;
13099	cfg_list_t *list;
13100	const cfg_listelt_t *elt;
13101
13102	FILE *fp = NULL;
13103	char tmp[1024];
13104	isc_result_t result;
13105
13106	result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp,
13107				   sizeof(tmp));
13108	if (result == ISC_R_SUCCESS) {
13109		result = isc_file_openunique(tmp, &fp);
13110	}
13111	if (result != ISC_R_SUCCESS) {
13112		return (result);
13113	}
13114
13115	cfg_map_get(config, "zone", &zl);
13116	if (!cfg_obj_islist(zl)) {
13117		CHECK(ISC_R_FAILURE);
13118	}
13119
13120	DE_CONST(&zl->value.list, list);
13121
13122	CHECK(add_comment(fp, view->name)); /* force a comment */
13123
13124	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13125	     elt = ISC_LIST_NEXT(elt, link))
13126	{
13127		const cfg_obj_t *zconfig = cfg_listelt_value(elt);
13128
13129		CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
13130		cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
13131		CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
13132	}
13133
13134	CHECK(isc_stdio_flush(fp));
13135	result = isc_stdio_close(fp);
13136	fp = NULL;
13137	if (result != ISC_R_SUCCESS) {
13138		goto cleanup;
13139	}
13140	CHECK(isc_file_rename(tmp, view->new_zone_file));
13141	return (result);
13142
13143cleanup:
13144	if (fp != NULL) {
13145		(void)isc_stdio_close(fp);
13146	}
13147	(void)isc_file_remove(tmp);
13148	return (result);
13149}
13150
13151#else /* HAVE_LMDB */
13152
13153static void
13154nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
13155	dns_fixedname_t fixed;
13156
13157	dns_fixedname_init(&fixed);
13158	dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
13159	dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
13160
13161	key->mv_data = namebuf;
13162	key->mv_size = strlen(namebuf);
13163}
13164
13165static void
13166dumpzone(void *arg, const char *buf, int len) {
13167	ns_dzarg_t *dzarg = arg;
13168	isc_result_t result;
13169
13170	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
13171
13172	result = putmem(dzarg->text, buf, len);
13173	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
13174		dzarg->result = result;
13175	}
13176}
13177
13178static isc_result_t
13179nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
13180	 const cfg_obj_t *zconfig) {
13181	isc_result_t result;
13182	int status;
13183	dns_view_t *view;
13184	bool commit = false;
13185	isc_buffer_t *text = NULL;
13186	char namebuf[1024];
13187	MDB_val key, data;
13188	ns_dzarg_t dzarg;
13189
13190	view = dns_zone_getview(zone);
13191
13192	nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
13193
13194	if (zconfig == NULL) {
13195		/* We're deleting the zone from the database */
13196		status = mdb_del(*txnp, dbi, &key, NULL);
13197		if (status != MDB_SUCCESS && status != MDB_NOTFOUND) {
13198			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13199				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13200				      "Error deleting zone %s "
13201				      "from NZD database: %s",
13202				      namebuf, mdb_strerror(status));
13203			result = ISC_R_FAILURE;
13204			goto cleanup;
13205		} else if (status != MDB_NOTFOUND) {
13206			commit = true;
13207		}
13208	} else {
13209		/* We're creating or overwriting the zone */
13210		const cfg_obj_t *zoptions;
13211
13212		isc_buffer_allocate(view->mctx, &text, 256);
13213
13214		zoptions = cfg_tuple_get(zconfig, "options");
13215		if (zoptions == NULL) {
13216			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13217				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13218				      "Unable to get options from config in "
13219				      "nzd_save()");
13220			result = ISC_R_FAILURE;
13221			goto cleanup;
13222		}
13223
13224		dzarg.magic = DZARG_MAGIC;
13225		dzarg.text = &text;
13226		dzarg.result = ISC_R_SUCCESS;
13227		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13228		if (dzarg.result != ISC_R_SUCCESS) {
13229			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13230				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13231				      "Error writing zone config to "
13232				      "buffer in nzd_save(): %s",
13233				      isc_result_totext(dzarg.result));
13234			result = dzarg.result;
13235			goto cleanup;
13236		}
13237
13238		data.mv_data = isc_buffer_base(text);
13239		data.mv_size = isc_buffer_usedlength(text);
13240
13241		status = mdb_put(*txnp, dbi, &key, &data, 0);
13242		if (status != MDB_SUCCESS) {
13243			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13244				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13245				      "Error inserting zone in "
13246				      "NZD database: %s",
13247				      mdb_strerror(status));
13248			result = ISC_R_FAILURE;
13249			goto cleanup;
13250		}
13251
13252		commit = true;
13253	}
13254
13255	result = ISC_R_SUCCESS;
13256
13257cleanup:
13258	if (!commit || result != ISC_R_SUCCESS) {
13259		(void)mdb_txn_abort(*txnp);
13260	} else {
13261		status = mdb_txn_commit(*txnp);
13262		if (status != MDB_SUCCESS) {
13263			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13264				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13265				      "Error committing "
13266				      "NZD database: %s",
13267				      mdb_strerror(status));
13268			result = ISC_R_FAILURE;
13269		}
13270	}
13271	*txnp = NULL;
13272
13273	if (text != NULL) {
13274		isc_buffer_free(&text);
13275	}
13276
13277	return (result);
13278}
13279
13280/*
13281 * Check whether the new zone database for 'view' can be opened for writing.
13282 *
13283 * Caller must hold 'view->new_zone_lock'.
13284 */
13285static isc_result_t
13286nzd_writable(dns_view_t *view) {
13287	isc_result_t result = ISC_R_SUCCESS;
13288	int status;
13289	MDB_dbi dbi;
13290	MDB_txn *txn = NULL;
13291
13292	REQUIRE(view != NULL);
13293
13294	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn);
13295	if (status != MDB_SUCCESS) {
13296		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13297			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13298			      "mdb_txn_begin: %s", mdb_strerror(status));
13299		return (ISC_R_FAILURE);
13300	}
13301
13302	status = mdb_dbi_open(txn, NULL, 0, &dbi);
13303	if (status != MDB_SUCCESS) {
13304		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13305			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13306			      "mdb_dbi_open: %s", mdb_strerror(status));
13307		result = ISC_R_FAILURE;
13308	}
13309
13310	mdb_txn_abort(txn);
13311	return (result);
13312}
13313
13314/*
13315 * Open the new zone database for 'view' and start a transaction for it.
13316 *
13317 * Caller must hold 'view->new_zone_lock'.
13318 */
13319static isc_result_t
13320nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
13321	int status;
13322	MDB_txn *txn = NULL;
13323
13324	REQUIRE(view != NULL);
13325	REQUIRE(txnp != NULL && *txnp == NULL);
13326	REQUIRE(dbi != NULL);
13327
13328	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn);
13329	if (status != MDB_SUCCESS) {
13330		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13331			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13332			      "mdb_txn_begin: %s", mdb_strerror(status));
13333		goto cleanup;
13334	}
13335
13336	status = mdb_dbi_open(txn, NULL, 0, dbi);
13337	if (status != MDB_SUCCESS) {
13338		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13339			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13340			      "mdb_dbi_open: %s", mdb_strerror(status));
13341		goto cleanup;
13342	}
13343
13344	*txnp = txn;
13345
13346cleanup:
13347	if (status != MDB_SUCCESS) {
13348		if (txn != NULL) {
13349			mdb_txn_abort(txn);
13350		}
13351		return (ISC_R_FAILURE);
13352	}
13353
13354	return (ISC_R_SUCCESS);
13355}
13356
13357/*
13358 * nzd_env_close() and nzd_env_reopen are a kluge to address the
13359 * problem of an NZD file possibly being created before we drop
13360 * root privileges.
13361 */
13362static void
13363nzd_env_close(dns_view_t *view) {
13364	const char *dbpath = NULL;
13365	char dbpath_copy[PATH_MAX];
13366	char lockpath[PATH_MAX];
13367	int status, ret;
13368
13369	if (view->new_zone_dbenv == NULL) {
13370		return;
13371	}
13372
13373	status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
13374	INSIST(status == MDB_SUCCESS);
13375	snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
13376	strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
13377	mdb_env_close((MDB_env *)view->new_zone_dbenv);
13378
13379	/*
13380	 * Database files must be owned by the eventual user, not by root.
13381	 */
13382	ret = chown(dbpath_copy, ns_os_uid(), -1);
13383	UNUSED(ret);
13384
13385	/*
13386	 * Some platforms need the lockfile not to exist when we reopen the
13387	 * environment.
13388	 */
13389	(void)isc_file_remove(lockpath);
13390
13391	view->new_zone_dbenv = NULL;
13392}
13393
13394static isc_result_t
13395nzd_env_reopen(dns_view_t *view) {
13396	isc_result_t result;
13397	MDB_env *env = NULL;
13398	int status;
13399
13400	if (view->new_zone_db == NULL) {
13401		return (ISC_R_SUCCESS);
13402	}
13403
13404	nzd_env_close(view);
13405
13406	status = mdb_env_create(&env);
13407	if (status != MDB_SUCCESS) {
13408		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13409			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13410			      "mdb_env_create failed: %s",
13411			      mdb_strerror(status));
13412		CHECK(ISC_R_FAILURE);
13413	}
13414
13415	if (view->new_zone_mapsize != 0ULL) {
13416		status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
13417		if (status != MDB_SUCCESS) {
13418			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13419				      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13420				      "mdb_env_set_mapsize failed: %s",
13421				      mdb_strerror(status));
13422			CHECK(ISC_R_FAILURE);
13423		}
13424	}
13425
13426	status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
13427	if (status != MDB_SUCCESS) {
13428		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13429			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13430			      "mdb_env_open of '%s' failed: %s",
13431			      view->new_zone_db, mdb_strerror(status));
13432		CHECK(ISC_R_FAILURE);
13433	}
13434
13435	view->new_zone_dbenv = env;
13436	env = NULL;
13437	result = ISC_R_SUCCESS;
13438
13439cleanup:
13440	if (env != NULL) {
13441		mdb_env_close(env);
13442	}
13443	return (result);
13444}
13445
13446/*
13447 * If 'commit' is true, commit the new zone database transaction pointed to by
13448 * 'txnp'; otherwise, abort that transaction.
13449 *
13450 * Caller must hold 'view->new_zone_lock' for the view that the transaction
13451 * pointed to by 'txnp' was started for.
13452 */
13453static isc_result_t
13454nzd_close(MDB_txn **txnp, bool commit) {
13455	isc_result_t result = ISC_R_SUCCESS;
13456	int status;
13457
13458	REQUIRE(txnp != NULL);
13459
13460	if (*txnp != NULL) {
13461		if (commit) {
13462			status = mdb_txn_commit(*txnp);
13463			if (status != MDB_SUCCESS) {
13464				result = ISC_R_FAILURE;
13465			}
13466		} else {
13467			mdb_txn_abort(*txnp);
13468		}
13469		*txnp = NULL;
13470	}
13471
13472	return (result);
13473}
13474
13475/*
13476 * Count the zones configured in the new zone database for 'view' and store the
13477 * result in 'countp'.
13478 *
13479 * Caller must hold 'view->new_zone_lock'.
13480 */
13481static isc_result_t
13482nzd_count(dns_view_t *view, int *countp) {
13483	isc_result_t result;
13484	int status;
13485	MDB_txn *txn = NULL;
13486	MDB_dbi dbi;
13487	MDB_stat statbuf;
13488
13489	REQUIRE(countp != NULL);
13490
13491	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
13492	if (result != ISC_R_SUCCESS) {
13493		goto cleanup;
13494	}
13495
13496	status = mdb_stat(txn, dbi, &statbuf);
13497	if (status != MDB_SUCCESS) {
13498		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13499			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13500			      "mdb_stat: %s", mdb_strerror(status));
13501		result = ISC_R_FAILURE;
13502		goto cleanup;
13503	}
13504
13505	*countp = statbuf.ms_entries;
13506
13507cleanup:
13508	(void)nzd_close(&txn, false);
13509
13510	return (result);
13511}
13512
13513/*
13514 * Migrate zone configuration from an NZF file to an NZD database.
13515 * Caller must hold view->new_zone_lock.
13516 */
13517static isc_result_t
13518migrate_nzf(dns_view_t *view) {
13519	isc_result_t result;
13520	cfg_obj_t *nzf_config = NULL;
13521	int status, n;
13522	isc_buffer_t *text = NULL;
13523	bool commit = false;
13524	const cfg_obj_t *zonelist;
13525	const cfg_listelt_t *element;
13526	char tempname[PATH_MAX];
13527	MDB_txn *txn = NULL;
13528	MDB_dbi dbi;
13529	MDB_val key, data;
13530	ns_dzarg_t dzarg;
13531
13532	/*
13533	 * If NZF file doesn't exist, or NZD DB exists and already
13534	 * has data, return without attempting migration.
13535	 */
13536	if (!isc_file_exists(view->new_zone_file)) {
13537		result = ISC_R_SUCCESS;
13538		goto cleanup;
13539	}
13540
13541	result = nzd_count(view, &n);
13542	if (result == ISC_R_SUCCESS && n > 0) {
13543		result = ISC_R_SUCCESS;
13544		goto cleanup;
13545	}
13546
13547	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13548		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13549		      "Migrating zones from NZF file '%s' to "
13550		      "NZD database '%s'",
13551		      view->new_zone_file, view->new_zone_db);
13552	/*
13553	 * Instead of blindly copying lines, we parse the NZF file using
13554	 * the configuration parser, because it validates it against the
13555	 * config type, giving us a guarantee that valid configuration
13556	 * will be written to DB.
13557	 */
13558	cfg_parser_reset(named_g_addparser);
13559	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
13560				&cfg_type_addzoneconf, &nzf_config);
13561	if (result != ISC_R_SUCCESS) {
13562		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13563			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13564			      "Error parsing NZF file '%s': %s",
13565			      view->new_zone_file, isc_result_totext(result));
13566		goto cleanup;
13567	}
13568
13569	zonelist = NULL;
13570	CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
13571	if (!cfg_obj_islist(zonelist)) {
13572		CHECK(ISC_R_FAILURE);
13573	}
13574
13575	CHECK(nzd_open(view, 0, &txn, &dbi));
13576
13577	isc_buffer_allocate(view->mctx, &text, 256);
13578
13579	for (element = cfg_list_first(zonelist); element != NULL;
13580	     element = cfg_list_next(element))
13581	{
13582		const cfg_obj_t *zconfig;
13583		const cfg_obj_t *zoptions;
13584		char zname[DNS_NAME_FORMATSIZE];
13585		dns_fixedname_t fname;
13586		dns_name_t *name;
13587		const char *origin;
13588		isc_buffer_t b;
13589
13590		zconfig = cfg_listelt_value(element);
13591
13592		origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
13593		if (origin == NULL) {
13594			result = ISC_R_FAILURE;
13595			goto cleanup;
13596		}
13597
13598		/* Normalize zone name */
13599		isc_buffer_constinit(&b, origin, strlen(origin));
13600		isc_buffer_add(&b, strlen(origin));
13601		name = dns_fixedname_initname(&fname);
13602		CHECK(dns_name_fromtext(name, &b, dns_rootname,
13603					DNS_NAME_DOWNCASE, NULL));
13604		dns_name_format(name, zname, sizeof(zname));
13605
13606		key.mv_data = zname;
13607		key.mv_size = strlen(zname);
13608
13609		zoptions = cfg_tuple_get(zconfig, "options");
13610		if (zoptions == NULL) {
13611			result = ISC_R_FAILURE;
13612			goto cleanup;
13613		}
13614
13615		isc_buffer_clear(text);
13616		dzarg.magic = DZARG_MAGIC;
13617		dzarg.text = &text;
13618		dzarg.result = ISC_R_SUCCESS;
13619		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13620		if (dzarg.result != ISC_R_SUCCESS) {
13621			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13622				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13623				      "Error writing zone config to "
13624				      "buffer in migrate_nzf(): %s",
13625				      isc_result_totext(result));
13626			result = dzarg.result;
13627			goto cleanup;
13628		}
13629
13630		data.mv_data = isc_buffer_base(text);
13631		data.mv_size = isc_buffer_usedlength(text);
13632
13633		status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
13634		if (status != MDB_SUCCESS) {
13635			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13636				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13637				      "Error inserting zone in "
13638				      "NZD database: %s",
13639				      mdb_strerror(status));
13640			result = ISC_R_FAILURE;
13641			goto cleanup;
13642		}
13643
13644		commit = true;
13645	}
13646
13647	result = ISC_R_SUCCESS;
13648
13649	/*
13650	 * Leaving the NZF file in place is harmless as we won't use it
13651	 * if an NZD database is found for the view. But we rename NZF file
13652	 * to a backup name here.
13653	 */
13654	strlcpy(tempname, view->new_zone_file, sizeof(tempname));
13655	if (strlen(tempname) < sizeof(tempname) - 1) {
13656		strlcat(tempname, "~", sizeof(tempname));
13657		isc_file_rename(view->new_zone_file, tempname);
13658	}
13659
13660cleanup:
13661	if (result != ISC_R_SUCCESS) {
13662		(void)nzd_close(&txn, false);
13663	} else {
13664		result = nzd_close(&txn, commit);
13665	}
13666
13667	if (text != NULL) {
13668		isc_buffer_free(&text);
13669	}
13670
13671	if (nzf_config != NULL) {
13672		cfg_obj_destroy(named_g_addparser, &nzf_config);
13673	}
13674
13675	return (result);
13676}
13677
13678#endif /* HAVE_LMDB */
13679
13680static isc_result_t
13681newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
13682	      cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
13683	      bool *redirectp, isc_buffer_t **text) {
13684	isc_result_t result;
13685	isc_buffer_t argbuf;
13686	bool redirect = false;
13687	cfg_obj_t *zoneconf = NULL;
13688	const cfg_obj_t *zlist = NULL;
13689	const cfg_obj_t *zoneobj = NULL;
13690	const cfg_obj_t *zoptions = NULL;
13691	const cfg_obj_t *obj = NULL;
13692	const char *viewname = NULL;
13693	dns_rdataclass_t rdclass;
13694	dns_view_t *view = NULL;
13695	const char *bn = NULL;
13696
13697	REQUIRE(viewp != NULL && *viewp == NULL);
13698	REQUIRE(zoneobjp != NULL && *zoneobjp == NULL);
13699	REQUIRE(zoneconfp != NULL && *zoneconfp == NULL);
13700	REQUIRE(redirectp != NULL);
13701
13702	/* Try to parse the argument string */
13703	isc_buffer_init(&argbuf, command, (unsigned int)strlen(command));
13704	isc_buffer_add(&argbuf, strlen(command));
13705
13706	if (strncasecmp(command, "add", 3) == 0) {
13707		bn = "addzone";
13708	} else if (strncasecmp(command, "mod", 3) == 0) {
13709		bn = "modzone";
13710	} else {
13711		UNREACHABLE();
13712	}
13713
13714	/*
13715	 * Convert the "addzone" or "modzone" to just "zone", for
13716	 * the benefit of the parser
13717	 */
13718	isc_buffer_forward(&argbuf, 3);
13719
13720	cfg_parser_reset(named_g_addparser);
13721	CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0,
13722			       &cfg_type_addzoneconf, 0, &zoneconf));
13723	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
13724	if (!cfg_obj_islist(zlist)) {
13725		CHECK(ISC_R_FAILURE);
13726	}
13727
13728	/* For now we only support adding one zone at a time */
13729	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
13730
13731	/* Check the zone type for ones that are not supported by addzone. */
13732	zoptions = cfg_tuple_get(zoneobj, "options");
13733
13734	obj = NULL;
13735	(void)cfg_map_get(zoptions, "type", &obj);
13736	if (obj == NULL) {
13737		(void)cfg_map_get(zoptions, "in-view", &obj);
13738		if (obj != NULL) {
13739			(void)putstr(text, "'in-view' zones not supported by ");
13740			(void)putstr(text, bn);
13741		} else {
13742			(void)putstr(text, "zone type not specified");
13743		}
13744		CHECK(ISC_R_FAILURE);
13745	}
13746
13747	if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
13748	    strcasecmp(cfg_obj_asstring(obj), "forward") == 0 ||
13749	    strcasecmp(cfg_obj_asstring(obj), "delegation-only") == 0)
13750	{
13751		(void)putstr(text, "'");
13752		(void)putstr(text, cfg_obj_asstring(obj));
13753		(void)putstr(text, "' zones not supported by ");
13754		(void)putstr(text, bn);
13755		CHECK(ISC_R_FAILURE);
13756	}
13757
13758	if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0) {
13759		redirect = true;
13760	}
13761
13762	/* Make sense of optional class argument */
13763	obj = cfg_tuple_get(zoneobj, "class");
13764	CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass));
13765
13766	/* Make sense of optional view argument */
13767	obj = cfg_tuple_get(zoneobj, "view");
13768	if (obj && cfg_obj_isstring(obj)) {
13769		viewname = cfg_obj_asstring(obj);
13770	}
13771	if (viewname == NULL || *viewname == '\0') {
13772		viewname = "_default";
13773	}
13774	result = dns_viewlist_find(&server->viewlist, viewname, rdclass, &view);
13775	if (result == ISC_R_NOTFOUND) {
13776		(void)putstr(text, "no matching view found for '");
13777		(void)putstr(text, viewname);
13778		(void)putstr(text, "'");
13779		goto cleanup;
13780	} else if (result != ISC_R_SUCCESS) {
13781		goto cleanup;
13782	}
13783
13784	*viewp = view;
13785	*zoneobjp = zoneobj;
13786	*zoneconfp = zoneconf;
13787	*redirectp = redirect;
13788
13789	return (ISC_R_SUCCESS);
13790
13791cleanup:
13792	if (zoneconf != NULL) {
13793		cfg_obj_destroy(named_g_addparser, &zoneconf);
13794	}
13795	if (view != NULL) {
13796		dns_view_detach(&view);
13797	}
13798
13799	return (result);
13800}
13801
13802static isc_result_t
13803delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config,
13804		const dns_name_t *zname, nzfwriter_t nzfwriter) {
13805	isc_result_t result = ISC_R_NOTFOUND;
13806	const cfg_listelt_t *elt = NULL;
13807	const cfg_obj_t *zl = NULL;
13808	cfg_list_t *list;
13809	dns_fixedname_t myfixed;
13810	dns_name_t *myname;
13811
13812	REQUIRE(view != NULL);
13813	REQUIRE(pctx != NULL);
13814	REQUIRE(config != NULL);
13815	REQUIRE(zname != NULL);
13816
13817	LOCK(&view->new_zone_lock);
13818
13819	cfg_map_get(config, "zone", &zl);
13820
13821	if (!cfg_obj_islist(zl)) {
13822		CHECK(ISC_R_FAILURE);
13823	}
13824
13825	DE_CONST(&zl->value.list, list);
13826
13827	myname = dns_fixedname_initname(&myfixed);
13828
13829	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13830	     elt = ISC_LIST_NEXT(elt, link))
13831	{
13832		const cfg_obj_t *zconf = cfg_listelt_value(elt);
13833		const char *zn;
13834		cfg_listelt_t *e;
13835
13836		zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
13837		result = dns_name_fromstring(myname, zn, 0, NULL);
13838		if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname)) {
13839			continue;
13840		}
13841
13842		DE_CONST(elt, e);
13843		ISC_LIST_UNLINK(*list, e, link);
13844		cfg_obj_destroy(pctx, &e->obj);
13845		isc_mem_put(pctx->mctx, e, sizeof(*e));
13846		result = ISC_R_SUCCESS;
13847		break;
13848	}
13849
13850	/*
13851	 * Write config to NZF file if appropriate
13852	 */
13853	if (nzfwriter != NULL && view->new_zone_file != NULL) {
13854		result = nzfwriter(config, view);
13855	}
13856
13857cleanup:
13858	UNLOCK(&view->new_zone_lock);
13859	return (result);
13860}
13861
13862static isc_result_t
13863do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13864	   dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
13865	   bool redirect, isc_buffer_t **text) {
13866	isc_result_t result, tresult;
13867	dns_zone_t *zone = NULL;
13868#ifndef HAVE_LMDB
13869	FILE *fp = NULL;
13870	bool cleanup_config = false;
13871#else /* HAVE_LMDB */
13872	MDB_txn *txn = NULL;
13873	MDB_dbi dbi;
13874	bool locked = false;
13875
13876	UNUSED(zoneconf);
13877#endif
13878
13879	/* Zone shouldn't already exist */
13880	if (redirect) {
13881		result = (view->redirect != NULL) ? ISC_R_SUCCESS
13882						  : ISC_R_NOTFOUND;
13883	} else {
13884		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13885	}
13886	if (result == ISC_R_SUCCESS) {
13887		result = ISC_R_EXISTS;
13888		goto cleanup;
13889	} else if (result == DNS_R_PARTIALMATCH) {
13890		/* Create our sub-zone anyway */
13891		dns_zone_detach(&zone);
13892		zone = NULL;
13893	} else if (result != ISC_R_NOTFOUND) {
13894		goto cleanup;
13895	}
13896
13897	result = isc_task_beginexclusive(server->task);
13898	RUNTIME_CHECK(result == ISC_R_SUCCESS);
13899
13900#ifndef HAVE_LMDB
13901	/*
13902	 * Make sure we can open the configuration save file
13903	 */
13904	result = isc_stdio_open(view->new_zone_file, "a", &fp);
13905	if (result != ISC_R_SUCCESS) {
13906		isc_task_endexclusive(server->task);
13907		TCHECK(putstr(text, "unable to create '"));
13908		TCHECK(putstr(text, view->new_zone_file));
13909		TCHECK(putstr(text, "': "));
13910		TCHECK(putstr(text, isc_result_totext(result)));
13911		goto cleanup;
13912	}
13913
13914	(void)isc_stdio_close(fp);
13915	fp = NULL;
13916#else  /* HAVE_LMDB */
13917	LOCK(&view->new_zone_lock);
13918	locked = true;
13919	/* Make sure we can open the NZD database */
13920	result = nzd_writable(view);
13921	if (result != ISC_R_SUCCESS) {
13922		isc_task_endexclusive(server->task);
13923		TCHECK(putstr(text, "unable to open NZD database for '"));
13924		TCHECK(putstr(text, view->new_zone_db));
13925		TCHECK(putstr(text, "'"));
13926		result = ISC_R_FAILURE;
13927		goto cleanup;
13928	}
13929#endif /* HAVE_LMDB */
13930
13931	/* Mark view unfrozen and configure zone */
13932	dns_view_thaw(view);
13933	result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
13934				server->mctx, view, &server->viewlist,
13935				&server->kasplist, cfg->actx, true, false,
13936				false);
13937	dns_view_freeze(view);
13938
13939	isc_task_endexclusive(server->task);
13940
13941	if (result != ISC_R_SUCCESS) {
13942		TCHECK(putstr(text, "configure_zone failed: "));
13943		TCHECK(putstr(text, isc_result_totext(result)));
13944		goto cleanup;
13945	}
13946
13947	/* Is it there yet? */
13948	if (redirect) {
13949		if (view->redirect == NULL) {
13950			CHECK(ISC_R_NOTFOUND);
13951		}
13952		dns_zone_attach(view->redirect, &zone);
13953	} else {
13954		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13955		if (result != ISC_R_SUCCESS) {
13956			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13957				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13958				      "added new zone was not found: %s",
13959				      isc_result_totext(result));
13960			goto cleanup;
13961		}
13962	}
13963
13964#ifndef HAVE_LMDB
13965	/*
13966	 * If there wasn't a previous newzone config, just save the one
13967	 * we've created. If there was a previous one, merge the new
13968	 * zone into it.
13969	 */
13970	if (cfg->nzf_config == NULL) {
13971		cfg_obj_attach(zoneconf, &cfg->nzf_config);
13972	} else {
13973		cfg_obj_t *z;
13974		DE_CONST(zoneobj, z);
13975		CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z,
13976					"zone"));
13977	}
13978	cleanup_config = true;
13979#endif /* HAVE_LMDB */
13980
13981	/*
13982	 * Load the zone from the master file.  If this fails, we'll
13983	 * need to undo the configuration we've done already.
13984	 */
13985	result = dns_zone_load(zone, true);
13986	if (result != ISC_R_SUCCESS) {
13987		dns_db_t *dbp = NULL;
13988
13989		TCHECK(putstr(text, "dns_zone_loadnew failed: "));
13990		TCHECK(putstr(text, isc_result_totext(result)));
13991
13992		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13993			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13994			      "addzone failed; reverting.");
13995
13996		/* If the zone loaded partially, unload it */
13997		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13998			dns_db_detach(&dbp);
13999			dns_zone_unload(zone);
14000		}
14001
14002		/* Remove the zone from the zone table */
14003		dns_zt_unmount(view->zonetable, zone);
14004		goto cleanup;
14005	}
14006
14007	/* Flag the zone as having been added at runtime */
14008	dns_zone_setadded(zone, true);
14009
14010#ifdef HAVE_LMDB
14011	/* Save the new zone configuration into the NZD */
14012	CHECK(nzd_open(view, 0, &txn, &dbi));
14013	CHECK(nzd_save(&txn, dbi, zone, zoneobj));
14014#else  /* ifdef HAVE_LMDB */
14015	/* Append the zone configuration to the NZF */
14016	result = nzf_append(view, zoneobj);
14017#endif /* HAVE_LMDB */
14018
14019cleanup:
14020
14021#ifndef HAVE_LMDB
14022	if (fp != NULL) {
14023		(void)isc_stdio_close(fp);
14024	}
14025	if (result != ISC_R_SUCCESS && cleanup_config) {
14026		tresult = delete_zoneconf(view, cfg->add_parser,
14027					  cfg->nzf_config, name, NULL);
14028		RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
14029	}
14030#else  /* HAVE_LMDB */
14031	if (txn != NULL) {
14032		(void)nzd_close(&txn, false);
14033	}
14034	if (locked) {
14035		UNLOCK(&view->new_zone_lock);
14036	}
14037#endif /* HAVE_LMDB */
14038
14039	if (zone != NULL) {
14040		dns_zone_detach(&zone);
14041	}
14042
14043	return (result);
14044}
14045
14046static isc_result_t
14047do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
14048	   dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
14049	   bool redirect, isc_buffer_t **text) {
14050	isc_result_t result, tresult;
14051	dns_zone_t *zone = NULL;
14052	bool added;
14053	bool exclusive = false;
14054#ifndef HAVE_LMDB
14055	FILE *fp = NULL;
14056	cfg_obj_t *z;
14057#else  /* HAVE_LMDB */
14058	MDB_txn *txn = NULL;
14059	MDB_dbi dbi;
14060	bool locked = false;
14061#endif /* HAVE_LMDB */
14062
14063	/* Zone must already exist */
14064	if (redirect) {
14065		if (view->redirect != NULL) {
14066			dns_zone_attach(view->redirect, &zone);
14067			result = ISC_R_SUCCESS;
14068		} else {
14069			result = ISC_R_NOTFOUND;
14070		}
14071	} else {
14072		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
14073	}
14074	if (result != ISC_R_SUCCESS) {
14075		goto cleanup;
14076	}
14077
14078	added = dns_zone_getadded(zone);
14079	dns_zone_detach(&zone);
14080
14081#ifndef HAVE_LMDB
14082	cfg = (ns_cfgctx_t *)view->new_zone_config;
14083	if (cfg == NULL) {
14084		TCHECK(putstr(text, "new zone config is not set"));
14085		CHECK(ISC_R_FAILURE);
14086	}
14087#endif /* ifndef HAVE_LMDB */
14088
14089	result = isc_task_beginexclusive(server->task);
14090	RUNTIME_CHECK(result == ISC_R_SUCCESS);
14091	exclusive = true;
14092
14093#ifndef HAVE_LMDB
14094	/* Make sure we can open the configuration save file */
14095	result = isc_stdio_open(view->new_zone_file, "a", &fp);
14096	if (result != ISC_R_SUCCESS) {
14097		TCHECK(putstr(text, "unable to open '"));
14098		TCHECK(putstr(text, view->new_zone_file));
14099		TCHECK(putstr(text, "': "));
14100		TCHECK(putstr(text, isc_result_totext(result)));
14101		goto cleanup;
14102	}
14103	(void)isc_stdio_close(fp);
14104	fp = NULL;
14105#else  /* HAVE_LMDB */
14106	LOCK(&view->new_zone_lock);
14107	locked = true;
14108	/* Make sure we can open the NZD database */
14109	result = nzd_writable(view);
14110	if (result != ISC_R_SUCCESS) {
14111		TCHECK(putstr(text, "unable to open NZD database for '"));
14112		TCHECK(putstr(text, view->new_zone_db));
14113		TCHECK(putstr(text, "'"));
14114		result = ISC_R_FAILURE;
14115		goto cleanup;
14116	}
14117#endif /* HAVE_LMDB */
14118
14119	/* Reconfigure the zone */
14120	dns_view_thaw(view);
14121	result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
14122				server->mctx, view, &server->viewlist,
14123				&server->kasplist, cfg->actx, true, false,
14124				true);
14125	dns_view_freeze(view);
14126
14127	exclusive = false;
14128	isc_task_endexclusive(server->task);
14129
14130	if (result != ISC_R_SUCCESS) {
14131		TCHECK(putstr(text, "configure_zone failed: "));
14132		TCHECK(putstr(text, isc_result_totext(result)));
14133		goto cleanup;
14134	}
14135
14136	/* Is it there yet? */
14137	if (redirect) {
14138		if (view->redirect == NULL) {
14139			CHECK(ISC_R_NOTFOUND);
14140		}
14141		dns_zone_attach(view->redirect, &zone);
14142	} else {
14143		CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
14144	}
14145
14146#ifndef HAVE_LMDB
14147	/* Remove old zone from configuration (and NZF file if applicable) */
14148	if (added) {
14149		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
14150					 dns_zone_getorigin(zone),
14151					 nzf_writeconf);
14152		if (result != ISC_R_SUCCESS) {
14153			TCHECK(putstr(text, "former zone configuration "
14154					    "not deleted: "));
14155			TCHECK(putstr(text, isc_result_totext(result)));
14156			goto cleanup;
14157		}
14158	}
14159#endif /* HAVE_LMDB */
14160
14161	if (!added) {
14162		if (cfg->vconfig == NULL) {
14163			result = delete_zoneconf(
14164				view, cfg->conf_parser, cfg->config,
14165				dns_zone_getorigin(zone), NULL);
14166		} else {
14167			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14168								  "options");
14169			result = delete_zoneconf(
14170				view, cfg->conf_parser, voptions,
14171				dns_zone_getorigin(zone), NULL);
14172		}
14173
14174		if (result != ISC_R_SUCCESS) {
14175			TCHECK(putstr(text, "former zone configuration "
14176					    "not deleted: "));
14177			TCHECK(putstr(text, isc_result_totext(result)));
14178			goto cleanup;
14179		}
14180	}
14181
14182	/* Load the zone from the master file if it needs reloading. */
14183	result = dns_zone_load(zone, true);
14184
14185	/*
14186	 * Dynamic zones need no reloading, so we can pass this result.
14187	 */
14188	if (result == DNS_R_DYNAMIC) {
14189		result = ISC_R_SUCCESS;
14190	}
14191
14192	if (result != ISC_R_SUCCESS) {
14193		dns_db_t *dbp = NULL;
14194
14195		TCHECK(putstr(text, "failed to load zone '"));
14196		TCHECK(putstr(text, zname));
14197		TCHECK(putstr(text, "': "));
14198		TCHECK(putstr(text, isc_result_totext(result)));
14199		TCHECK(putstr(text, "\nThe zone is no longer being served. "));
14200		TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
14201		TCHECK(putstr(text, "the problem and restore service."));
14202
14203		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14204			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14205			      "modzone failed; removing zone.");
14206
14207		/* If the zone loaded partially, unload it */
14208		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14209			dns_db_detach(&dbp);
14210			dns_zone_unload(zone);
14211		}
14212
14213		/* Remove the zone from the zone table */
14214		dns_zt_unmount(view->zonetable, zone);
14215		goto cleanup;
14216	}
14217
14218#ifndef HAVE_LMDB
14219	/* Store the new zone configuration; also in NZF if applicable */
14220	DE_CONST(zoneobj, z);
14221	CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone"));
14222#endif /* HAVE_LMDB */
14223
14224	if (added) {
14225#ifdef HAVE_LMDB
14226		CHECK(nzd_open(view, 0, &txn, &dbi));
14227		CHECK(nzd_save(&txn, dbi, zone, zoneobj));
14228#else  /* ifdef HAVE_LMDB */
14229		result = nzf_append(view, zoneobj);
14230		if (result != ISC_R_SUCCESS) {
14231			TCHECK(putstr(text, "\nNew zone config not saved: "));
14232			TCHECK(putstr(text, isc_result_totext(result)));
14233			goto cleanup;
14234		}
14235#endif /* HAVE_LMDB */
14236
14237		TCHECK(putstr(text, "zone '"));
14238		TCHECK(putstr(text, zname));
14239		TCHECK(putstr(text, "' reconfigured."));
14240	} else {
14241		TCHECK(putstr(text, "zone '"));
14242		TCHECK(putstr(text, zname));
14243		TCHECK(putstr(text, "' must also be reconfigured in\n"));
14244		TCHECK(putstr(text, "named.conf to make changes permanent."));
14245	}
14246
14247cleanup:
14248	if (exclusive) {
14249		isc_task_endexclusive(server->task);
14250	}
14251
14252#ifndef HAVE_LMDB
14253	if (fp != NULL) {
14254		(void)isc_stdio_close(fp);
14255	}
14256#else  /* HAVE_LMDB */
14257	if (txn != NULL) {
14258		(void)nzd_close(&txn, false);
14259	}
14260	if (locked) {
14261		UNLOCK(&view->new_zone_lock);
14262	}
14263#endif /* HAVE_LMDB */
14264
14265	if (zone != NULL) {
14266		dns_zone_detach(&zone);
14267	}
14268
14269	return (result);
14270}
14271
14272/*
14273 * Act on an "addzone" or "modzone" command from the command channel.
14274 */
14275isc_result_t
14276named_server_changezone(named_server_t *server, char *command,
14277			isc_buffer_t **text) {
14278	isc_result_t result;
14279	bool addzone;
14280	bool redirect = false;
14281	ns_cfgctx_t *cfg = NULL;
14282	cfg_obj_t *zoneconf = NULL;
14283	const cfg_obj_t *zoneobj = NULL;
14284	const char *zonename;
14285	dns_view_t *view = NULL;
14286	isc_buffer_t buf;
14287	dns_fixedname_t fname;
14288	dns_name_t *dnsname;
14289
14290	REQUIRE(text != NULL);
14291
14292	if (strncasecmp(command, "add", 3) == 0) {
14293		addzone = true;
14294	} else {
14295		INSIST(strncasecmp(command, "mod", 3) == 0);
14296		addzone = false;
14297	}
14298
14299	CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj,
14300			    &redirect, text));
14301
14302	/* Are we accepting new zones in this view? */
14303#ifdef HAVE_LMDB
14304	if (view->new_zone_db == NULL)
14305#else  /* ifdef HAVE_LMDB */
14306	if (view->new_zone_file == NULL)
14307#endif /* HAVE_LMDB */
14308	{
14309		(void)putstr(text, "Not allowing new zones in view '");
14310		(void)putstr(text, view->name);
14311		(void)putstr(text, "'");
14312		result = ISC_R_NOPERM;
14313		goto cleanup;
14314	}
14315
14316	cfg = (ns_cfgctx_t *)view->new_zone_config;
14317	if (cfg == NULL) {
14318		result = ISC_R_FAILURE;
14319		goto cleanup;
14320	}
14321
14322	zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
14323	isc_buffer_constinit(&buf, zonename, strlen(zonename));
14324	isc_buffer_add(&buf, strlen(zonename));
14325
14326	dnsname = dns_fixedname_initname(&fname);
14327	CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL));
14328
14329	if (redirect) {
14330		if (!dns_name_equal(dnsname, dns_rootname)) {
14331			(void)putstr(text, "redirect zones must be called "
14332					   "\".\"");
14333			CHECK(ISC_R_FAILURE);
14334		}
14335	}
14336
14337	if (addzone) {
14338		CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj,
14339				 redirect, text));
14340	} else {
14341		CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj,
14342				 redirect, text));
14343	}
14344
14345	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14346		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14347		      "%s zone %s in view %s via %s",
14348		      addzone ? "added" : "updated", zonename, view->name,
14349		      addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
14350
14351	/* Changing a zone counts as reconfiguration */
14352	CHECK(isc_time_now(&named_g_configtime));
14353
14354cleanup:
14355	if (isc_buffer_usedlength(*text) > 0) {
14356		(void)putnull(text);
14357	}
14358	if (zoneconf != NULL) {
14359		cfg_obj_destroy(named_g_addparser, &zoneconf);
14360	}
14361	if (view != NULL) {
14362		dns_view_detach(&view);
14363	}
14364
14365	return (result);
14366}
14367
14368static bool
14369inuse(const char *file, bool first, isc_buffer_t **text) {
14370	if (file != NULL && isc_file_exists(file)) {
14371		if (first) {
14372			(void)putstr(text, "The following files were in use "
14373					   "and may now be removed:\n");
14374		} else {
14375			(void)putstr(text, "\n");
14376		}
14377		(void)putstr(text, file);
14378		(void)putnull(text);
14379		return (false);
14380	}
14381	return (first);
14382}
14383
14384typedef struct {
14385	dns_zone_t *zone;
14386	bool cleanup;
14387} ns_dzctx_t;
14388
14389/*
14390 * Carry out a zone deletion scheduled by named_server_delzone().
14391 */
14392static void
14393rmzone(isc_task_t *task, isc_event_t *event) {
14394	ns_dzctx_t *dz = (ns_dzctx_t *)event->ev_arg;
14395	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
14396	dns_catz_zone_t *catz = NULL;
14397	char zonename[DNS_NAME_FORMATSIZE];
14398	dns_view_t *view = NULL;
14399	ns_cfgctx_t *cfg = NULL;
14400	dns_db_t *dbp = NULL;
14401	bool added;
14402	isc_result_t result;
14403#ifdef HAVE_LMDB
14404	MDB_txn *txn = NULL;
14405	MDB_dbi dbi;
14406#endif /* ifdef HAVE_LMDB */
14407
14408	REQUIRE(dz != NULL);
14409
14410	isc_event_free(&event);
14411
14412	/* Dig out configuration for this zone */
14413	zone = dz->zone;
14414	view = dns_zone_getview(zone);
14415	cfg = (ns_cfgctx_t *)view->new_zone_config;
14416	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
14417
14418	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14419		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14420		      "deleting zone %s in view %s via delzone", zonename,
14421		      view->name);
14422
14423	/*
14424	 * Remove the zone from configuration (and NZF file if applicable)
14425	 * (If this is a catalog zone member then nzf_config can be NULL)
14426	 */
14427	added = dns_zone_getadded(zone);
14428	catz = dns_zone_get_parentcatz(zone);
14429
14430	if (added && catz == NULL && cfg != NULL) {
14431#ifdef HAVE_LMDB
14432		/* Make sure we can open the NZD database */
14433		LOCK(&view->new_zone_lock);
14434		result = nzd_open(view, 0, &txn, &dbi);
14435		if (result != ISC_R_SUCCESS) {
14436			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14437				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14438				      "unable to open NZD database for '%s'",
14439				      view->new_zone_db);
14440		} else {
14441			result = nzd_save(&txn, dbi, zone, NULL);
14442		}
14443
14444		if (result != ISC_R_SUCCESS) {
14445			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14446				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14447				      "unable to delete zone configuration: %s",
14448				      isc_result_totext(result));
14449		}
14450
14451		if (txn != NULL) {
14452			(void)nzd_close(&txn, false);
14453		}
14454		UNLOCK(&view->new_zone_lock);
14455#else  /* ifdef HAVE_LMDB */
14456		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
14457					 dns_zone_getorigin(zone),
14458					 nzf_writeconf);
14459		if (result != ISC_R_SUCCESS) {
14460			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14461				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14462				      "unable to delete zone configuration: %s",
14463				      isc_result_totext(result));
14464		}
14465#endif /* HAVE_LMDB */
14466	}
14467
14468	if (!added && cfg != NULL) {
14469		if (cfg->vconfig != NULL) {
14470			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14471								  "options");
14472			result = delete_zoneconf(
14473				view, cfg->conf_parser, voptions,
14474				dns_zone_getorigin(zone), NULL);
14475		} else {
14476			result = delete_zoneconf(
14477				view, cfg->conf_parser, cfg->config,
14478				dns_zone_getorigin(zone), NULL);
14479		}
14480		if (result != ISC_R_SUCCESS) {
14481			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14482				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14483				      "unable to delete zone configuration: %s",
14484				      isc_result_totext(result));
14485		}
14486	}
14487
14488	/* Unload zone database */
14489	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14490		dns_db_detach(&dbp);
14491		dns_zone_unload(zone);
14492	}
14493
14494	/* Clean up stub/secondary zone files if requested to do so */
14495	dns_zone_getraw(zone, &raw);
14496	mayberaw = (raw != NULL) ? raw : zone;
14497
14498	if (added && dz->cleanup) {
14499		const char *file;
14500
14501		file = dns_zone_getfile(mayberaw);
14502		result = isc_file_remove(file);
14503		if (result != ISC_R_SUCCESS) {
14504			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14505				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14506				      "file %s not removed: %s", file,
14507				      isc_result_totext(result));
14508		}
14509
14510		file = dns_zone_getjournal(mayberaw);
14511		result = isc_file_remove(file);
14512		if (result != ISC_R_SUCCESS) {
14513			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14514				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14515				      "file %s not removed: %s", file,
14516				      isc_result_totext(result));
14517		}
14518
14519		if (zone != mayberaw) {
14520			file = dns_zone_getfile(zone);
14521			result = isc_file_remove(file);
14522			if (result != ISC_R_SUCCESS) {
14523				isc_log_write(
14524					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14525					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14526					"file %s not removed: %s", file,
14527					isc_result_totext(result));
14528			}
14529
14530			file = dns_zone_getjournal(zone);
14531			result = isc_file_remove(file);
14532			if (result != ISC_R_SUCCESS) {
14533				isc_log_write(
14534					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14535					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14536					"file %s not removed: %s", file,
14537					isc_result_totext(result));
14538			}
14539		}
14540	}
14541
14542	if (raw != NULL) {
14543		dns_zone_detach(&raw);
14544	}
14545	dns_zone_detach(&zone);
14546	isc_mem_put(named_g_mctx, dz, sizeof(*dz));
14547	isc_task_detach(&task);
14548}
14549
14550/*
14551 * Act on a "delzone" command from the command channel.
14552 */
14553isc_result_t
14554named_server_delzone(named_server_t *server, isc_lex_t *lex,
14555		     isc_buffer_t **text) {
14556	isc_result_t result, tresult;
14557	dns_zone_t *zone = NULL;
14558	dns_zone_t *raw = NULL;
14559	dns_zone_t *mayberaw;
14560	dns_view_t *view = NULL;
14561	char zonename[DNS_NAME_FORMATSIZE];
14562	bool cleanup = false;
14563	const char *ptr;
14564	bool added;
14565	ns_dzctx_t *dz = NULL;
14566	isc_event_t *dzevent = NULL;
14567	isc_task_t *task = NULL;
14568
14569	REQUIRE(text != NULL);
14570
14571	/* Skip the command name. */
14572	ptr = next_token(lex, text);
14573	if (ptr == NULL) {
14574		return (ISC_R_UNEXPECTEDEND);
14575	}
14576
14577	/* Find out what we are to do. */
14578	ptr = next_token(lex, text);
14579	if (ptr == NULL) {
14580		return (ISC_R_UNEXPECTEDEND);
14581	}
14582
14583	if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) {
14584		cleanup = true;
14585		ptr = next_token(lex, text);
14586	}
14587
14588	CHECK(zone_from_args(server, lex, ptr, &zone, zonename, text, false));
14589	if (zone == NULL) {
14590		result = ISC_R_UNEXPECTEDEND;
14591		goto cleanup;
14592	}
14593
14594	INSIST(zonename != NULL);
14595
14596	/* Is this a policy zone? */
14597	if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
14598		TCHECK(putstr(text, "zone '"));
14599		TCHECK(putstr(text, zonename));
14600		TCHECK(putstr(text,
14601			      "' cannot be deleted: response-policy zone."));
14602		result = ISC_R_FAILURE;
14603		goto cleanup;
14604	}
14605
14606	view = dns_zone_getview(zone);
14607	if (dns_zone_gettype(zone) == dns_zone_redirect) {
14608		dns_zone_detach(&view->redirect);
14609	} else {
14610		CHECK(dns_zt_unmount(view->zonetable, zone));
14611	}
14612
14613	/* Send cleanup event */
14614	dz = isc_mem_get(named_g_mctx, sizeof(*dz));
14615
14616	dz->cleanup = cleanup;
14617	dz->zone = NULL;
14618	dns_zone_attach(zone, &dz->zone);
14619	dzevent = isc_event_allocate(named_g_mctx, server, NAMED_EVENT_DELZONE,
14620				     rmzone, dz, sizeof(isc_event_t));
14621
14622	dns_zone_gettask(zone, &task);
14623	isc_task_send(task, &dzevent);
14624	dz = NULL;
14625
14626	/* Inform user about cleaning up stub/secondary zone files */
14627	dns_zone_getraw(zone, &raw);
14628	mayberaw = (raw != NULL) ? raw : zone;
14629
14630	added = dns_zone_getadded(zone);
14631	if (!added) {
14632		TCHECK(putstr(text, "zone '"));
14633		TCHECK(putstr(text, zonename));
14634		TCHECK(putstr(text, "' is no longer active and will be "
14635				    "deleted.\n"));
14636		TCHECK(putstr(text, "To keep it from returning "));
14637		TCHECK(putstr(text, "when the server is restarted, it\n"));
14638		TCHECK(putstr(text, "must also be removed from named.conf."));
14639	} else if (cleanup) {
14640		TCHECK(putstr(text, "zone '"));
14641		TCHECK(putstr(text, zonename));
14642		TCHECK(putstr(text, "' and associated files will be deleted."));
14643	} else if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
14644		   dns_zone_gettype(mayberaw) == dns_zone_mirror ||
14645		   dns_zone_gettype(mayberaw) == dns_zone_stub)
14646	{
14647		bool first;
14648		const char *file;
14649
14650		TCHECK(putstr(text, "zone '"));
14651		TCHECK(putstr(text, zonename));
14652		TCHECK(putstr(text, "' will be deleted."));
14653
14654		file = dns_zone_getfile(mayberaw);
14655		first = inuse(file, true, text);
14656
14657		file = dns_zone_getjournal(mayberaw);
14658		first = inuse(file, first, text);
14659
14660		if (zone != mayberaw) {
14661			file = dns_zone_getfile(zone);
14662			first = inuse(file, first, text);
14663
14664			file = dns_zone_getjournal(zone);
14665			(void)inuse(file, first, text);
14666		}
14667	}
14668
14669	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14670		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14671		      "zone %s scheduled for removal via delzone", zonename);
14672
14673	/* Removing a zone counts as reconfiguration */
14674	CHECK(isc_time_now(&named_g_configtime));
14675
14676	result = ISC_R_SUCCESS;
14677
14678cleanup:
14679	if (isc_buffer_usedlength(*text) > 0) {
14680		(void)putnull(text);
14681	}
14682	if (raw != NULL) {
14683		dns_zone_detach(&raw);
14684	}
14685	if (zone != NULL) {
14686		dns_zone_detach(&zone);
14687	}
14688
14689	return (result);
14690}
14691
14692static const cfg_obj_t *
14693find_name_in_list_from_map(const cfg_obj_t *config,
14694			   const char *map_key_for_list, const char *name,
14695			   bool redirect) {
14696	const cfg_obj_t *list = NULL;
14697	const cfg_listelt_t *element;
14698	const cfg_obj_t *obj = NULL;
14699	dns_fixedname_t fixed1, fixed2;
14700	dns_name_t *name1 = NULL, *name2 = NULL;
14701	isc_result_t result;
14702
14703	if (strcmp(map_key_for_list, "zone") == 0) {
14704		name1 = dns_fixedname_initname(&fixed1);
14705		name2 = dns_fixedname_initname(&fixed2);
14706		result = dns_name_fromstring(name1, name, 0, NULL);
14707		RUNTIME_CHECK(result == ISC_R_SUCCESS);
14708	}
14709
14710	cfg_map_get(config, map_key_for_list, &list);
14711	for (element = cfg_list_first(list); element != NULL;
14712	     element = cfg_list_next(element))
14713	{
14714		const char *vname;
14715
14716		obj = cfg_listelt_value(element);
14717		INSIST(obj != NULL);
14718		vname = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
14719		if (vname == NULL) {
14720			obj = NULL;
14721			continue;
14722		}
14723
14724		if (name1 != NULL) {
14725			result = dns_name_fromstring(name2, vname, 0, NULL);
14726			if (result == ISC_R_SUCCESS &&
14727			    dns_name_equal(name1, name2))
14728			{
14729				const cfg_obj_t *zoptions;
14730				const cfg_obj_t *typeobj = NULL;
14731				zoptions = cfg_tuple_get(obj, "options");
14732
14733				if (zoptions != NULL) {
14734					cfg_map_get(zoptions, "type", &typeobj);
14735				}
14736				if (redirect && typeobj != NULL &&
14737				    strcasecmp(cfg_obj_asstring(typeobj),
14738					       "redirect") == 0)
14739				{
14740					break;
14741				} else if (!redirect) {
14742					break;
14743				}
14744			}
14745		} else if (strcasecmp(vname, name) == 0) {
14746			break;
14747		}
14748
14749		obj = NULL;
14750	}
14751
14752	return (obj);
14753}
14754
14755static void
14756emitzone(void *arg, const char *buf, int len) {
14757	ns_dzarg_t *dzarg = arg;
14758	isc_result_t result;
14759
14760	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
14761	result = putmem(dzarg->text, buf, len);
14762	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
14763		dzarg->result = result;
14764	}
14765}
14766
14767/*
14768 * Act on a "showzone" command from the command channel.
14769 */
14770isc_result_t
14771named_server_showzone(named_server_t *server, isc_lex_t *lex,
14772		      isc_buffer_t **text) {
14773	isc_result_t result;
14774	const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
14775	char zonename[DNS_NAME_FORMATSIZE];
14776	const cfg_obj_t *map;
14777	dns_view_t *view = NULL;
14778	dns_zone_t *zone = NULL;
14779	ns_cfgctx_t *cfg = NULL;
14780#ifdef HAVE_LMDB
14781	cfg_obj_t *nzconfig = NULL;
14782#endif /* HAVE_LMDB */
14783	bool added, redirect;
14784	ns_dzarg_t dzarg;
14785
14786	REQUIRE(text != NULL);
14787
14788	/* Parse parameters */
14789	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
14790	if (zone == NULL) {
14791		result = ISC_R_UNEXPECTEDEND;
14792		goto cleanup;
14793	}
14794
14795	redirect = dns_zone_gettype(zone) == dns_zone_redirect;
14796	added = dns_zone_getadded(zone);
14797	view = dns_zone_getview(zone);
14798	dns_zone_detach(&zone);
14799
14800	cfg = (ns_cfgctx_t *)view->new_zone_config;
14801	if (cfg == NULL) {
14802		result = ISC_R_FAILURE;
14803		goto cleanup;
14804	}
14805
14806	if (!added) {
14807		/* Find the view statement */
14808		vconfig = find_name_in_list_from_map(cfg->config, "view",
14809						     view->name, false);
14810
14811		/* Find the zone statement */
14812		if (vconfig != NULL) {
14813			map = cfg_tuple_get(vconfig, "options");
14814		} else {
14815			map = cfg->config;
14816		}
14817
14818		zconfig = find_name_in_list_from_map(map, "zone", zonename,
14819						     redirect);
14820	}
14821
14822#ifndef HAVE_LMDB
14823	if (zconfig == NULL && cfg->nzf_config != NULL) {
14824		zconfig = find_name_in_list_from_map(cfg->nzf_config, "zone",
14825						     zonename, redirect);
14826	}
14827#else  /* HAVE_LMDB */
14828	if (zconfig == NULL) {
14829		const cfg_obj_t *zlist = NULL;
14830		CHECK(get_newzone_config(view, zonename, &nzconfig));
14831		CHECK(cfg_map_get(nzconfig, "zone", &zlist));
14832		if (!cfg_obj_islist(zlist)) {
14833			CHECK(ISC_R_FAILURE);
14834		}
14835
14836		zconfig = cfg_listelt_value(cfg_list_first(zlist));
14837	}
14838#endif /* HAVE_LMDB */
14839
14840	if (zconfig == NULL) {
14841		CHECK(ISC_R_NOTFOUND);
14842	}
14843
14844	CHECK(putstr(text, "zone "));
14845	dzarg.magic = DZARG_MAGIC;
14846	dzarg.text = text;
14847	dzarg.result = ISC_R_SUCCESS;
14848	cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
14849	CHECK(dzarg.result);
14850
14851	CHECK(putstr(text, ";"));
14852
14853	result = ISC_R_SUCCESS;
14854
14855cleanup:
14856#ifdef HAVE_LMDB
14857	if (nzconfig != NULL) {
14858		cfg_obj_destroy(named_g_addparser, &nzconfig);
14859	}
14860#endif /* HAVE_LMDB */
14861	if (isc_buffer_usedlength(*text) > 0) {
14862		(void)putnull(text);
14863	}
14864
14865	return (result);
14866}
14867
14868static void
14869newzone_cfgctx_destroy(void **cfgp) {
14870	ns_cfgctx_t *cfg;
14871
14872	REQUIRE(cfgp != NULL && *cfgp != NULL);
14873
14874	cfg = *cfgp;
14875
14876	if (cfg->conf_parser != NULL) {
14877		if (cfg->config != NULL) {
14878			cfg_obj_destroy(cfg->conf_parser, &cfg->config);
14879		}
14880		if (cfg->vconfig != NULL) {
14881			cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
14882		}
14883		cfg_parser_destroy(&cfg->conf_parser);
14884	}
14885	if (cfg->add_parser != NULL) {
14886		if (cfg->nzf_config != NULL) {
14887			cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
14888		}
14889		cfg_parser_destroy(&cfg->add_parser);
14890	}
14891
14892	if (cfg->actx != NULL) {
14893		cfg_aclconfctx_detach(&cfg->actx);
14894	}
14895
14896	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
14897	*cfgp = NULL;
14898}
14899
14900isc_result_t
14901named_server_signing(named_server_t *server, isc_lex_t *lex,
14902		     isc_buffer_t **text) {
14903	isc_result_t result = ISC_R_SUCCESS;
14904	dns_zone_t *zone = NULL;
14905	dns_name_t *origin;
14906	dns_db_t *db = NULL;
14907	dns_dbnode_t *node = NULL;
14908	dns_dbversion_t *version = NULL;
14909	dns_rdatatype_t privatetype;
14910	dns_rdataset_t privset;
14911	bool first = true;
14912	bool list = false, clear = false;
14913	bool chain = false;
14914	bool setserial = false;
14915	bool resalt = false;
14916	uint32_t serial = 0;
14917	char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
14918	unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
14919	unsigned char salt[255];
14920	const char *ptr;
14921	size_t n;
14922
14923	REQUIRE(text != NULL);
14924
14925	dns_rdataset_init(&privset);
14926
14927	/* Skip the command name. */
14928	ptr = next_token(lex, text);
14929	if (ptr == NULL) {
14930		return (ISC_R_UNEXPECTEDEND);
14931	}
14932
14933	/* Find out what we are to do. */
14934	ptr = next_token(lex, text);
14935	if (ptr == NULL) {
14936		return (ISC_R_UNEXPECTEDEND);
14937	}
14938
14939	if (strcasecmp(ptr, "-list") == 0) {
14940		list = true;
14941	} else if ((strcasecmp(ptr, "-clear") == 0) ||
14942		   (strcasecmp(ptr, "-clean") == 0))
14943	{
14944		clear = true;
14945		ptr = next_token(lex, text);
14946		if (ptr == NULL) {
14947			return (ISC_R_UNEXPECTEDEND);
14948		}
14949		strlcpy(keystr, ptr, sizeof(keystr));
14950	} else if (strcasecmp(ptr, "-nsec3param") == 0) {
14951		char hashbuf[64], flagbuf[64], iterbuf[64];
14952		char nbuf[256];
14953
14954		chain = true;
14955		ptr = next_token(lex, text);
14956		if (ptr == NULL) {
14957			return (ISC_R_UNEXPECTEDEND);
14958		}
14959
14960		if (strcasecmp(ptr, "none") == 0) {
14961			hash = 0;
14962		} else {
14963			strlcpy(hashbuf, ptr, sizeof(hashbuf));
14964
14965			ptr = next_token(lex, text);
14966			if (ptr == NULL) {
14967				return (ISC_R_UNEXPECTEDEND);
14968			}
14969			strlcpy(flagbuf, ptr, sizeof(flagbuf));
14970
14971			ptr = next_token(lex, text);
14972			if (ptr == NULL) {
14973				return (ISC_R_UNEXPECTEDEND);
14974			}
14975			strlcpy(iterbuf, ptr, sizeof(iterbuf));
14976			n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", hashbuf,
14977				     flagbuf, iterbuf);
14978			if (n == sizeof(nbuf)) {
14979				return (ISC_R_NOSPACE);
14980			}
14981			n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
14982			if (n != 3U) {
14983				return (ISC_R_BADNUMBER);
14984			}
14985
14986			if (hash > 0xffU || flags > 0xffU ||
14987			    iter > dns_nsec3_maxiterations())
14988			{
14989				return (ISC_R_RANGE);
14990			}
14991
14992			ptr = next_token(lex, text);
14993			if (ptr == NULL) {
14994				return (ISC_R_UNEXPECTEDEND);
14995			} else if (strcasecmp(ptr, "auto") == 0) {
14996				/* Auto-generate a random salt.
14997				 * XXXMUKS: This currently uses the
14998				 * minimum recommended length by RFC
14999				 * 5155 (64 bits). It should be made
15000				 * configurable.
15001				 */
15002				saltlen = 8;
15003				resalt = true;
15004			} else if (strcmp(ptr, "-") != 0) {
15005				isc_buffer_t buf;
15006
15007				isc_buffer_init(&buf, salt, sizeof(salt));
15008				CHECK(isc_hex_decodestring(ptr, &buf));
15009				saltlen = isc_buffer_usedlength(&buf);
15010			}
15011		}
15012	} else if (strcasecmp(ptr, "-serial") == 0) {
15013		ptr = next_token(lex, text);
15014		if (ptr == NULL) {
15015			return (ISC_R_UNEXPECTEDEND);
15016		}
15017		CHECK(isc_parse_uint32(&serial, ptr, 10));
15018		setserial = true;
15019	} else {
15020		CHECK(DNS_R_SYNTAX);
15021	}
15022
15023	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
15024	if (zone == NULL) {
15025		CHECK(ISC_R_UNEXPECTEDEND);
15026	}
15027
15028	if (dns_zone_getkasp(zone) != NULL) {
15029		(void)putstr(text, "zone uses dnssec-policy, use rndc dnssec "
15030				   "command instead");
15031		(void)putnull(text);
15032		goto cleanup;
15033	}
15034
15035	if (clear) {
15036		CHECK(dns_zone_keydone(zone, keystr));
15037		(void)putstr(text, "request queued");
15038		(void)putnull(text);
15039	} else if (chain) {
15040		CHECK(dns_zone_setnsec3param(
15041			zone, (uint8_t)hash, (uint8_t)flags, iter,
15042			(uint8_t)saltlen, salt, true, resalt));
15043		(void)putstr(text, "nsec3param request queued");
15044		(void)putnull(text);
15045	} else if (setserial) {
15046		CHECK(dns_zone_setserial(zone, serial));
15047		(void)putstr(text, "serial request queued");
15048		(void)putnull(text);
15049	} else if (list) {
15050		privatetype = dns_zone_getprivatetype(zone);
15051		origin = dns_zone_getorigin(zone);
15052		CHECK(dns_zone_getdb(zone, &db));
15053		CHECK(dns_db_findnode(db, origin, false, &node));
15054		dns_db_currentversion(db, &version);
15055
15056		result = dns_db_findrdataset(db, node, version, privatetype,
15057					     dns_rdatatype_none, 0, &privset,
15058					     NULL);
15059		if (result == ISC_R_NOTFOUND) {
15060			(void)putstr(text, "No signing records found");
15061			(void)putnull(text);
15062			result = ISC_R_SUCCESS;
15063			goto cleanup;
15064		}
15065
15066		for (result = dns_rdataset_first(&privset);
15067		     result == ISC_R_SUCCESS;
15068		     result = dns_rdataset_next(&privset))
15069		{
15070			dns_rdata_t priv = DNS_RDATA_INIT;
15071			/*
15072			 * In theory, the output buffer could hold a full RDATA
15073			 * record which is 16-bit and then some text around
15074			 * it
15075			 */
15076			char output[UINT16_MAX + BUFSIZ];
15077			isc_buffer_t buf;
15078
15079			dns_rdataset_current(&privset, &priv);
15080
15081			isc_buffer_init(&buf, output, sizeof(output));
15082			CHECK(dns_private_totext(&priv, &buf));
15083			if (!first) {
15084				CHECK(putstr(text, "\n"));
15085			}
15086			CHECK(putstr(text, output));
15087			first = false;
15088		}
15089		if (!first) {
15090			CHECK(putnull(text));
15091		}
15092
15093		if (result == ISC_R_NOMORE) {
15094			result = ISC_R_SUCCESS;
15095		}
15096	}
15097
15098cleanup:
15099	if (dns_rdataset_isassociated(&privset)) {
15100		dns_rdataset_disassociate(&privset);
15101	}
15102	if (node != NULL) {
15103		dns_db_detachnode(db, &node);
15104	}
15105	if (version != NULL) {
15106		dns_db_closeversion(db, &version, false);
15107	}
15108	if (db != NULL) {
15109		dns_db_detach(&db);
15110	}
15111	if (zone != NULL) {
15112		dns_zone_detach(&zone);
15113	}
15114
15115	return (result);
15116}
15117
15118static bool
15119argcheck(char *cmd, const char *full) {
15120	size_t l;
15121
15122	if (cmd == NULL || cmd[0] != '-') {
15123		return (false);
15124	}
15125
15126	cmd++;
15127	l = strlen(cmd);
15128	if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
15129		return (false);
15130	}
15131
15132	return (true);
15133}
15134
15135isc_result_t
15136named_server_dnssec(named_server_t *server, isc_lex_t *lex,
15137		    isc_buffer_t **text) {
15138	isc_result_t result = ISC_R_SUCCESS;
15139	dns_zone_t *zone = NULL;
15140	dns_kasp_t *kasp = NULL;
15141	dns_dnsseckeylist_t keys;
15142	dns_dnsseckey_t *key;
15143	char *ptr, *zonetext = NULL;
15144	const char *msg = NULL;
15145	/* variables for -checkds */
15146	bool checkds = false, dspublish = false;
15147	/* variables for -rollover */
15148	bool rollover = false;
15149	/* variables for -key */
15150	bool use_keyid = false;
15151	dns_keytag_t keyid = 0;
15152	uint8_t algorithm = 0;
15153	/* variables for -status */
15154	bool status = false;
15155	char output[4096];
15156	isc_stdtime_t now, when;
15157	isc_time_t timenow, timewhen;
15158	const char *dir;
15159	dns_db_t *db = NULL;
15160	dns_dbversion_t *version = NULL;
15161
15162	REQUIRE(text != NULL);
15163
15164	/* Skip the command name. */
15165	ptr = next_token(lex, text);
15166	if (ptr == NULL) {
15167		return (ISC_R_UNEXPECTEDEND);
15168	}
15169
15170	/* Find out what we are to do. */
15171	ptr = next_token(lex, text);
15172	if (ptr == NULL) {
15173		return (ISC_R_UNEXPECTEDEND);
15174	}
15175
15176	/* Initialize current time and key list. */
15177	TIME_NOW(&timenow);
15178	now = isc_time_seconds(&timenow);
15179	when = now;
15180
15181	ISC_LIST_INIT(keys);
15182
15183	if (strcasecmp(ptr, "-status") == 0) {
15184		status = true;
15185	} else if (strcasecmp(ptr, "-rollover") == 0) {
15186		rollover = true;
15187	} else if (strcasecmp(ptr, "-checkds") == 0) {
15188		checkds = true;
15189	} else {
15190		CHECK(DNS_R_SYNTAX);
15191	}
15192
15193	if (rollover || checkds) {
15194		/* Check for options */
15195		for (;;) {
15196			ptr = next_token(lex, text);
15197			if (ptr == NULL) {
15198				msg = "Bad format";
15199				CHECK(ISC_R_UNEXPECTEDEND);
15200			} else if (argcheck(ptr, "alg")) {
15201				isc_consttextregion_t alg;
15202				ptr = next_token(lex, text);
15203				if (ptr == NULL) {
15204					msg = "No key algorithm specified";
15205					CHECK(ISC_R_UNEXPECTEDEND);
15206				}
15207				alg.base = ptr;
15208				alg.length = strlen(alg.base);
15209				result = dns_secalg_fromtext(
15210					&algorithm, (isc_textregion_t *)&alg);
15211				if (result != ISC_R_SUCCESS) {
15212					msg = "Bad algorithm";
15213					CHECK(DNS_R_SYNTAX);
15214				}
15215				continue;
15216			} else if (argcheck(ptr, "key")) {
15217				uint16_t id;
15218				ptr = next_token(lex, text);
15219				if (ptr == NULL) {
15220					msg = "No key identifier specified";
15221					CHECK(ISC_R_UNEXPECTEDEND);
15222				}
15223				CHECK(isc_parse_uint16(&id, ptr, 10));
15224				keyid = (dns_keytag_t)id;
15225				use_keyid = true;
15226				continue;
15227			} else if (argcheck(ptr, "when")) {
15228				uint32_t tw;
15229				ptr = next_token(lex, text);
15230				if (ptr == NULL) {
15231					msg = "No time specified";
15232					CHECK(ISC_R_UNEXPECTEDEND);
15233				}
15234				CHECK(dns_time32_fromtext(ptr, &tw));
15235				when = (isc_stdtime_t)tw;
15236				continue;
15237			} else if (ptr[0] == '-') {
15238				msg = "Unknown option";
15239				CHECK(DNS_R_SYNTAX);
15240			} else if (checkds) {
15241				/*
15242				 * No arguments provided, so we must be
15243				 * parsing "published|withdrawn".
15244				 */
15245				if (strcasecmp(ptr, "published") == 0) {
15246					dspublish = true;
15247				} else if (strcasecmp(ptr, "withdrawn") != 0) {
15248					CHECK(DNS_R_SYNTAX);
15249				}
15250			} else if (rollover) {
15251				/*
15252				 * No arguments provided, so we must be
15253				 * parsing the zone.
15254				 */
15255				zonetext = ptr;
15256			}
15257			break;
15258		}
15259
15260		if (rollover && !use_keyid) {
15261			msg = "Key id is required when scheduling rollover";
15262			CHECK(DNS_R_SYNTAX);
15263		}
15264
15265		if (algorithm > 0 && !use_keyid) {
15266			msg = "Key id is required when setting algorithm";
15267			CHECK(DNS_R_SYNTAX);
15268		}
15269	}
15270
15271	/* Get zone. */
15272	CHECK(zone_from_args(server, lex, zonetext, &zone, NULL, text, false));
15273	if (zone == NULL) {
15274		msg = "Zone not found";
15275		CHECK(ISC_R_UNEXPECTEDEND);
15276	}
15277
15278	/* Trailing garbage? */
15279	ptr = next_token(lex, text);
15280	if (ptr != NULL) {
15281		msg = "Too many arguments";
15282		CHECK(DNS_R_SYNTAX);
15283	}
15284
15285	/* Get dnssec-policy. */
15286	kasp = dns_zone_getkasp(zone);
15287	if (kasp == NULL) {
15288		msg = "Zone does not have dnssec-policy";
15289		goto cleanup;
15290	}
15291
15292	/* Get DNSSEC keys. */
15293	dir = dns_zone_getkeydirectory(zone);
15294	CHECK(dns_zone_getdb(zone, &db));
15295	dns_db_currentversion(db, &version);
15296	LOCK(&kasp->lock);
15297	result = dns_zone_getdnsseckeys(zone, db, version, now, &keys);
15298	UNLOCK(&kasp->lock);
15299	if (result != ISC_R_SUCCESS) {
15300		if (result != ISC_R_NOTFOUND) {
15301			goto cleanup;
15302		}
15303	}
15304
15305	if (status) {
15306		/*
15307		 * Output the DNSSEC status of the key and signing policy.
15308		 */
15309		LOCK(&kasp->lock);
15310		dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
15311		UNLOCK(&kasp->lock);
15312		CHECK(putstr(text, output));
15313	} else if (checkds) {
15314		/*
15315		 * Mark DS record has been seen, so it may move to the
15316		 * rumoured state.
15317		 */
15318		char whenbuf[80];
15319		isc_time_set(&timewhen, when, 0);
15320		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
15321		isc_result_t ret;
15322
15323		LOCK(&kasp->lock);
15324		if (use_keyid) {
15325			result = dns_keymgr_checkds_id(kasp, &keys, dir, now,
15326						       when, dspublish, keyid,
15327						       (unsigned int)algorithm);
15328		} else {
15329			result = dns_keymgr_checkds(kasp, &keys, dir, now, when,
15330						    dspublish);
15331		}
15332		UNLOCK(&kasp->lock);
15333
15334		switch (result) {
15335		case ISC_R_SUCCESS:
15336			/*
15337			 * Rekey after checkds command because the next key
15338			 * event may have changed.
15339			 */
15340			dns_zone_rekey(zone, false);
15341
15342			if (use_keyid) {
15343				char tagbuf[6];
15344				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
15345				CHECK(putstr(text, "KSK "));
15346				CHECK(putstr(text, tagbuf));
15347				CHECK(putstr(text, ": "));
15348			}
15349			CHECK(putstr(text, "Marked DS as "));
15350			if (dspublish) {
15351				CHECK(putstr(text, "published "));
15352			} else {
15353				CHECK(putstr(text, "withdrawn "));
15354			}
15355			CHECK(putstr(text, "since "));
15356			CHECK(putstr(text, whenbuf));
15357			break;
15358		case DNS_R_TOOMANYKEYS:
15359			CHECK(putstr(text,
15360				     "Error: multiple possible keys found, "
15361				     "retry command with -key id"));
15362			break;
15363		default:
15364			ret = result;
15365			CHECK(putstr(text,
15366				     "Error executing checkds command: "));
15367			CHECK(putstr(text, isc_result_totext(ret)));
15368			break;
15369		}
15370	} else if (rollover) {
15371		/*
15372		 * Manually rollover a key.
15373		 */
15374		char whenbuf[80];
15375		isc_time_set(&timewhen, when, 0);
15376		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
15377		isc_result_t ret;
15378
15379		LOCK(&kasp->lock);
15380		result = dns_keymgr_rollover(kasp, &keys, dir, now, when, keyid,
15381					     (unsigned int)algorithm);
15382		UNLOCK(&kasp->lock);
15383
15384		switch (result) {
15385		case ISC_R_SUCCESS:
15386			/*
15387			 * Rekey after rollover command because the next key
15388			 * event may have changed.
15389			 */
15390			dns_zone_rekey(zone, false);
15391
15392			if (use_keyid) {
15393				char tagbuf[6];
15394				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
15395				CHECK(putstr(text, "Key "));
15396				CHECK(putstr(text, tagbuf));
15397				CHECK(putstr(text, ": "));
15398			}
15399			CHECK(putstr(text, "Rollover scheduled on "));
15400			CHECK(putstr(text, whenbuf));
15401			break;
15402		case DNS_R_TOOMANYKEYS:
15403			CHECK(putstr(text,
15404				     "Error: multiple possible keys found, "
15405				     "retry command with -alg algorithm"));
15406			break;
15407		default:
15408			ret = result;
15409			CHECK(putstr(text,
15410				     "Error executing rollover command: "));
15411			CHECK(putstr(text, isc_result_totext(ret)));
15412			break;
15413		}
15414	}
15415	CHECK(putnull(text));
15416
15417cleanup:
15418	if (msg != NULL) {
15419		(void)putstr(text, msg);
15420		(void)putnull(text);
15421	}
15422
15423	if (version != NULL) {
15424		dns_db_closeversion(db, &version, false);
15425	}
15426	if (db != NULL) {
15427		dns_db_detach(&db);
15428	}
15429
15430	while (!ISC_LIST_EMPTY(keys)) {
15431		key = ISC_LIST_HEAD(keys);
15432		ISC_LIST_UNLINK(keys, key, link);
15433		dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
15434	}
15435
15436	if (zone != NULL) {
15437		dns_zone_detach(&zone);
15438	}
15439
15440	return (result);
15441}
15442
15443static isc_result_t
15444putmem(isc_buffer_t **b, const char *str, size_t len) {
15445	isc_result_t result;
15446
15447	result = isc_buffer_reserve(b, (unsigned int)len);
15448	if (result != ISC_R_SUCCESS) {
15449		return (ISC_R_NOSPACE);
15450	}
15451
15452	isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
15453	return (ISC_R_SUCCESS);
15454}
15455
15456static isc_result_t
15457putstr(isc_buffer_t **b, const char *str) {
15458	return (putmem(b, str, strlen(str)));
15459}
15460
15461static isc_result_t
15462putuint8(isc_buffer_t **b, uint8_t val) {
15463	isc_result_t result;
15464
15465	result = isc_buffer_reserve(b, 1);
15466	if (result != ISC_R_SUCCESS) {
15467		return (ISC_R_NOSPACE);
15468	}
15469
15470	isc_buffer_putuint8(*b, val);
15471	return (ISC_R_SUCCESS);
15472}
15473
15474static isc_result_t
15475putnull(isc_buffer_t **b) {
15476	return (putuint8(b, 0));
15477}
15478
15479isc_result_t
15480named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
15481			isc_buffer_t **text) {
15482	isc_result_t result = ISC_R_SUCCESS;
15483	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
15484	const char *type, *file;
15485	char zonename[DNS_NAME_FORMATSIZE];
15486	uint32_t serial, signed_serial, nodes;
15487	char serbuf[16], sserbuf[16], nodebuf[16];
15488	char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2];
15489	char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15490	char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15491	char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15492	char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15493	char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15494	isc_time_t loadtime, expiretime, refreshtime;
15495	isc_time_t refreshkeytime, resigntime;
15496	dns_zonetype_t zonetype;
15497	bool dynamic = false, frozen = false;
15498	bool hasraw = false;
15499	bool secure, maintain, allow;
15500	dns_db_t *db = NULL, *rawdb = NULL;
15501	char **incfiles = NULL;
15502	int nfiles = 0;
15503
15504	REQUIRE(text != NULL);
15505
15506	isc_time_settoepoch(&loadtime);
15507	isc_time_settoepoch(&refreshtime);
15508	isc_time_settoepoch(&expiretime);
15509	isc_time_settoepoch(&refreshkeytime);
15510	isc_time_settoepoch(&resigntime);
15511
15512	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
15513	if (zone == NULL) {
15514		result = ISC_R_UNEXPECTEDEND;
15515		goto cleanup;
15516	}
15517
15518	/* Inline signing? */
15519	CHECK(dns_zone_getdb(zone, &db));
15520	dns_zone_getraw(zone, &raw);
15521	hasraw = (raw != NULL);
15522	if (hasraw) {
15523		mayberaw = raw;
15524		zonetype = dns_zone_gettype(raw);
15525		CHECK(dns_zone_getdb(raw, &rawdb));
15526	} else {
15527		mayberaw = zone;
15528		zonetype = dns_zone_gettype(zone);
15529	}
15530
15531	type = dns_zonetype_name(zonetype);
15532
15533	/* Serial number */
15534	result = dns_zone_getserial(mayberaw, &serial);
15535
15536	/* This is to mirror old behavior with dns_zone_getserial */
15537	if (result != ISC_R_SUCCESS) {
15538		serial = 0;
15539	}
15540
15541	snprintf(serbuf, sizeof(serbuf), "%u", serial);
15542	if (hasraw) {
15543		result = dns_zone_getserial(zone, &signed_serial);
15544		if (result != ISC_R_SUCCESS) {
15545			serial = 0;
15546		}
15547		snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial);
15548	}
15549
15550	/* Database node count */
15551	nodes = dns_db_nodecount(hasraw ? rawdb : db, dns_dbtree_main);
15552	snprintf(nodebuf, sizeof(nodebuf), "%u", nodes);
15553
15554	/* Security */
15555	secure = dns_db_issecure(db);
15556	allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
15557	maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
15558
15559	/* Master files */
15560	file = dns_zone_getfile(mayberaw);
15561	nfiles = dns_zone_getincludes(mayberaw, &incfiles);
15562
15563	/* Load time */
15564	dns_zone_getloadtime(zone, &loadtime);
15565	isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
15566
15567	/* Refresh/expire times */
15568	if (zonetype == dns_zone_secondary || zonetype == dns_zone_mirror ||
15569	    zonetype == dns_zone_stub || zonetype == dns_zone_redirect)
15570	{
15571		dns_zone_getexpiretime(mayberaw, &expiretime);
15572		isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
15573		dns_zone_getrefreshtime(mayberaw, &refreshtime);
15574		isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
15575	}
15576
15577	/* Key refresh time */
15578	if (zonetype == dns_zone_primary ||
15579	    (zonetype == dns_zone_secondary && hasraw))
15580	{
15581		dns_zone_getrefreshkeytime(zone, &refreshkeytime);
15582		isc_time_formathttptimestamp(&refreshkeytime, kbuf,
15583					     sizeof(kbuf));
15584	}
15585
15586	/* Dynamic? */
15587	if (zonetype == dns_zone_primary) {
15588		dynamic = dns_zone_isdynamic(mayberaw, true);
15589		frozen = dynamic && !dns_zone_isdynamic(mayberaw, false);
15590	}
15591
15592	/* Next resign event */
15593	if (secure &&
15594	    (zonetype == dns_zone_primary ||
15595	     (zonetype == dns_zone_secondary && hasraw)) &&
15596	    ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0))
15597	{
15598		dns_name_t *name;
15599		dns_fixedname_t fixed;
15600		dns_rdataset_t next;
15601
15602		dns_rdataset_init(&next);
15603		name = dns_fixedname_initname(&fixed);
15604
15605		result = dns_db_getsigningtime(db, &next, name);
15606		if (result == ISC_R_SUCCESS) {
15607			isc_stdtime_t timenow;
15608			char namebuf[DNS_NAME_FORMATSIZE];
15609			char typebuf[DNS_RDATATYPE_FORMATSIZE];
15610
15611			isc_stdtime_get(&timenow);
15612			dns_name_format(name, namebuf, sizeof(namebuf));
15613			dns_rdatatype_format(next.covers, typebuf,
15614					     sizeof(typebuf));
15615			snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf,
15616				 typebuf);
15617			isc_time_set(
15618				&resigntime,
15619				next.resign -
15620					dns_zone_getsigresigninginterval(zone),
15621				0);
15622			isc_time_formathttptimestamp(&resigntime, rtbuf,
15623						     sizeof(rtbuf));
15624			dns_rdataset_disassociate(&next);
15625		}
15626	}
15627
15628	/* Create text */
15629	CHECK(putstr(text, "name: "));
15630	CHECK(putstr(text, zonename));
15631
15632	CHECK(putstr(text, "\ntype: "));
15633	CHECK(putstr(text, type));
15634
15635	if (file != NULL) {
15636		int i;
15637		CHECK(putstr(text, "\nfiles: "));
15638		CHECK(putstr(text, file));
15639		for (i = 0; i < nfiles; i++) {
15640			CHECK(putstr(text, ", "));
15641			if (incfiles[i] != NULL) {
15642				CHECK(putstr(text, incfiles[i]));
15643			}
15644		}
15645	}
15646
15647	CHECK(putstr(text, "\nserial: "));
15648	CHECK(putstr(text, serbuf));
15649	if (hasraw) {
15650		CHECK(putstr(text, "\nsigned serial: "));
15651		CHECK(putstr(text, sserbuf));
15652	}
15653
15654	CHECK(putstr(text, "\nnodes: "));
15655	CHECK(putstr(text, nodebuf));
15656
15657	if (!isc_time_isepoch(&loadtime)) {
15658		CHECK(putstr(text, "\nlast loaded: "));
15659		CHECK(putstr(text, lbuf));
15660	}
15661
15662	if (!isc_time_isepoch(&refreshtime)) {
15663		CHECK(putstr(text, "\nnext refresh: "));
15664		CHECK(putstr(text, rbuf));
15665	}
15666
15667	if (!isc_time_isepoch(&expiretime)) {
15668		CHECK(putstr(text, "\nexpires: "));
15669		CHECK(putstr(text, xbuf));
15670	}
15671
15672	if (secure) {
15673		CHECK(putstr(text, "\nsecure: yes"));
15674		if (hasraw) {
15675			CHECK(putstr(text, "\ninline signing: yes"));
15676		} else {
15677			CHECK(putstr(text, "\ninline signing: no"));
15678		}
15679	} else {
15680		CHECK(putstr(text, "\nsecure: no"));
15681	}
15682
15683	if (maintain) {
15684		CHECK(putstr(text, "\nkey maintenance: automatic"));
15685		if (!isc_time_isepoch(&refreshkeytime)) {
15686			CHECK(putstr(text, "\nnext key event: "));
15687			CHECK(putstr(text, kbuf));
15688		}
15689	} else if (allow) {
15690		CHECK(putstr(text, "\nkey maintenance: on command"));
15691	} else if (secure || hasraw) {
15692		CHECK(putstr(text, "\nkey maintenance: none"));
15693	}
15694
15695	if (!isc_time_isepoch(&resigntime)) {
15696		CHECK(putstr(text, "\nnext resign node: "));
15697		CHECK(putstr(text, resignbuf));
15698		CHECK(putstr(text, "\nnext resign time: "));
15699		CHECK(putstr(text, rtbuf));
15700	}
15701
15702	if (dynamic) {
15703		CHECK(putstr(text, "\ndynamic: yes"));
15704		if (frozen) {
15705			CHECK(putstr(text, "\nfrozen: yes"));
15706		} else {
15707			CHECK(putstr(text, "\nfrozen: no"));
15708		}
15709	} else {
15710		CHECK(putstr(text, "\ndynamic: no"));
15711	}
15712
15713	CHECK(putstr(text, "\nreconfigurable via modzone: "));
15714	CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
15715
15716cleanup:
15717	/* Indicate truncated output if possible. */
15718	if (result == ISC_R_NOSPACE) {
15719		(void)putstr(text, "\n...");
15720	}
15721	if ((result == ISC_R_SUCCESS || result == ISC_R_NOSPACE)) {
15722		(void)putnull(text);
15723	}
15724
15725	if (db != NULL) {
15726		dns_db_detach(&db);
15727	}
15728	if (rawdb != NULL) {
15729		dns_db_detach(&rawdb);
15730	}
15731	if (incfiles != NULL && mayberaw != NULL) {
15732		int i;
15733		isc_mem_t *mctx = dns_zone_getmctx(mayberaw);
15734
15735		for (i = 0; i < nfiles; i++) {
15736			if (incfiles[i] != NULL) {
15737				isc_mem_free(mctx, incfiles[i]);
15738			}
15739		}
15740		isc_mem_free(mctx, incfiles);
15741	}
15742	if (raw != NULL) {
15743		dns_zone_detach(&raw);
15744	}
15745	if (zone != NULL) {
15746		dns_zone_detach(&zone);
15747	}
15748	return (result);
15749}
15750
15751isc_result_t
15752named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
15753		 isc_buffer_t **text) {
15754	dns_view_t *view;
15755	dns_ntatable_t *ntatable = NULL;
15756	isc_result_t result = ISC_R_SUCCESS;
15757	char *ptr, *nametext = NULL, *viewname;
15758	char namebuf[DNS_NAME_FORMATSIZE];
15759	char viewbuf[DNS_NAME_FORMATSIZE];
15760	isc_stdtime_t now, when;
15761	isc_time_t t;
15762	char tbuf[64];
15763	const char *msg = NULL;
15764	bool dump = false, force = false;
15765	dns_fixedname_t fn;
15766	const dns_name_t *ntaname;
15767	dns_name_t *fname;
15768	dns_ttl_t ntattl;
15769	bool ttlset = false, excl = false, viewfound = false;
15770	dns_rdataclass_t rdclass = dns_rdataclass_in;
15771	bool first = true;
15772
15773	REQUIRE(text != NULL);
15774
15775	UNUSED(force);
15776
15777	fname = dns_fixedname_initname(&fn);
15778
15779	/* Skip the command name. */
15780	ptr = next_token(lex, text);
15781	if (ptr == NULL) {
15782		return (ISC_R_UNEXPECTEDEND);
15783	}
15784
15785	for (;;) {
15786		/* Check for options */
15787		ptr = next_token(lex, text);
15788		if (ptr == NULL) {
15789			return (ISC_R_UNEXPECTEDEND);
15790		}
15791
15792		if (strcmp(ptr, "--") == 0) {
15793			break;
15794		} else if (argcheck(ptr, "dump")) {
15795			dump = true;
15796		} else if (argcheck(ptr, "remove")) {
15797			ntattl = 0;
15798			ttlset = true;
15799		} else if (argcheck(ptr, "force")) {
15800			force = true;
15801			continue;
15802		} else if (argcheck(ptr, "lifetime")) {
15803			isc_textregion_t tr;
15804
15805			ptr = next_token(lex, text);
15806			if (ptr == NULL) {
15807				msg = "No lifetime specified";
15808				CHECK(ISC_R_UNEXPECTEDEND);
15809			}
15810
15811			tr.base = ptr;
15812			tr.length = strlen(ptr);
15813			result = dns_ttl_fromtext(&tr, &ntattl);
15814			if (result != ISC_R_SUCCESS) {
15815				msg = "could not parse NTA lifetime";
15816				CHECK(result);
15817			}
15818
15819			if (ntattl > 604800) {
15820				msg = "NTA lifetime cannot exceed one week";
15821				CHECK(ISC_R_RANGE);
15822			}
15823
15824			ttlset = true;
15825			continue;
15826		} else if (argcheck(ptr, "class")) {
15827			isc_textregion_t tr;
15828
15829			ptr = next_token(lex, text);
15830			if (ptr == NULL) {
15831				msg = "No class specified";
15832				CHECK(ISC_R_UNEXPECTEDEND);
15833			}
15834
15835			tr.base = ptr;
15836			tr.length = strlen(ptr);
15837			CHECK(dns_rdataclass_fromtext(&rdclass, &tr));
15838			continue;
15839		} else if (ptr[0] == '-') {
15840			msg = "Unknown option";
15841			CHECK(DNS_R_SYNTAX);
15842		} else {
15843			nametext = ptr;
15844		}
15845
15846		break;
15847	}
15848
15849	/*
15850	 * If -dump was specified, list NTA's and return
15851	 */
15852	if (dump) {
15853		size_t last = 0;
15854
15855		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15856		     view = ISC_LIST_NEXT(view, link))
15857		{
15858			if (ntatable != NULL) {
15859				dns_ntatable_detach(&ntatable);
15860			}
15861			result = dns_view_getntatable(view, &ntatable);
15862			if (result == ISC_R_NOTFOUND) {
15863				continue;
15864			}
15865
15866			if (last != isc_buffer_usedlength(*text)) {
15867				CHECK(putstr(text, "\n"));
15868			}
15869
15870			last = isc_buffer_usedlength(*text);
15871
15872			CHECK(dns_ntatable_totext(ntatable, view->name, text));
15873		}
15874		CHECK(putnull(text));
15875
15876		goto cleanup;
15877	}
15878
15879	if (readonly) {
15880		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15881			      NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
15882			      "rejecting restricted control channel "
15883			      "NTA command");
15884		CHECK(ISC_R_FAILURE);
15885	}
15886
15887	/* Get the NTA name if not found above. */
15888	if (nametext == NULL) {
15889		nametext = next_token(lex, text);
15890	}
15891	if (nametext == NULL) {
15892		return (ISC_R_UNEXPECTEDEND);
15893	}
15894
15895	/* Copy nametext as it'll be overwritten by next_token() */
15896	strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE);
15897
15898	if (strcmp(namebuf, ".") == 0) {
15899		ntaname = dns_rootname;
15900	} else {
15901		isc_buffer_t b;
15902		isc_buffer_init(&b, namebuf, strlen(namebuf));
15903		isc_buffer_add(&b, strlen(namebuf));
15904		CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL));
15905		ntaname = fname;
15906	}
15907
15908	/* Look for the view name. */
15909	viewname = next_token(lex, text);
15910	if (viewname != NULL) {
15911		strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE);
15912		viewname = viewbuf;
15913	}
15914
15915	if (next_token(lex, text) != NULL) {
15916		CHECK(DNS_R_SYNTAX);
15917	}
15918
15919	isc_stdtime_get(&now);
15920
15921	result = isc_task_beginexclusive(server->task);
15922	RUNTIME_CHECK(result == ISC_R_SUCCESS);
15923	excl = true;
15924	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15925	     view = ISC_LIST_NEXT(view, link))
15926	{
15927		if (viewname != NULL && strcmp(view->name, viewname) != 0) {
15928			continue;
15929		}
15930		viewfound = true;
15931
15932		if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) {
15933			continue;
15934		}
15935
15936		if (view->nta_lifetime == 0) {
15937			continue;
15938		}
15939
15940		if (!ttlset) {
15941			ntattl = view->nta_lifetime;
15942		}
15943
15944		if (ntatable != NULL) {
15945			dns_ntatable_detach(&ntatable);
15946		}
15947
15948		result = dns_view_getntatable(view, &ntatable);
15949		if (result == ISC_R_NOTFOUND) {
15950			result = ISC_R_SUCCESS;
15951			continue;
15952		}
15953
15954		result = dns_view_flushnode(view, ntaname, true);
15955		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15956			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15957			      "flush tree '%s' in cache view '%s': %s", namebuf,
15958			      view->name, isc_result_totext(result));
15959
15960		if (ntattl != 0) {
15961			CHECK(dns_ntatable_add(ntatable, ntaname, force, now,
15962					       ntattl));
15963
15964			when = now + ntattl;
15965			isc_time_set(&t, when, 0);
15966			isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
15967
15968			if (!first) {
15969				CHECK(putstr(text, "\n"));
15970			}
15971			first = false;
15972
15973			CHECK(putstr(text, "Negative trust anchor added: "));
15974			CHECK(putstr(text, namebuf));
15975			CHECK(putstr(text, "/"));
15976			CHECK(putstr(text, view->name));
15977			CHECK(putstr(text, ", expires "));
15978			CHECK(putstr(text, tbuf));
15979
15980			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15981				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15982				      "added NTA '%s' (%d sec) in view '%s'",
15983				      namebuf, ntattl, view->name);
15984		} else {
15985			bool wasremoved;
15986
15987			result = dns_ntatable_delete(ntatable, ntaname);
15988			if (result == ISC_R_SUCCESS) {
15989				wasremoved = true;
15990			} else if (result == ISC_R_NOTFOUND) {
15991				wasremoved = false;
15992			} else {
15993				goto cleanup;
15994			}
15995
15996			if (!first) {
15997				CHECK(putstr(text, "\n"));
15998			}
15999			first = false;
16000
16001			CHECK(putstr(text, "Negative trust anchor "));
16002			CHECK(putstr(text,
16003				     wasremoved ? "removed: " : "not found: "));
16004			CHECK(putstr(text, namebuf));
16005			CHECK(putstr(text, "/"));
16006			CHECK(putstr(text, view->name));
16007
16008			if (wasremoved) {
16009				isc_log_write(
16010					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16011					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
16012					"removed NTA '%s' in view %s", namebuf,
16013					view->name);
16014			}
16015		}
16016
16017		result = dns_view_saventa(view);
16018		if (result != ISC_R_SUCCESS) {
16019			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16020				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
16021				      "error writing NTA file "
16022				      "for view '%s': %s",
16023				      view->name, isc_result_totext(result));
16024		}
16025	}
16026
16027	if (!viewfound) {
16028		msg = "No such view";
16029		CHECK(ISC_R_NOTFOUND);
16030	}
16031
16032	(void)putnull(text);
16033
16034cleanup:
16035	if (msg != NULL) {
16036		(void)putstr(text, msg);
16037		(void)putnull(text);
16038	}
16039
16040	if (excl) {
16041		isc_task_endexclusive(server->task);
16042	}
16043	if (ntatable != NULL) {
16044		dns_ntatable_detach(&ntatable);
16045	}
16046	return (result);
16047}
16048
16049isc_result_t
16050named_server_saventa(named_server_t *server) {
16051	dns_view_t *view;
16052
16053	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16054	     view = ISC_LIST_NEXT(view, link))
16055	{
16056		isc_result_t result = dns_view_saventa(view);
16057
16058		if (result != ISC_R_SUCCESS) {
16059			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16060				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
16061				      "error writing NTA file "
16062				      "for view '%s': %s",
16063				      view->name, isc_result_totext(result));
16064		}
16065	}
16066
16067	return (ISC_R_SUCCESS);
16068}
16069
16070isc_result_t
16071named_server_loadnta(named_server_t *server) {
16072	dns_view_t *view;
16073
16074	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16075	     view = ISC_LIST_NEXT(view, link))
16076	{
16077		isc_result_t result = dns_view_loadnta(view);
16078
16079		if ((result != ISC_R_SUCCESS) &&
16080		    (result != ISC_R_FILENOTFOUND) &&
16081		    (result != ISC_R_NOTFOUND))
16082		{
16083			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16084				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
16085				      "error loading NTA file "
16086				      "for view '%s': %s",
16087				      view->name, isc_result_totext(result));
16088		}
16089	}
16090
16091	return (ISC_R_SUCCESS);
16092}
16093
16094static isc_result_t
16095mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
16096	isc_result_t result;
16097	char msg[DNS_NAME_FORMATSIZE + 500] = "";
16098
16099	snprintf(msg, sizeof(msg), "refreshing managed keys for '%s'",
16100		 view->name);
16101	CHECK(putstr(text, msg));
16102	CHECK(dns_zone_synckeyzone(view->managed_keys));
16103
16104cleanup:
16105	return (result);
16106}
16107
16108static isc_result_t
16109mkey_destroy(named_server_t *server, dns_view_t *view, isc_buffer_t **text) {
16110	isc_result_t result;
16111	char msg[DNS_NAME_FORMATSIZE + 500] = "";
16112	bool exclusive = false;
16113	const char *file = NULL;
16114	dns_db_t *dbp = NULL;
16115	dns_zone_t *mkzone = NULL;
16116	bool removed_a_file = false;
16117
16118	if (view->managed_keys == NULL) {
16119		CHECK(ISC_R_NOTFOUND);
16120	}
16121
16122	snprintf(msg, sizeof(msg), "destroying managed-keys database for '%s'",
16123		 view->name);
16124	CHECK(putstr(text, msg));
16125
16126	result = isc_task_beginexclusive(server->task);
16127	RUNTIME_CHECK(result == ISC_R_SUCCESS);
16128	exclusive = true;
16129
16130	/* Remove and clean up managed keys zone from view */
16131	mkzone = view->managed_keys;
16132	view->managed_keys = NULL;
16133	(void)dns_zone_flush(mkzone);
16134
16135	/* Unload zone database */
16136	if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) {
16137		dns_db_detach(&dbp);
16138		dns_zone_unload(mkzone);
16139	}
16140
16141	/* Delete files */
16142	file = dns_zone_getfile(mkzone);
16143	result = isc_file_remove(file);
16144	if (result == ISC_R_SUCCESS) {
16145		removed_a_file = true;
16146	} else {
16147		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16148			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
16149			      "file %s not removed: %s", file,
16150			      isc_result_totext(result));
16151	}
16152
16153	file = dns_zone_getjournal(mkzone);
16154	result = isc_file_remove(file);
16155	if (result == ISC_R_SUCCESS) {
16156		removed_a_file = true;
16157	} else {
16158		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16159			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
16160			      "file %s not removed: %s", file,
16161			      isc_result_totext(result));
16162	}
16163
16164	if (!removed_a_file) {
16165		CHECK(putstr(text, "error: no files could be removed"));
16166		CHECK(ISC_R_FAILURE);
16167	}
16168
16169	dns_zone_detach(&mkzone);
16170	result = ISC_R_SUCCESS;
16171
16172cleanup:
16173	if (exclusive) {
16174		isc_task_endexclusive(server->task);
16175	}
16176	return (result);
16177}
16178
16179static isc_result_t
16180mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
16181	isc_result_t result;
16182	dns_db_t *db = NULL;
16183	dns_dbversion_t *ver = NULL;
16184	dns_rriterator_t rrit;
16185	isc_stdtime_t now;
16186	dns_name_t *prevname = NULL;
16187
16188	isc_stdtime_get(&now);
16189
16190	CHECK(dns_zone_getdb(view->managed_keys, &db));
16191	dns_db_currentversion(db, &ver);
16192	dns_rriterator_init(&rrit, db, ver, 0);
16193	for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS;
16194	     result = dns_rriterator_nextrrset(&rrit))
16195	{
16196		char buf[DNS_NAME_FORMATSIZE + 500];
16197		dns_name_t *name = NULL;
16198		dns_rdataset_t *kdset = NULL;
16199		dns_rdata_t rdata = DNS_RDATA_INIT;
16200		dns_rdata_keydata_t kd;
16201		uint32_t ttl;
16202
16203		dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
16204		if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
16205		    !dns_rdataset_isassociated(kdset))
16206		{
16207			continue;
16208		}
16209
16210		if (name != prevname) {
16211			char nbuf[DNS_NAME_FORMATSIZE];
16212			dns_name_format(name, nbuf, sizeof(nbuf));
16213			snprintf(buf, sizeof(buf), "\n\n    name: %s", nbuf);
16214			CHECK(putstr(text, buf));
16215		}
16216
16217		for (result = dns_rdataset_first(kdset);
16218		     result == ISC_R_SUCCESS; result = dns_rdataset_next(kdset))
16219		{
16220			char alg[DNS_SECALG_FORMATSIZE];
16221			char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
16222			dns_keytag_t keyid;
16223			isc_region_t r;
16224			isc_time_t t;
16225			bool revoked;
16226
16227			dns_rdata_reset(&rdata);
16228			dns_rdataset_current(kdset, &rdata);
16229			result = dns_rdata_tostruct(&rdata, &kd, NULL);
16230			RUNTIME_CHECK(result == ISC_R_SUCCESS);
16231
16232			dns_rdata_toregion(&rdata, &r);
16233			isc_region_consume(&r, 12);
16234			keyid = dst_region_computeid(&r);
16235
16236			snprintf(buf, sizeof(buf), "\n    keyid: %u", keyid);
16237			CHECK(putstr(text, buf));
16238
16239			dns_secalg_format(kd.algorithm, alg, sizeof(alg));
16240			snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
16241			CHECK(putstr(text, buf));
16242
16243			revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
16244			snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
16245				 revoked ? " REVOKE" : "",
16246				 ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP"
16247								     : "",
16248				 (kd.flags == 0) ? " (none)" : "");
16249			CHECK(putstr(text, buf));
16250
16251			isc_time_set(&t, kd.refresh, 0);
16252			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
16253			snprintf(buf, sizeof(buf), "\n\tnext refresh: %s",
16254				 tbuf);
16255			CHECK(putstr(text, buf));
16256
16257			if (kd.removehd != 0) {
16258				isc_time_set(&t, kd.removehd, 0);
16259				isc_time_formathttptimestamp(&t, tbuf,
16260							     sizeof(tbuf));
16261				snprintf(buf, sizeof(buf), "\n\tremove at: %s",
16262					 tbuf);
16263				CHECK(putstr(text, buf));
16264			}
16265
16266			isc_time_set(&t, kd.addhd, 0);
16267			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
16268			if (kd.addhd == 0) {
16269				snprintf(buf, sizeof(buf), "\n\tno trust");
16270			} else if (revoked) {
16271				snprintf(buf, sizeof(buf), "\n\ttrust revoked");
16272			} else if (kd.addhd <= now) {
16273				snprintf(buf, sizeof(buf),
16274					 "\n\ttrusted since: %s", tbuf);
16275			} else if (kd.addhd > now) {
16276				snprintf(buf, sizeof(buf),
16277					 "\n\ttrust pending: %s", tbuf);
16278			}
16279			CHECK(putstr(text, buf));
16280		}
16281	}
16282
16283	if (result == ISC_R_NOMORE) {
16284		result = ISC_R_SUCCESS;
16285	}
16286
16287cleanup:
16288	if (ver != NULL) {
16289		dns_rriterator_destroy(&rrit);
16290		dns_db_closeversion(db, &ver, false);
16291	}
16292	if (db != NULL) {
16293		dns_db_detach(&db);
16294	}
16295
16296	return (result);
16297}
16298
16299static isc_result_t
16300mkey_status(dns_view_t *view, isc_buffer_t **text) {
16301	isc_result_t result;
16302	char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
16303	isc_time_t t;
16304
16305	CHECK(putstr(text, "view: "));
16306	CHECK(putstr(text, view->name));
16307
16308	CHECK(putstr(text, "\nnext scheduled event: "));
16309
16310	dns_zone_getrefreshkeytime(view->managed_keys, &t);
16311	if (isc_time_isepoch(&t)) {
16312		CHECK(putstr(text, "never"));
16313	} else {
16314		isc_time_formathttptimestamp(&t, msg, sizeof(msg));
16315		CHECK(putstr(text, msg));
16316	}
16317
16318	CHECK(mkey_dumpzone(view, text));
16319
16320cleanup:
16321	return (result);
16322}
16323
16324isc_result_t
16325named_server_mkeys(named_server_t *server, isc_lex_t *lex,
16326		   isc_buffer_t **text) {
16327	char *cmd, *classtxt, *viewtxt = NULL;
16328	isc_result_t result = ISC_R_SUCCESS;
16329	dns_view_t *view = NULL;
16330	dns_rdataclass_t rdclass;
16331	char msg[DNS_NAME_FORMATSIZE + 500] = "";
16332	enum { NONE, STATUS, REFRESH, SYNC, DESTROY } opt = NONE;
16333	bool found = false;
16334	bool first = true;
16335
16336	REQUIRE(text != NULL);
16337
16338	/* Skip rndc command name */
16339	cmd = next_token(lex, text);
16340	if (cmd == NULL) {
16341		return (ISC_R_UNEXPECTEDEND);
16342	}
16343
16344	/* Get managed-keys subcommand */
16345	cmd = next_token(lex, text);
16346	if (cmd == NULL) {
16347		return (ISC_R_UNEXPECTEDEND);
16348	}
16349
16350	if (strcasecmp(cmd, "status") == 0) {
16351		opt = STATUS;
16352	} else if (strcasecmp(cmd, "refresh") == 0) {
16353		opt = REFRESH;
16354	} else if (strcasecmp(cmd, "sync") == 0) {
16355		opt = SYNC;
16356	} else if (strcasecmp(cmd, "destroy") == 0) {
16357		opt = DESTROY;
16358	} else {
16359		snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
16360		(void)putstr(text, msg);
16361		result = ISC_R_UNEXPECTED;
16362		goto cleanup;
16363	}
16364
16365	/* Look for the optional class name. */
16366	classtxt = next_token(lex, text);
16367	if (classtxt != NULL) {
16368		isc_textregion_t r;
16369		r.base = classtxt;
16370		r.length = strlen(classtxt);
16371		result = dns_rdataclass_fromtext(&rdclass, &r);
16372		if (result != ISC_R_SUCCESS) {
16373			snprintf(msg, sizeof(msg), "unknown class '%s'",
16374				 classtxt);
16375			(void)putstr(text, msg);
16376			goto cleanup;
16377		}
16378		viewtxt = next_token(lex, text);
16379	}
16380
16381	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16382	     view = ISC_LIST_NEXT(view, link))
16383	{
16384		if (viewtxt != NULL && (rdclass != view->rdclass ||
16385					strcmp(view->name, viewtxt) != 0))
16386		{
16387			continue;
16388		}
16389
16390		if (view->managed_keys == NULL) {
16391			if (viewtxt != NULL) {
16392				snprintf(msg, sizeof(msg),
16393					 "view '%s': no managed keys", viewtxt);
16394				CHECK(putstr(text, msg));
16395				goto cleanup;
16396			} else {
16397				continue;
16398			}
16399		}
16400
16401		found = true;
16402
16403		switch (opt) {
16404		case REFRESH:
16405			if (!first) {
16406				CHECK(putstr(text, "\n"));
16407			}
16408			CHECK(mkey_refresh(view, text));
16409			break;
16410		case STATUS:
16411			if (!first) {
16412				CHECK(putstr(text, "\n\n"));
16413			}
16414			CHECK(mkey_status(view, text));
16415			break;
16416		case SYNC:
16417			CHECK(dns_zone_flush(view->managed_keys));
16418			break;
16419		case DESTROY:
16420			if (!first) {
16421				CHECK(putstr(text, "\n"));
16422			}
16423			CHECK(mkey_destroy(server, view, text));
16424			break;
16425		default:
16426			UNREACHABLE();
16427		}
16428
16429		if (viewtxt != NULL) {
16430			break;
16431		}
16432		first = false;
16433	}
16434
16435	if (!found) {
16436		CHECK(putstr(text, "no views with managed keys"));
16437	}
16438
16439cleanup:
16440	if (isc_buffer_usedlength(*text) > 0) {
16441		(void)putnull(text);
16442	}
16443
16444	return (result);
16445}
16446
16447isc_result_t
16448named_server_dnstap(named_server_t *server, isc_lex_t *lex,
16449		    isc_buffer_t **text) {
16450#ifdef HAVE_DNSTAP
16451	char *ptr;
16452	isc_result_t result;
16453	bool reopen = false;
16454	int backups = 0;
16455
16456	REQUIRE(text != NULL);
16457
16458	if (server->dtenv == NULL) {
16459		return (ISC_R_NOTFOUND);
16460	}
16461
16462	/* Check the command name. */
16463	ptr = next_token(lex, text);
16464	if (ptr == NULL) {
16465		return (ISC_R_UNEXPECTEDEND);
16466	}
16467
16468	/* "dnstap-reopen" was used in 9.11.0b1 */
16469	if (strcasecmp(ptr, "dnstap-reopen") == 0) {
16470		reopen = true;
16471	} else {
16472		ptr = next_token(lex, text);
16473		if (ptr == NULL) {
16474			return (ISC_R_UNEXPECTEDEND);
16475		}
16476	}
16477
16478	if (reopen || strcasecmp(ptr, "-reopen") == 0) {
16479		backups = ISC_LOG_ROLLNEVER;
16480	} else if ((strcasecmp(ptr, "-roll") == 0)) {
16481		unsigned int n;
16482		ptr = next_token(lex, text);
16483		if (ptr != NULL) {
16484			unsigned int u;
16485			n = sscanf(ptr, "%u", &u);
16486			if (n != 1U || u > INT_MAX) {
16487				return (ISC_R_BADNUMBER);
16488			}
16489			backups = u;
16490		} else {
16491			backups = ISC_LOG_ROLLINFINITE;
16492		}
16493	} else {
16494		return (DNS_R_SYNTAX);
16495	}
16496
16497	result = dns_dt_reopen(server->dtenv, backups);
16498	return (result);
16499#else  /* ifdef HAVE_DNSTAP */
16500	UNUSED(server);
16501	UNUSED(lex);
16502	UNUSED(text);
16503	return (ISC_R_NOTIMPLEMENTED);
16504#endif /* ifdef HAVE_DNSTAP */
16505}
16506
16507isc_result_t
16508named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) {
16509	char *ptr;
16510	isc_result_t result = ISC_R_SUCCESS;
16511	uint32_t initial, idle, keepalive, advertised;
16512	char msg[128];
16513
16514	/* Skip the command name. */
16515	ptr = next_token(lex, text);
16516	if (ptr == NULL) {
16517		return (ISC_R_UNEXPECTEDEND);
16518	}
16519
16520	isc_nm_gettimeouts(named_g_netmgr, &initial, &idle, &keepalive,
16521			   &advertised);
16522
16523	/* Look for optional arguments. */
16524	ptr = next_token(lex, NULL);
16525	if (ptr != NULL) {
16526		CHECK(isc_parse_uint32(&initial, ptr, 10));
16527		initial *= 100;
16528		if (initial > MAX_INITIAL_TIMEOUT) {
16529			CHECK(ISC_R_RANGE);
16530		}
16531		if (initial < MIN_INITIAL_TIMEOUT) {
16532			CHECK(ISC_R_RANGE);
16533		}
16534
16535		ptr = next_token(lex, text);
16536		if (ptr == NULL) {
16537			return (ISC_R_UNEXPECTEDEND);
16538		}
16539		CHECK(isc_parse_uint32(&idle, ptr, 10));
16540		idle *= 100;
16541		if (idle > MAX_IDLE_TIMEOUT) {
16542			CHECK(ISC_R_RANGE);
16543		}
16544		if (idle < MIN_IDLE_TIMEOUT) {
16545			CHECK(ISC_R_RANGE);
16546		}
16547
16548		ptr = next_token(lex, text);
16549		if (ptr == NULL) {
16550			return (ISC_R_UNEXPECTEDEND);
16551		}
16552		CHECK(isc_parse_uint32(&keepalive, ptr, 10));
16553		keepalive *= 100;
16554		if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
16555			CHECK(ISC_R_RANGE);
16556		}
16557		if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
16558			CHECK(ISC_R_RANGE);
16559		}
16560
16561		ptr = next_token(lex, text);
16562		if (ptr == NULL) {
16563			return (ISC_R_UNEXPECTEDEND);
16564		}
16565		CHECK(isc_parse_uint32(&advertised, ptr, 10));
16566		advertised *= 100;
16567		if (advertised > MAX_ADVERTISED_TIMEOUT) {
16568			CHECK(ISC_R_RANGE);
16569		}
16570
16571		result = isc_task_beginexclusive(named_g_server->task);
16572		RUNTIME_CHECK(result == ISC_R_SUCCESS);
16573
16574		isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
16575				   advertised);
16576
16577		isc_task_endexclusive(named_g_server->task);
16578	}
16579
16580	snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100);
16581	CHECK(putstr(text, msg));
16582	snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100);
16583	CHECK(putstr(text, msg));
16584	snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n",
16585		 keepalive / 100);
16586	CHECK(putstr(text, msg));
16587	snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u",
16588		 advertised / 100);
16589	CHECK(putstr(text, msg));
16590
16591cleanup:
16592	if (isc_buffer_usedlength(*text) > 0) {
16593		(void)putnull(text);
16594	}
16595
16596	return (result);
16597}
16598
16599isc_result_t
16600named_server_servestale(named_server_t *server, isc_lex_t *lex,
16601			isc_buffer_t **text) {
16602	char *ptr, *classtxt, *viewtxt = NULL;
16603	char msg[128];
16604	dns_rdataclass_t rdclass = dns_rdataclass_in;
16605	dns_view_t *view;
16606	bool found = false;
16607	dns_stale_answer_t staleanswersok = dns_stale_answer_conf;
16608	bool wantstatus = false;
16609	isc_result_t result = ISC_R_SUCCESS;
16610	bool exclusive = false;
16611
16612	REQUIRE(text != NULL);
16613
16614	/* Skip the command name. */
16615	ptr = next_token(lex, text);
16616	if (ptr == NULL) {
16617		return (ISC_R_UNEXPECTEDEND);
16618	}
16619
16620	ptr = next_token(lex, NULL);
16621	if (ptr == NULL) {
16622		return (ISC_R_UNEXPECTEDEND);
16623	}
16624
16625	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
16626	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
16627	{
16628		staleanswersok = dns_stale_answer_yes;
16629	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
16630		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
16631	{
16632		staleanswersok = dns_stale_answer_no;
16633	} else if (strcasecmp(ptr, "reset") == 0) {
16634		staleanswersok = dns_stale_answer_conf;
16635	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
16636		wantstatus = true;
16637	} else {
16638		return (DNS_R_SYNTAX);
16639	}
16640
16641	/* Look for the optional class name. */
16642	classtxt = next_token(lex, text);
16643	if (classtxt != NULL) {
16644		isc_textregion_t r;
16645
16646		/* Look for the optional view name. */
16647		viewtxt = next_token(lex, text);
16648
16649		/*
16650		 * If 'classtext' is not a valid class then it us a view name.
16651		 */
16652		r.base = classtxt;
16653		r.length = strlen(classtxt);
16654		result = dns_rdataclass_fromtext(&rdclass, &r);
16655		if (result != ISC_R_SUCCESS) {
16656			if (viewtxt != NULL) {
16657				snprintf(msg, sizeof(msg), "unknown class '%s'",
16658					 classtxt);
16659				(void)putstr(text, msg);
16660				goto cleanup;
16661			}
16662
16663			viewtxt = classtxt;
16664			classtxt = NULL;
16665		}
16666	}
16667
16668	result = isc_task_beginexclusive(server->task);
16669	RUNTIME_CHECK(result == ISC_R_SUCCESS);
16670	exclusive = true;
16671
16672	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16673	     view = ISC_LIST_NEXT(view, link))
16674	{
16675		dns_ttl_t stale_ttl = 0;
16676		uint32_t stale_refresh = 0;
16677		dns_db_t *db = NULL;
16678
16679		if (classtxt != NULL && rdclass != view->rdclass) {
16680			continue;
16681		}
16682
16683		if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0) {
16684			continue;
16685		}
16686
16687		if (!wantstatus) {
16688			view->staleanswersok = staleanswersok;
16689			found = true;
16690			continue;
16691		}
16692
16693		db = NULL;
16694		dns_db_attach(view->cachedb, &db);
16695		(void)dns_db_getservestalettl(db, &stale_ttl);
16696		(void)dns_db_getservestalerefresh(db, &stale_refresh);
16697		dns_db_detach(&db);
16698		if (found) {
16699			CHECK(putstr(text, "\n"));
16700		}
16701		CHECK(putstr(text, view->name));
16702		CHECK(putstr(text, ": "));
16703		switch (view->staleanswersok) {
16704		case dns_stale_answer_yes:
16705			if (stale_ttl > 0) {
16706				CHECK(putstr(text, "stale cache enabled; stale "
16707						   "answers enabled"));
16708			} else {
16709				CHECK(putstr(text,
16710					     "stale cache disabled; stale "
16711					     "answers unavailable"));
16712			}
16713			break;
16714		case dns_stale_answer_no:
16715			if (stale_ttl > 0) {
16716				CHECK(putstr(text, "stale cache enabled; stale "
16717						   "answers disabled"));
16718			} else {
16719				CHECK(putstr(text,
16720					     "stale cache disabled; stale "
16721					     "answers unavailable"));
16722			}
16723			break;
16724		case dns_stale_answer_conf:
16725			if (view->staleanswersenable && stale_ttl > 0) {
16726				CHECK(putstr(text, "stale cache enabled; stale "
16727						   "answers enabled"));
16728			} else if (stale_ttl > 0) {
16729				CHECK(putstr(text, "stale cache enabled; stale "
16730						   "answers disabled"));
16731			} else {
16732				CHECK(putstr(text,
16733					     "stale cache disabled; stale "
16734					     "answers unavailable"));
16735			}
16736			break;
16737		}
16738		if (stale_ttl > 0) {
16739			snprintf(msg, sizeof(msg),
16740				 " (stale-answer-ttl=%u max-stale-ttl=%u "
16741				 "stale-refresh-time=%u)",
16742				 view->staleanswerttl, stale_ttl,
16743				 stale_refresh);
16744			CHECK(putstr(text, msg));
16745		}
16746		found = true;
16747	}
16748
16749	if (!found) {
16750		result = ISC_R_NOTFOUND;
16751	}
16752
16753cleanup:
16754	if (exclusive) {
16755		isc_task_endexclusive(named_g_server->task);
16756	}
16757
16758	if (isc_buffer_usedlength(*text) > 0) {
16759		(void)putnull(text);
16760	}
16761
16762	return (result);
16763}
16764