xref: /netbsd/external/mpl/bind/dist/bin/named/server.c (revision a706c3b7)
1 /*	$NetBSD: server.c,v 1.20 2023/06/26 22:02:59 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/base64.h>
34 #include <isc/commandline.h>
35 #include <isc/dir.h>
36 #include <isc/file.h>
37 #include <isc/hash.h>
38 #include <isc/hex.h>
39 #include <isc/hmac.h>
40 #include <isc/httpd.h>
41 #include <isc/lex.h>
42 #include <isc/meminfo.h>
43 #include <isc/netmgr.h>
44 #include <isc/nonce.h>
45 #include <isc/parseint.h>
46 #include <isc/platform.h>
47 #include <isc/portset.h>
48 #include <isc/print.h>
49 #include <isc/refcount.h>
50 #include <isc/resource.h>
51 #include <isc/siphash.h>
52 #include <isc/socket.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/lib.h>
82 #include <dns/master.h>
83 #include <dns/masterdump.h>
84 #include <dns/nsec3.h>
85 #include <dns/nta.h>
86 #include <dns/order.h>
87 #include <dns/peer.h>
88 #include <dns/portlist.h>
89 #include <dns/private.h>
90 #include <dns/rbt.h>
91 #include <dns/rdataclass.h>
92 #include <dns/rdatalist.h>
93 #include <dns/rdataset.h>
94 #include <dns/rdatastruct.h>
95 #include <dns/resolver.h>
96 #include <dns/rootns.h>
97 #include <dns/rriterator.h>
98 #include <dns/secalg.h>
99 #include <dns/soa.h>
100 #include <dns/stats.h>
101 #include <dns/time.h>
102 #include <dns/tkey.h>
103 #include <dns/tsig.h>
104 #include <dns/ttl.h>
105 #include <dns/view.h>
106 #include <dns/zone.h>
107 #include <dns/zt.h>
108 
109 #include <dst/dst.h>
110 #include <dst/result.h>
111 
112 #include <isccfg/grammar.h>
113 #include <isccfg/kaspconf.h>
114 #include <isccfg/namedconf.h>
115 
116 #include <ns/client.h>
117 #include <ns/hooks.h>
118 #include <ns/interfacemgr.h>
119 #include <ns/listenlist.h>
120 
121 #include <bind9/check.h>
122 
123 #include <named/config.h>
124 #include <named/control.h>
125 #if defined(HAVE_GEOIP2)
126 #include <named/geoip.h>
127 #endif /* HAVE_GEOIP2 */
128 #include <named/log.h>
129 #include <named/logconf.h>
130 #include <named/main.h>
131 #include <named/os.h>
132 #include <named/server.h>
133 #include <named/statschannel.h>
134 #include <named/tkeyconf.h>
135 #include <named/tsigconf.h>
136 #include <named/zoneconf.h>
137 #ifdef HAVE_LIBSCF
138 #include <stdlib.h>
139 
140 #include <named/smf_globals.h>
141 #endif /* ifdef HAVE_LIBSCF */
142 
143 #ifdef HAVE_LMDB
144 #include <lmdb.h>
145 
146 #include <dns/lmdb.h>
147 #define count_newzones	   count_newzones_db
148 #define configure_newzones configure_newzones_db
149 #define dumpzone	   dumpzone_db
150 #else /* HAVE_LMDB */
151 #define count_newzones	   count_newzones_file
152 #define configure_newzones configure_newzones_file
153 #define dumpzone	   dumpzone_file
154 #endif /* HAVE_LMDB */
155 
156 #ifndef SIZE_MAX
157 #define SIZE_MAX ((size_t)-1)
158 #endif /* ifndef SIZE_MAX */
159 
160 #ifndef SIZE_AS_PERCENT
161 #define SIZE_AS_PERCENT ((size_t)-2)
162 #endif /* ifndef SIZE_AS_PERCENT */
163 
164 #ifdef TUNE_LARGE
165 #define RESOLVER_NTASKS_PERCPU 32
166 #define UDPBUFFERS	       32768
167 #define EXCLBUFFERS	       32768
168 #else
169 #define RESOLVER_NTASKS_PERCPU 8
170 #define UDPBUFFERS	       1000
171 #define EXCLBUFFERS	       4096
172 #endif /* TUNE_LARGE */
173 
174 /* RFC7828 defines timeout as 16-bit value specified in units of 100
175  * milliseconds, so the maximum and minimum advertised and keepalive
176  * timeouts are capped by the data type (it's ~109 minutes)
177  */
178 #define MIN_INITIAL_TIMEOUT    UINT32_C(2500)	/* 2.5 seconds */
179 #define MAX_INITIAL_TIMEOUT    UINT32_C(120000) /* 2 minutes */
180 #define MIN_IDLE_TIMEOUT       UINT32_C(100)	/* 0.1 seconds */
181 #define MAX_IDLE_TIMEOUT       UINT32_C(120000) /* 2 minutes */
182 #define MIN_KEEPALIVE_TIMEOUT  UINT32_C(100)	/* 0.1 seconds */
183 #define MAX_KEEPALIVE_TIMEOUT  UINT32_C(UINT16_MAX * 100)
184 #define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */
185 #define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100)
186 
187 /*%
188  * Check an operation for failure.  Assumes that the function
189  * using it has a 'result' variable and a 'cleanup' label.
190  */
191 #define CHECK(op)                            \
192 	do {                                 \
193 		result = (op);               \
194 		if (result != ISC_R_SUCCESS) \
195 			goto cleanup;        \
196 	} while (0)
197 
198 #define TCHECK(op)                               \
199 	do {                                     \
200 		tresult = (op);                  \
201 		if (tresult != ISC_R_SUCCESS) {  \
202 			isc_buffer_clear(*text); \
203 			goto cleanup;            \
204 		}                                \
205 	} while (0)
206 
207 #define CHECKM(op, msg)                                                        \
208 	do {                                                                   \
209 		result = (op);                                                 \
210 		if (result != ISC_R_SUCCESS) {                                 \
211 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
212 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
213 				      "%s: %s", msg,                           \
214 				      isc_result_totext(result));              \
215 			goto cleanup;                                          \
216 		}                                                              \
217 	} while (0)
218 
219 #define CHECKMF(op, msg, file)                                                 \
220 	do {                                                                   \
221 		result = (op);                                                 \
222 		if (result != ISC_R_SUCCESS) {                                 \
223 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
224 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
225 				      "%s '%s': %s", msg, file,                \
226 				      isc_result_totext(result));              \
227 			goto cleanup;                                          \
228 		}                                                              \
229 	} while (0)
230 
231 #define CHECKFATAL(op, msg)                         \
232 	do {                                        \
233 		result = (op);                      \
234 		if (result != ISC_R_SUCCESS)        \
235 			fatal(server, msg, result); \
236 	} while (0)
237 
238 /*%
239  * Maximum ADB size for views that share a cache.  Use this limit to suppress
240  * the total of memory footprint, which should be the main reason for sharing
241  * a cache.  Only effective when a finite max-cache-size is specified.
242  * This is currently defined to be 8MB.
243  */
244 #define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
245 
246 struct named_dispatch {
247 	isc_sockaddr_t addr;
248 	unsigned int dispatchgen;
249 	dns_dispatch_t *dispatch;
250 	ISC_LINK(struct named_dispatch) link;
251 };
252 
253 struct named_cache {
254 	dns_cache_t *cache;
255 	dns_view_t *primaryview;
256 	bool needflush;
257 	bool adbsizeadjusted;
258 	dns_rdataclass_t rdclass;
259 	ISC_LINK(named_cache_t) link;
260 };
261 
262 struct dumpcontext {
263 	isc_mem_t *mctx;
264 	bool dumpcache;
265 	bool dumpzones;
266 	bool dumpadb;
267 	bool dumpbad;
268 	bool dumpexpired;
269 	bool dumpfail;
270 	FILE *fp;
271 	ISC_LIST(struct viewlistentry) viewlist;
272 	struct viewlistentry *view;
273 	struct zonelistentry *zone;
274 	dns_dumpctx_t *mdctx;
275 	dns_db_t *db;
276 	dns_db_t *cache;
277 	isc_task_t *task;
278 	dns_dbversion_t *version;
279 };
280 
281 struct viewlistentry {
282 	dns_view_t *view;
283 	ISC_LINK(struct viewlistentry) link;
284 	ISC_LIST(struct zonelistentry) zonelist;
285 };
286 
287 struct zonelistentry {
288 	dns_zone_t *zone;
289 	ISC_LINK(struct zonelistentry) link;
290 };
291 
292 /*%
293  * Configuration context to retain for each view that allows
294  * new zones to be added at runtime.
295  */
296 typedef struct ns_cfgctx {
297 	isc_mem_t *mctx;
298 	cfg_parser_t *conf_parser;
299 	cfg_parser_t *add_parser;
300 	cfg_obj_t *config;
301 	cfg_obj_t *vconfig;
302 	cfg_obj_t *nzf_config;
303 	cfg_aclconfctx_t *actx;
304 } ns_cfgctx_t;
305 
306 /*%
307  * A function to write out added-zone configuration to the new_zone_file
308  * specified in 'view'. Maybe called by delete_zoneconf().
309  */
310 typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
311 
312 /*%
313  * Holds state information for the initial zone loading process.
314  * Uses the isc_refcount structure to count the number of views
315  * with pending zone loads, dereferencing as each view finishes.
316  */
317 typedef struct {
318 	named_server_t *server;
319 	bool reconfig;
320 	isc_refcount_t refs;
321 } ns_zoneload_t;
322 
323 typedef struct {
324 	named_server_t *server;
325 } catz_cb_data_t;
326 
327 typedef struct catz_chgzone_event {
328 	ISC_EVENT_COMMON(struct catz_chgzone_event);
329 	dns_catz_entry_t *entry;
330 	dns_catz_zone_t *origin;
331 	dns_view_t *view;
332 	catz_cb_data_t *cbd;
333 	bool mod;
334 } catz_chgzone_event_t;
335 
336 typedef struct {
337 	unsigned int magic;
338 #define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
339 	isc_buffer_t **text;
340 	isc_result_t result;
341 } ns_dzarg_t;
342 
343 /*
344  * These zones should not leak onto the Internet.
345  */
346 const char *empty_zones[] = {
347 	/* RFC 1918 */
348 	"10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
349 	"18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
350 	"21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
351 	"24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
352 	"27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
353 	"30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
354 
355 	/* RFC 6598 */
356 	"64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
357 	"67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
358 	"70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
359 	"73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
360 	"76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
361 	"79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
362 	"82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
363 	"85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
364 	"88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
365 	"91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
366 	"94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
367 	"97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
368 	"100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA", "102.100.IN-ADDR.ARPA",
369 	"103.100.IN-ADDR.ARPA", "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
370 	"106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA", "108.100.IN-ADDR.ARPA",
371 	"109.100.IN-ADDR.ARPA", "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
372 	"112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA", "114.100.IN-ADDR.ARPA",
373 	"115.100.IN-ADDR.ARPA", "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
374 	"118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA", "120.100.IN-ADDR.ARPA",
375 	"121.100.IN-ADDR.ARPA", "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
376 	"124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA", "126.100.IN-ADDR.ARPA",
377 	"127.100.IN-ADDR.ARPA",
378 
379 	/* RFC 5735 and RFC 5737 */
380 	"0.IN-ADDR.ARPA",		/* THIS NETWORK */
381 	"127.IN-ADDR.ARPA",		/* LOOPBACK */
382 	"254.169.IN-ADDR.ARPA",		/* LINK LOCAL */
383 	"2.0.192.IN-ADDR.ARPA",		/* TEST NET */
384 	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
385 	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
386 	"255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
387 
388 	/* Local IPv6 Unicast Addresses */
389 	"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."
390 	"ARPA",
391 	"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."
392 	"ARPA",
393 	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
394 	"D.F.IP6.ARPA", "8.E.F.IP6.ARPA", /* LINK LOCAL */
395 	"9.E.F.IP6.ARPA",		  /* LINK LOCAL */
396 	"A.E.F.IP6.ARPA",		  /* LINK LOCAL */
397 	"B.E.F.IP6.ARPA",		  /* LINK LOCAL */
398 
399 	/* Example Prefix, RFC 3849. */
400 	"8.B.D.0.1.0.0.2.IP6.ARPA",
401 
402 	/* RFC 7534 */
403 	"EMPTY.AS112.ARPA",
404 
405 	/* RFC 8375 */
406 	"HOME.ARPA",
407 
408 	NULL
409 };
410 
411 ISC_PLATFORM_NORETURN_PRE static void
412 fatal(named_server_t *server, const char *msg,
413       isc_result_t result) ISC_PLATFORM_NORETURN_POST;
414 
415 static void
416 named_server_reload(isc_task_t *task, isc_event_t *event);
417 
418 static isc_result_t
419 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
420 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
421 			uint16_t family, ns_listenelt_t **target);
422 static isc_result_t
423 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
424 			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
425 			 uint16_t family, ns_listenlist_t **target);
426 
427 static isc_result_t
428 configure_forward(const cfg_obj_t *config, dns_view_t *view,
429 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
430 		  const cfg_obj_t *forwardtype);
431 
432 static isc_result_t
433 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
434 		     const cfg_obj_t *alternates);
435 
436 static isc_result_t
437 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
438 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
439 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
440 	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
441 	       bool modify);
442 
443 static void
444 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
445 			     dns_view_t *view);
446 
447 static isc_result_t
448 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
449 		   isc_mem_t *mctx, cfg_aclconfctx_t *actx);
450 
451 static isc_result_t
452 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
453 
454 static void
455 end_reserved_dispatches(named_server_t *server, bool all);
456 
457 static void
458 newzone_cfgctx_destroy(void **cfgp);
459 
460 static isc_result_t
461 putstr(isc_buffer_t **b, const char *str);
462 
463 static isc_result_t
464 putmem(isc_buffer_t **b, const char *str, size_t len);
465 
466 static isc_result_t
467 putuint8(isc_buffer_t **b, uint8_t val);
468 
469 static isc_result_t
470 putnull(isc_buffer_t **b);
471 
472 static int
473 count_zones(const cfg_obj_t *conf);
474 
475 #ifdef HAVE_LMDB
476 static isc_result_t
477 migrate_nzf(dns_view_t *view);
478 
479 static isc_result_t
480 nzd_writable(dns_view_t *view);
481 
482 static isc_result_t
483 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
484 
485 static isc_result_t
486 nzd_env_reopen(dns_view_t *view);
487 
488 static void
489 nzd_env_close(dns_view_t *view);
490 
491 static isc_result_t
492 nzd_close(MDB_txn **txnp, bool commit);
493 
494 static isc_result_t
495 nzd_count(dns_view_t *view, int *countp);
496 #else  /* ifdef HAVE_LMDB */
497 static isc_result_t
498 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
499 #endif /* ifdef HAVE_LMDB */
500 
501 /*%
502  * Configure a single view ACL at '*aclp'.  Get its configuration from
503  * 'vconfig' (for per-view configuration) and maybe from 'config'
504  */
505 static isc_result_t
configure_view_acl(const cfg_obj_t * vconfig,const cfg_obj_t * config,const cfg_obj_t * gconfig,const char * aclname,const char * acltuplename,cfg_aclconfctx_t * actx,isc_mem_t * mctx,dns_acl_t ** aclp)506 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
507 		   const cfg_obj_t *gconfig, const char *aclname,
508 		   const char *acltuplename, cfg_aclconfctx_t *actx,
509 		   isc_mem_t *mctx, dns_acl_t **aclp) {
510 	isc_result_t result;
511 	const cfg_obj_t *maps[4];
512 	const cfg_obj_t *aclobj = NULL;
513 	int i = 0;
514 
515 	if (*aclp != NULL) {
516 		dns_acl_detach(aclp);
517 	}
518 	if (vconfig != NULL) {
519 		maps[i++] = cfg_tuple_get(vconfig, "options");
520 	}
521 	if (config != NULL) {
522 		const cfg_obj_t *options = NULL;
523 		(void)cfg_map_get(config, "options", &options);
524 		if (options != NULL) {
525 			maps[i++] = options;
526 		}
527 	}
528 	if (gconfig != NULL) {
529 		const cfg_obj_t *options = NULL;
530 		(void)cfg_map_get(gconfig, "options", &options);
531 		if (options != NULL) {
532 			maps[i++] = options;
533 		}
534 	}
535 	maps[i] = NULL;
536 
537 	(void)named_config_get(maps, aclname, &aclobj);
538 	if (aclobj == NULL) {
539 		/*
540 		 * No value available.	*aclp == NULL.
541 		 */
542 		return (ISC_R_SUCCESS);
543 	}
544 
545 	if (acltuplename != NULL) {
546 		/*
547 		 * If the ACL is given in an optional tuple, retrieve it.
548 		 * The parser should have ensured that a valid object be
549 		 * returned.
550 		 */
551 		aclobj = cfg_tuple_get(aclobj, acltuplename);
552 	}
553 
554 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
555 				    aclp);
556 
557 	return (result);
558 }
559 
560 /*%
561  * Configure a sortlist at '*aclp'.  Essentially the same as
562  * configure_view_acl() except it calls cfg_acl_fromconfig with a
563  * nest_level value of 2.
564  */
565 static isc_result_t
configure_view_sortlist(const cfg_obj_t * vconfig,const cfg_obj_t * config,cfg_aclconfctx_t * actx,isc_mem_t * mctx,dns_acl_t ** aclp)566 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
567 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
568 			dns_acl_t **aclp) {
569 	isc_result_t result;
570 	const cfg_obj_t *maps[3];
571 	const cfg_obj_t *aclobj = NULL;
572 	int i = 0;
573 
574 	if (*aclp != NULL) {
575 		dns_acl_detach(aclp);
576 	}
577 	if (vconfig != NULL) {
578 		maps[i++] = cfg_tuple_get(vconfig, "options");
579 	}
580 	if (config != NULL) {
581 		const cfg_obj_t *options = NULL;
582 		(void)cfg_map_get(config, "options", &options);
583 		if (options != NULL) {
584 			maps[i++] = options;
585 		}
586 	}
587 	maps[i] = NULL;
588 
589 	(void)named_config_get(maps, "sortlist", &aclobj);
590 	if (aclobj == NULL) {
591 		return (ISC_R_SUCCESS);
592 	}
593 
594 	/*
595 	 * Use a nest level of 3 for the "top level" of the sortlist;
596 	 * this means each entry in the top three levels will be stored
597 	 * as lists of separate, nested ACLs, rather than merged together
598 	 * into IP tables as is usually done with ACLs.
599 	 */
600 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
601 				    aclp);
602 
603 	return (result);
604 }
605 
606 static isc_result_t
configure_view_nametable(const cfg_obj_t * vconfig,const cfg_obj_t * config,const char * confname,const char * conftuplename,isc_mem_t * mctx,dns_rbt_t ** rbtp)607 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
608 			 const char *confname, const char *conftuplename,
609 			 isc_mem_t *mctx, dns_rbt_t **rbtp) {
610 	isc_result_t result;
611 	const cfg_obj_t *maps[3];
612 	const cfg_obj_t *obj = NULL;
613 	const cfg_listelt_t *element;
614 	int i = 0;
615 	dns_fixedname_t fixed;
616 	dns_name_t *name;
617 	isc_buffer_t b;
618 	const char *str;
619 	const cfg_obj_t *nameobj;
620 
621 	if (*rbtp != NULL) {
622 		dns_rbt_destroy(rbtp);
623 	}
624 	if (vconfig != NULL) {
625 		maps[i++] = cfg_tuple_get(vconfig, "options");
626 	}
627 	if (config != NULL) {
628 		const cfg_obj_t *options = NULL;
629 		(void)cfg_map_get(config, "options", &options);
630 		if (options != NULL) {
631 			maps[i++] = options;
632 		}
633 	}
634 	maps[i] = NULL;
635 
636 	(void)named_config_get(maps, confname, &obj);
637 	if (obj == NULL) {
638 		/*
639 		 * No value available.	*rbtp == NULL.
640 		 */
641 		return (ISC_R_SUCCESS);
642 	}
643 
644 	if (conftuplename != NULL) {
645 		obj = cfg_tuple_get(obj, conftuplename);
646 		if (cfg_obj_isvoid(obj)) {
647 			return (ISC_R_SUCCESS);
648 		}
649 	}
650 
651 	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
652 	if (result != ISC_R_SUCCESS) {
653 		return (result);
654 	}
655 
656 	name = dns_fixedname_initname(&fixed);
657 	for (element = cfg_list_first(obj); element != NULL;
658 	     element = cfg_list_next(element))
659 	{
660 		nameobj = cfg_listelt_value(element);
661 		str = cfg_obj_asstring(nameobj);
662 		isc_buffer_constinit(&b, str, strlen(str));
663 		isc_buffer_add(&b, strlen(str));
664 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
665 		/*
666 		 * We don't need the node data, but need to set dummy data to
667 		 * avoid a partial match with an empty node.  For example, if
668 		 * we have foo.example.com and bar.example.com, we'd get a match
669 		 * for baz.example.com, which is not the expected result.
670 		 * We simply use (void *)1 as the dummy data.
671 		 */
672 		result = dns_rbt_addname(*rbtp, name, (void *)1);
673 		if (result != ISC_R_SUCCESS) {
674 			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
675 				    "failed to add %s for %s: %s", str,
676 				    confname, isc_result_totext(result));
677 			goto cleanup;
678 		}
679 	}
680 
681 	return (result);
682 
683 cleanup:
684 	dns_rbt_destroy(rbtp);
685 	return (result);
686 }
687 
688 static isc_result_t
ta_fromconfig(const cfg_obj_t * key,bool * initialp,const char ** namestrp,unsigned char * digest,dns_rdata_ds_t * ds)689 ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
690 	      unsigned char *digest, dns_rdata_ds_t *ds) {
691 	isc_result_t result;
692 	dns_rdata_dnskey_t keystruct;
693 	dns_rdata_t rdata = DNS_RDATA_INIT;
694 	uint32_t rdata1, rdata2, rdata3;
695 	const char *datastr = NULL, *namestr = NULL;
696 	unsigned char data[4096];
697 	isc_buffer_t databuf;
698 	unsigned char rrdata[4096];
699 	isc_buffer_t rrdatabuf;
700 	isc_region_t r;
701 	dns_fixedname_t fname;
702 	dns_name_t *name = NULL;
703 	isc_buffer_t namebuf;
704 	const char *atstr = NULL;
705 	enum {
706 		INIT_DNSKEY,
707 		STATIC_DNSKEY,
708 		INIT_DS,
709 		STATIC_DS,
710 		TRUSTED
711 	} anchortype;
712 
713 	REQUIRE(namestrp != NULL && *namestrp == NULL);
714 	REQUIRE(ds != NULL);
715 
716 	/* if DNSKEY, flags; if DS, key tag */
717 	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
718 
719 	/* if DNSKEY, protocol; if DS, algorithm */
720 	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
721 
722 	/* if DNSKEY, algorithm; if DS, digest type */
723 	rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3"));
724 
725 	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
726 	*namestrp = namestr;
727 
728 	name = dns_fixedname_initname(&fname);
729 	isc_buffer_constinit(&namebuf, namestr, strlen(namestr));
730 	isc_buffer_add(&namebuf, strlen(namestr));
731 	CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL));
732 
733 	if (*initialp) {
734 		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
735 
736 		if (strcasecmp(atstr, "static-key") == 0) {
737 			*initialp = false;
738 			anchortype = STATIC_DNSKEY;
739 		} else if (strcasecmp(atstr, "static-ds") == 0) {
740 			*initialp = false;
741 			anchortype = STATIC_DS;
742 		} else if (strcasecmp(atstr, "initial-key") == 0) {
743 			anchortype = INIT_DNSKEY;
744 		} else if (strcasecmp(atstr, "initial-ds") == 0) {
745 			anchortype = INIT_DS;
746 		} else {
747 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
748 				    "key '%s': "
749 				    "invalid initialization method '%s'",
750 				    namestr, atstr);
751 			result = ISC_R_FAILURE;
752 			goto cleanup;
753 		}
754 	} else {
755 		anchortype = TRUSTED;
756 	}
757 
758 	isc_buffer_init(&databuf, data, sizeof(data));
759 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
760 
761 	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
762 				.common.rdtype = dns_rdatatype_ds };
763 
764 	ISC_LINK_INIT(&ds->common, link);
765 
766 	switch (anchortype) {
767 	case INIT_DNSKEY:
768 	case STATIC_DNSKEY:
769 	case TRUSTED:
770 		/*
771 		 * This function should never be reached for view
772 		 * class other than IN
773 		 */
774 		keystruct.common.rdclass = dns_rdataclass_in;
775 		keystruct.common.rdtype = dns_rdatatype_dnskey;
776 
777 		/*
778 		 * The key data in keystruct is not dynamically allocated.
779 		 */
780 		keystruct.mctx = NULL;
781 
782 		ISC_LINK_INIT(&keystruct.common, link);
783 
784 		if (rdata1 > 0xffff) {
785 			CHECKM(ISC_R_RANGE, "key flags");
786 		}
787 		if (rdata1 & DNS_KEYFLAG_REVOKE) {
788 			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
789 		}
790 		if (rdata2 > 0xff) {
791 			CHECKM(ISC_R_RANGE, "key protocol");
792 		}
793 		if (rdata3 > 0xff) {
794 			CHECKM(ISC_R_RANGE, "key algorithm");
795 		}
796 
797 		keystruct.flags = (uint16_t)rdata1;
798 		keystruct.protocol = (uint8_t)rdata2;
799 		keystruct.algorithm = (uint8_t)rdata3;
800 
801 		if (!dst_algorithm_supported(keystruct.algorithm)) {
802 			CHECK(DST_R_UNSUPPORTEDALG);
803 		}
804 
805 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
806 		CHECK(isc_base64_decodestring(datastr, &databuf));
807 		isc_buffer_usedregion(&databuf, &r);
808 		keystruct.datalen = r.length;
809 		keystruct.data = r.base;
810 
811 		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
812 					   keystruct.common.rdtype, &keystruct,
813 					   &rrdatabuf));
814 		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
815 					  digest, ds));
816 		break;
817 
818 	case INIT_DS:
819 	case STATIC_DS:
820 		if (rdata1 > 0xffff) {
821 			CHECKM(ISC_R_RANGE, "key tag");
822 		}
823 		if (rdata2 > 0xff) {
824 			CHECKM(ISC_R_RANGE, "key algorithm");
825 		}
826 		if (rdata3 > 0xff) {
827 			CHECKM(ISC_R_RANGE, "digest type");
828 		}
829 
830 		ds->key_tag = (uint16_t)rdata1;
831 		ds->algorithm = (uint8_t)rdata2;
832 		ds->digest_type = (uint8_t)rdata3;
833 
834 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
835 		CHECK(isc_hex_decodestring(datastr, &databuf));
836 		isc_buffer_usedregion(&databuf, &r);
837 
838 		switch (ds->digest_type) {
839 		case DNS_DSDIGEST_SHA1:
840 			if (r.length != ISC_SHA1_DIGESTLENGTH) {
841 				CHECK(ISC_R_UNEXPECTEDEND);
842 			}
843 			break;
844 		case DNS_DSDIGEST_SHA256:
845 			if (r.length != ISC_SHA256_DIGESTLENGTH) {
846 				CHECK(ISC_R_UNEXPECTEDEND);
847 			}
848 			break;
849 		case DNS_DSDIGEST_SHA384:
850 			if (r.length != ISC_SHA384_DIGESTLENGTH) {
851 				CHECK(ISC_R_UNEXPECTEDEND);
852 			}
853 			break;
854 		default:
855 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
856 				    "key '%s': "
857 				    "unknown ds digest type %u",
858 				    namestr, ds->digest_type);
859 			result = ISC_R_FAILURE;
860 			goto cleanup;
861 			break;
862 		}
863 
864 		ds->length = r.length;
865 		ds->digest = digest;
866 		memmove(ds->digest, r.base, r.length);
867 
868 		break;
869 
870 	default:
871 		UNREACHABLE();
872 	}
873 
874 	return (ISC_R_SUCCESS);
875 
876 cleanup:
877 	return (result);
878 }
879 
880 /*%
881  * Parse 'key' in the context of view configuration 'vconfig'.  If successful,
882  * add the key to 'secroots' if both of the following conditions are true:
883  *
884  *   - 'keyname_match' is NULL or it matches the owner name of 'key',
885  *   - support for the algorithm used by 'key' is not disabled by 'resolver'
886  *     for the owner name of 'key'.
887  *
888  * 'managed' is true for managed keys and false for trusted keys.  'mctx' is
889  * the memory context to use for allocating memory.
890  */
891 static isc_result_t
process_key(const cfg_obj_t * key,dns_keytable_t * secroots,const dns_name_t * keyname_match,dns_resolver_t * resolver,bool managed)892 process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
893 	    const dns_name_t *keyname_match, dns_resolver_t *resolver,
894 	    bool managed) {
895 	dns_fixedname_t fkeyname;
896 	dns_name_t *keyname = NULL;
897 	const char *namestr = NULL;
898 	dns_rdata_ds_t ds;
899 	isc_result_t result;
900 	bool initializing = managed;
901 	unsigned char digest[ISC_MAX_MD_SIZE];
902 	isc_buffer_t b;
903 
904 	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
905 
906 	switch (result) {
907 	case ISC_R_SUCCESS:
908 		/*
909 		 * Trust anchor was parsed correctly.
910 		 */
911 		isc_buffer_constinit(&b, namestr, strlen(namestr));
912 		isc_buffer_add(&b, strlen(namestr));
913 		keyname = dns_fixedname_initname(&fkeyname);
914 		result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
915 		if (result != ISC_R_SUCCESS) {
916 			return (result);
917 		}
918 		break;
919 	case DST_R_UNSUPPORTEDALG:
920 	case DST_R_BADKEYTYPE:
921 		/*
922 		 * Key was parsed correctly, but it cannot be used; this is not
923 		 * a fatal error - log a warning about this key being ignored,
924 		 * but do not prevent any further ones from being processed.
925 		 */
926 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
927 			    "ignoring %s for '%s': %s",
928 			    initializing ? "initial-key" : "static-key",
929 			    namestr, isc_result_totext(result));
930 		return (ISC_R_SUCCESS);
931 	case DST_R_NOCRYPTO:
932 		/*
933 		 * Crypto support is not available.
934 		 */
935 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
936 			    "ignoring %s for '%s': no crypto support",
937 			    initializing ? "initial-key" : "static-key",
938 			    namestr);
939 		return (result);
940 	default:
941 		/*
942 		 * Something unexpected happened; we have no choice but to
943 		 * indicate an error so that the configuration loading process
944 		 * is interrupted.
945 		 */
946 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
947 			    "configuring %s for '%s': %s",
948 			    initializing ? "initial-key" : "static-key",
949 			    namestr, isc_result_totext(result));
950 		return (ISC_R_FAILURE);
951 	}
952 
953 	/*
954 	 * If the caller requested to only load keys for a specific name and
955 	 * the owner name of this key does not match the requested name, do not
956 	 * load it.
957 	 */
958 	if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) {
959 		goto done;
960 	}
961 
962 	/*
963 	 * Ensure that 'resolver' allows using the algorithm of this key for
964 	 * its owner name.  If it does not, do not load the key and log a
965 	 * warning, but do not prevent further keys from being processed.
966 	 */
967 	if (!dns_resolver_algorithm_supported(resolver, keyname, ds.algorithm))
968 	{
969 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
970 			    "ignoring %s for '%s': algorithm is disabled",
971 			    initializing ? "initial-key" : "static-key",
972 			    namestr);
973 		goto done;
974 	}
975 
976 	/*
977 	 * Add the key to 'secroots'.  Keys from a "trust-anchors" or
978 	 * "managed-keys" statement may be either static or initializing
979 	 * keys. If it's not initializing, we don't want to treat it as
980 	 * managed, so we use 'initializing' twice here, for both the
981 	 * 'managed' and 'initializing' arguments to dns_keytable_add().
982 	 */
983 	result = dns_keytable_add(secroots, initializing, initializing, keyname,
984 				  &ds);
985 
986 done:
987 	return (result);
988 }
989 
990 /*
991  * Load keys from configuration into key table. If 'keyname' is specified,
992  * only load keys matching that name. If 'managed' is true, load the key as
993  * an initializing key.
994  */
995 static isc_result_t
load_view_keys(const cfg_obj_t * keys,dns_view_t * view,bool managed,const dns_name_t * keyname)996 load_view_keys(const cfg_obj_t *keys, dns_view_t *view, bool managed,
997 	       const dns_name_t *keyname) {
998 	const cfg_listelt_t *elt, *elt2;
999 	const cfg_obj_t *keylist;
1000 	isc_result_t result;
1001 	dns_keytable_t *secroots = NULL;
1002 
1003 	CHECK(dns_view_getsecroots(view, &secroots));
1004 
1005 	for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt))
1006 	{
1007 		keylist = cfg_listelt_value(elt);
1008 
1009 		for (elt2 = cfg_list_first(keylist); elt2 != NULL;
1010 		     elt2 = cfg_list_next(elt2))
1011 		{
1012 			CHECK(process_key(cfg_listelt_value(elt2), secroots,
1013 					  keyname, view->resolver, managed));
1014 		}
1015 	}
1016 
1017 cleanup:
1018 	if (secroots != NULL) {
1019 		dns_keytable_detach(&secroots);
1020 	}
1021 	if (result == DST_R_NOCRYPTO) {
1022 		result = ISC_R_SUCCESS;
1023 	}
1024 	return (result);
1025 }
1026 
1027 /*%
1028  * Check whether a key has been successfully loaded.
1029  */
1030 static bool
keyloaded(dns_view_t * view,const dns_name_t * name)1031 keyloaded(dns_view_t *view, const dns_name_t *name) {
1032 	isc_result_t result;
1033 	dns_keytable_t *secroots = NULL;
1034 	dns_keynode_t *keynode = NULL;
1035 
1036 	result = dns_view_getsecroots(view, &secroots);
1037 	if (result != ISC_R_SUCCESS) {
1038 		return (false);
1039 	}
1040 
1041 	result = dns_keytable_find(secroots, name, &keynode);
1042 
1043 	if (keynode != NULL) {
1044 		dns_keytable_detachkeynode(secroots, &keynode);
1045 	}
1046 	if (secroots != NULL) {
1047 		dns_keytable_detach(&secroots);
1048 	}
1049 
1050 	return (result == ISC_R_SUCCESS);
1051 }
1052 
1053 /*%
1054  * Configure DNSSEC keys for a view.
1055  *
1056  * The per-view configuration values and the server-global defaults are read
1057  * from 'vconfig' and 'config'.
1058  */
1059 static isc_result_t
configure_view_dnsseckeys(dns_view_t * view,const cfg_obj_t * vconfig,const cfg_obj_t * config,const cfg_obj_t * bindkeys,bool auto_root,isc_mem_t * mctx)1060 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
1061 			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
1062 			  bool auto_root, isc_mem_t *mctx) {
1063 	isc_result_t result = ISC_R_SUCCESS;
1064 	const cfg_obj_t *view_keys = NULL;
1065 	const cfg_obj_t *global_keys = NULL;
1066 	const cfg_obj_t *view_managed_keys = NULL;
1067 	const cfg_obj_t *view_trust_anchors = NULL;
1068 	const cfg_obj_t *global_managed_keys = NULL;
1069 	const cfg_obj_t *global_trust_anchors = NULL;
1070 	const cfg_obj_t *maps[4];
1071 	const cfg_obj_t *voptions = NULL;
1072 	const cfg_obj_t *options = NULL;
1073 	const cfg_obj_t *obj = NULL;
1074 	const char *directory;
1075 	int i = 0;
1076 
1077 	/* We don't need trust anchors for the _bind view */
1078 	if (strcmp(view->name, "_bind") == 0 &&
1079 	    view->rdclass == dns_rdataclass_chaos)
1080 	{
1081 		return (ISC_R_SUCCESS);
1082 	}
1083 
1084 	if (vconfig != NULL) {
1085 		voptions = cfg_tuple_get(vconfig, "options");
1086 		if (voptions != NULL) {
1087 			(void)cfg_map_get(voptions, "trusted-keys", &view_keys);
1088 
1089 			/* managed-keys and trust-anchors are synonyms. */
1090 			(void)cfg_map_get(voptions, "managed-keys",
1091 					  &view_managed_keys);
1092 			(void)cfg_map_get(voptions, "trust-anchors",
1093 					  &view_trust_anchors);
1094 
1095 			maps[i++] = voptions;
1096 		}
1097 	}
1098 
1099 	if (config != NULL) {
1100 		(void)cfg_map_get(config, "trusted-keys", &global_keys);
1101 
1102 		/* managed-keys and trust-anchors are synonyms. */
1103 		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
1104 		(void)cfg_map_get(config, "trust-anchors",
1105 				  &global_trust_anchors);
1106 
1107 		(void)cfg_map_get(config, "options", &options);
1108 		if (options != NULL) {
1109 			maps[i++] = options;
1110 		}
1111 	}
1112 
1113 	maps[i++] = named_g_defaults;
1114 	maps[i] = NULL;
1115 
1116 	result = dns_view_initsecroots(view, mctx);
1117 	if (result != ISC_R_SUCCESS) {
1118 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1119 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1120 			      "couldn't create keytable");
1121 		return (ISC_R_UNEXPECTED);
1122 	}
1123 
1124 	result = dns_view_initntatable(view, named_g_taskmgr, named_g_timermgr);
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 NTA table");
1129 		return (ISC_R_UNEXPECTED);
1130 	}
1131 
1132 	if (auto_root && view->rdclass == dns_rdataclass_in) {
1133 		const cfg_obj_t *builtin_keys = NULL;
1134 
1135 		/*
1136 		 * If bind.keys exists and is populated, it overrides
1137 		 * the trust-anchors clause hard-coded in named_g_config.
1138 		 */
1139 		if (bindkeys != NULL) {
1140 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1141 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1142 				      "obtaining root key for view %s "
1143 				      "from '%s'",
1144 				      view->name, named_g_server->bindkeysfile);
1145 
1146 			(void)cfg_map_get(bindkeys, "trust-anchors",
1147 					  &builtin_keys);
1148 
1149 			if (builtin_keys == NULL) {
1150 				isc_log_write(
1151 					named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1152 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
1153 					"dnssec-validation auto: "
1154 					"WARNING: root zone key "
1155 					"not found");
1156 			}
1157 		}
1158 
1159 		if (builtin_keys == NULL) {
1160 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1161 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1162 				      "using built-in root key for view %s",
1163 				      view->name);
1164 
1165 			(void)cfg_map_get(named_g_config, "trust-anchors",
1166 					  &builtin_keys);
1167 		}
1168 
1169 		if (builtin_keys != NULL) {
1170 			CHECK(load_view_keys(builtin_keys, view, true,
1171 					     dns_rootname));
1172 		}
1173 
1174 		if (!keyloaded(view, dns_rootname)) {
1175 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1176 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1177 				      "root key not loaded");
1178 			result = ISC_R_FAILURE;
1179 			goto cleanup;
1180 		}
1181 	}
1182 
1183 	if (view->rdclass == dns_rdataclass_in) {
1184 		CHECK(load_view_keys(view_keys, view, false, NULL));
1185 		CHECK(load_view_keys(view_trust_anchors, view, true, NULL));
1186 		CHECK(load_view_keys(view_managed_keys, view, true, NULL));
1187 
1188 		CHECK(load_view_keys(global_keys, view, false, NULL));
1189 		CHECK(load_view_keys(global_trust_anchors, view, true, NULL));
1190 		CHECK(load_view_keys(global_managed_keys, view, true, NULL));
1191 	}
1192 
1193 	/*
1194 	 * Add key zone for managed keys.
1195 	 */
1196 	obj = NULL;
1197 	(void)named_config_get(maps, "managed-keys-directory", &obj);
1198 	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
1199 	if (directory != NULL) {
1200 		result = isc_file_isdirectory(directory);
1201 	}
1202 	if (result != ISC_R_SUCCESS) {
1203 		isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1204 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1205 			      "invalid managed-keys-directory %s: %s",
1206 			      directory, isc_result_totext(result));
1207 		goto cleanup;
1208 	} else if (directory != NULL) {
1209 		if (!isc_file_isdirwritable(directory)) {
1210 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1211 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1212 				      "managed-keys-directory '%s' "
1213 				      "is not writable",
1214 				      directory);
1215 			result = ISC_R_NOPERM;
1216 			goto cleanup;
1217 		}
1218 	}
1219 
1220 	CHECK(add_keydata_zone(view, directory, named_g_mctx));
1221 
1222 cleanup:
1223 	return (result);
1224 }
1225 
1226 static isc_result_t
mustbesecure(const cfg_obj_t * mbs,dns_resolver_t * resolver)1227 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
1228 	const cfg_listelt_t *element;
1229 	const cfg_obj_t *obj;
1230 	const char *str;
1231 	dns_fixedname_t fixed;
1232 	dns_name_t *name;
1233 	bool value;
1234 	isc_result_t result;
1235 	isc_buffer_t b;
1236 
1237 	name = dns_fixedname_initname(&fixed);
1238 	for (element = cfg_list_first(mbs); element != NULL;
1239 	     element = cfg_list_next(element))
1240 	{
1241 		obj = cfg_listelt_value(element);
1242 		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
1243 		isc_buffer_constinit(&b, str, strlen(str));
1244 		isc_buffer_add(&b, strlen(str));
1245 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1246 		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
1247 		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
1248 	}
1249 
1250 	result = ISC_R_SUCCESS;
1251 
1252 cleanup:
1253 	return (result);
1254 }
1255 
1256 /*%
1257  * Get a dispatch appropriate for the resolver of a given view.
1258  */
1259 static isc_result_t
get_view_querysource_dispatch(const cfg_obj_t ** maps,int af,dns_dispatch_t ** dispatchp,isc_dscp_t * dscpp,bool is_firstview)1260 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
1261 			      dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
1262 			      bool is_firstview) {
1263 	isc_result_t result = ISC_R_FAILURE;
1264 	dns_dispatch_t *disp;
1265 	isc_sockaddr_t sa;
1266 	unsigned int attrs, attrmask;
1267 	const cfg_obj_t *obj = NULL;
1268 	unsigned int maxdispatchbuffers = UDPBUFFERS;
1269 	isc_dscp_t dscp = -1;
1270 
1271 	switch (af) {
1272 	case AF_INET:
1273 		result = named_config_get(maps, "query-source", &obj);
1274 		INSIST(result == ISC_R_SUCCESS);
1275 		break;
1276 	case AF_INET6:
1277 		result = named_config_get(maps, "query-source-v6", &obj);
1278 		INSIST(result == ISC_R_SUCCESS);
1279 		break;
1280 	default:
1281 		UNREACHABLE();
1282 	}
1283 
1284 	sa = *(cfg_obj_assockaddr(obj));
1285 	INSIST(isc_sockaddr_pf(&sa) == af);
1286 
1287 	dscp = cfg_obj_getdscp(obj);
1288 	if (dscp != -1 && dscpp != NULL) {
1289 		*dscpp = dscp;
1290 	}
1291 
1292 	/*
1293 	 * If we don't support this address family, we're done!
1294 	 */
1295 	switch (af) {
1296 	case AF_INET:
1297 		result = isc_net_probeipv4();
1298 		break;
1299 	case AF_INET6:
1300 		result = isc_net_probeipv6();
1301 		break;
1302 	default:
1303 		UNREACHABLE();
1304 	}
1305 	if (result != ISC_R_SUCCESS) {
1306 		return (ISC_R_SUCCESS);
1307 	}
1308 
1309 	/*
1310 	 * Try to find a dispatcher that we can share.
1311 	 */
1312 	attrs = 0;
1313 	attrs |= DNS_DISPATCHATTR_UDP;
1314 	switch (af) {
1315 	case AF_INET:
1316 		attrs |= DNS_DISPATCHATTR_IPV4;
1317 		break;
1318 	case AF_INET6:
1319 		attrs |= DNS_DISPATCHATTR_IPV6;
1320 		break;
1321 	}
1322 	if (isc_sockaddr_getport(&sa) == 0) {
1323 		attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
1324 		maxdispatchbuffers = EXCLBUFFERS;
1325 	} else {
1326 		INSIST(obj != NULL);
1327 		if (is_firstview) {
1328 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
1329 				    "using specific query-source port "
1330 				    "suppresses port randomization and can be "
1331 				    "insecure.");
1332 		}
1333 	}
1334 
1335 	attrmask = 0;
1336 	attrmask |= DNS_DISPATCHATTR_UDP;
1337 	attrmask |= DNS_DISPATCHATTR_TCP;
1338 	attrmask |= DNS_DISPATCHATTR_IPV4;
1339 	attrmask |= DNS_DISPATCHATTR_IPV6;
1340 
1341 	disp = NULL;
1342 	result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr,
1343 				     named_g_taskmgr, &sa, 4096,
1344 				     maxdispatchbuffers, 32768, 16411, 16433,
1345 				     attrs, attrmask, &disp);
1346 	if (result != ISC_R_SUCCESS) {
1347 		isc_sockaddr_t any;
1348 		char buf[ISC_SOCKADDR_FORMATSIZE];
1349 
1350 		switch (af) {
1351 		case AF_INET:
1352 			isc_sockaddr_any(&any);
1353 			break;
1354 		case AF_INET6:
1355 			isc_sockaddr_any6(&any);
1356 			break;
1357 		}
1358 		if (isc_sockaddr_equal(&sa, &any)) {
1359 			return (ISC_R_SUCCESS);
1360 		}
1361 		isc_sockaddr_format(&sa, buf, sizeof(buf));
1362 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1363 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1364 			      "could not get query source dispatcher (%s)",
1365 			      buf);
1366 		return (result);
1367 	}
1368 
1369 	*dispatchp = disp;
1370 
1371 	return (ISC_R_SUCCESS);
1372 }
1373 
1374 static isc_result_t
configure_order(dns_order_t * order,const cfg_obj_t * ent)1375 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1376 	dns_rdataclass_t rdclass;
1377 	dns_rdatatype_t rdtype;
1378 	const cfg_obj_t *obj;
1379 	dns_fixedname_t fixed;
1380 	unsigned int mode = 0;
1381 	const char *str;
1382 	isc_buffer_t b;
1383 	isc_result_t result;
1384 	bool addroot;
1385 
1386 	result = named_config_getclass(cfg_tuple_get(ent, "class"),
1387 				       dns_rdataclass_any, &rdclass);
1388 	if (result != ISC_R_SUCCESS) {
1389 		return (result);
1390 	}
1391 
1392 	result = named_config_gettype(cfg_tuple_get(ent, "type"),
1393 				      dns_rdatatype_any, &rdtype);
1394 	if (result != ISC_R_SUCCESS) {
1395 		return (result);
1396 	}
1397 
1398 	obj = cfg_tuple_get(ent, "name");
1399 	if (cfg_obj_isstring(obj)) {
1400 		str = cfg_obj_asstring(obj);
1401 	} else {
1402 		str = "*";
1403 	}
1404 	addroot = (strcmp(str, "*") == 0);
1405 	isc_buffer_constinit(&b, str, strlen(str));
1406 	isc_buffer_add(&b, strlen(str));
1407 	dns_fixedname_init(&fixed);
1408 	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, dns_rootname,
1409 				   0, NULL);
1410 	if (result != ISC_R_SUCCESS) {
1411 		return (result);
1412 	}
1413 
1414 	obj = cfg_tuple_get(ent, "ordering");
1415 	INSIST(cfg_obj_isstring(obj));
1416 	str = cfg_obj_asstring(obj);
1417 	if (!strcasecmp(str, "fixed")) {
1418 #if DNS_RDATASET_FIXED
1419 		mode = DNS_RDATASETATTR_FIXEDORDER;
1420 #else  /* if DNS_RDATASET_FIXED */
1421 		mode = DNS_RDATASETATTR_CYCLIC;
1422 #endif /* DNS_RDATASET_FIXED */
1423 	} else if (!strcasecmp(str, "random")) {
1424 		mode = DNS_RDATASETATTR_RANDOMIZE;
1425 	} else if (!strcasecmp(str, "cyclic")) {
1426 		mode = DNS_RDATASETATTR_CYCLIC;
1427 	} else if (!strcasecmp(str, "none")) {
1428 		mode = DNS_RDATASETATTR_NONE;
1429 	} else {
1430 		UNREACHABLE();
1431 	}
1432 
1433 	/*
1434 	 * "*" should match everything including the root (BIND 8 compat).
1435 	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1436 	 * explicit entry for "." when the name is "*".
1437 	 */
1438 	if (addroot) {
1439 		result = dns_order_add(order, dns_rootname, rdtype, rdclass,
1440 				       mode);
1441 		if (result != ISC_R_SUCCESS) {
1442 			return (result);
1443 		}
1444 	}
1445 
1446 	return (dns_order_add(order, dns_fixedname_name(&fixed), rdtype,
1447 			      rdclass, mode));
1448 }
1449 
1450 static isc_result_t
configure_peer(const cfg_obj_t * cpeer,isc_mem_t * mctx,dns_peer_t ** peerp)1451 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1452 	isc_netaddr_t na;
1453 	dns_peer_t *peer;
1454 	const cfg_obj_t *obj;
1455 	const char *str;
1456 	isc_result_t result;
1457 	unsigned int prefixlen;
1458 
1459 	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1460 
1461 	peer = NULL;
1462 	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1463 	if (result != ISC_R_SUCCESS) {
1464 		return (result);
1465 	}
1466 
1467 	obj = NULL;
1468 	(void)cfg_map_get(cpeer, "bogus", &obj);
1469 	if (obj != NULL) {
1470 		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1471 	}
1472 
1473 	obj = NULL;
1474 	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1475 	if (obj != NULL) {
1476 		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1477 	}
1478 
1479 	obj = NULL;
1480 	(void)cfg_map_get(cpeer, "request-expire", &obj);
1481 	if (obj != NULL) {
1482 		CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
1483 	}
1484 
1485 	obj = NULL;
1486 	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
1487 	if (obj != NULL) {
1488 		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1489 	}
1490 
1491 	obj = NULL;
1492 	(void)cfg_map_get(cpeer, "request-nsid", &obj);
1493 	if (obj != NULL) {
1494 		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1495 	}
1496 
1497 	obj = NULL;
1498 	(void)cfg_map_get(cpeer, "send-cookie", &obj);
1499 	if (obj != NULL) {
1500 		CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj)));
1501 	}
1502 
1503 	obj = NULL;
1504 	(void)cfg_map_get(cpeer, "edns", &obj);
1505 	if (obj != NULL) {
1506 		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1507 	}
1508 
1509 	obj = NULL;
1510 	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1511 	if (obj != NULL) {
1512 		uint32_t udpsize = cfg_obj_asuint32(obj);
1513 		if (udpsize < 512U) {
1514 			udpsize = 512U;
1515 		}
1516 		if (udpsize > 4096U) {
1517 			udpsize = 4096U;
1518 		}
1519 		CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize));
1520 	}
1521 
1522 	obj = NULL;
1523 	(void)cfg_map_get(cpeer, "edns-version", &obj);
1524 	if (obj != NULL) {
1525 		uint32_t ednsversion = cfg_obj_asuint32(obj);
1526 		if (ednsversion > 255U) {
1527 			ednsversion = 255U;
1528 		}
1529 		CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion));
1530 	}
1531 
1532 	obj = NULL;
1533 	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
1534 	if (obj != NULL) {
1535 		uint32_t udpsize = cfg_obj_asuint32(obj);
1536 		if (udpsize < 512U) {
1537 			udpsize = 512U;
1538 		}
1539 		if (udpsize > 4096U) {
1540 			udpsize = 4096U;
1541 		}
1542 		CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize));
1543 	}
1544 
1545 	obj = NULL;
1546 	(void)cfg_map_get(cpeer, "padding", &obj);
1547 	if (obj != NULL) {
1548 		uint32_t padding = cfg_obj_asuint32(obj);
1549 		if (padding > 512U) {
1550 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
1551 				    "server padding value cannot "
1552 				    "exceed 512: lowering");
1553 			padding = 512U;
1554 		}
1555 		CHECK(dns_peer_setpadding(peer, (uint16_t)padding));
1556 	}
1557 
1558 	obj = NULL;
1559 	(void)cfg_map_get(cpeer, "tcp-only", &obj);
1560 	if (obj != NULL) {
1561 		CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
1562 	}
1563 
1564 	obj = NULL;
1565 	(void)cfg_map_get(cpeer, "tcp-keepalive", &obj);
1566 	if (obj != NULL) {
1567 		CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj)));
1568 	}
1569 
1570 	obj = NULL;
1571 	(void)cfg_map_get(cpeer, "transfers", &obj);
1572 	if (obj != NULL) {
1573 		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1574 	}
1575 
1576 	obj = NULL;
1577 	(void)cfg_map_get(cpeer, "transfer-format", &obj);
1578 	if (obj != NULL) {
1579 		str = cfg_obj_asstring(obj);
1580 		if (strcasecmp(str, "many-answers") == 0) {
1581 			CHECK(dns_peer_settransferformat(peer,
1582 							 dns_many_answers));
1583 		} else if (strcasecmp(str, "one-answer") == 0) {
1584 			CHECK(dns_peer_settransferformat(peer, dns_one_answer));
1585 		} else {
1586 			UNREACHABLE();
1587 		}
1588 	}
1589 
1590 	obj = NULL;
1591 	(void)cfg_map_get(cpeer, "keys", &obj);
1592 	if (obj != NULL) {
1593 		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1594 		if (result != ISC_R_SUCCESS) {
1595 			goto cleanup;
1596 		}
1597 	}
1598 
1599 	obj = NULL;
1600 	if (na.family == AF_INET) {
1601 		(void)cfg_map_get(cpeer, "transfer-source", &obj);
1602 	} else {
1603 		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1604 	}
1605 	if (obj != NULL) {
1606 		result = dns_peer_settransfersource(peer,
1607 						    cfg_obj_assockaddr(obj));
1608 		if (result != ISC_R_SUCCESS) {
1609 			goto cleanup;
1610 		}
1611 		result = dns_peer_settransferdscp(peer, cfg_obj_getdscp(obj));
1612 		if (result != ISC_R_SUCCESS) {
1613 			goto cleanup;
1614 		}
1615 		named_add_reserved_dispatch(named_g_server,
1616 					    cfg_obj_assockaddr(obj));
1617 	}
1618 
1619 	obj = NULL;
1620 	if (na.family == AF_INET) {
1621 		(void)cfg_map_get(cpeer, "notify-source", &obj);
1622 	} else {
1623 		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1624 	}
1625 	if (obj != NULL) {
1626 		result = dns_peer_setnotifysource(peer,
1627 						  cfg_obj_assockaddr(obj));
1628 		if (result != ISC_R_SUCCESS) {
1629 			goto cleanup;
1630 		}
1631 		result = dns_peer_setnotifydscp(peer, cfg_obj_getdscp(obj));
1632 		if (result != ISC_R_SUCCESS) {
1633 			goto cleanup;
1634 		}
1635 		named_add_reserved_dispatch(named_g_server,
1636 					    cfg_obj_assockaddr(obj));
1637 	}
1638 
1639 	obj = NULL;
1640 	if (na.family == AF_INET) {
1641 		(void)cfg_map_get(cpeer, "query-source", &obj);
1642 	} else {
1643 		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
1644 	}
1645 	if (obj != NULL) {
1646 		result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj));
1647 		if (result != ISC_R_SUCCESS) {
1648 			goto cleanup;
1649 		}
1650 		result = dns_peer_setquerydscp(peer, cfg_obj_getdscp(obj));
1651 		if (result != ISC_R_SUCCESS) {
1652 			goto cleanup;
1653 		}
1654 		named_add_reserved_dispatch(named_g_server,
1655 					    cfg_obj_assockaddr(obj));
1656 	}
1657 
1658 	*peerp = peer;
1659 	return (ISC_R_SUCCESS);
1660 
1661 cleanup:
1662 	dns_peer_detach(&peer);
1663 	return (result);
1664 }
1665 
1666 #ifdef HAVE_DLOPEN
1667 static isc_result_t
configure_dyndb(const cfg_obj_t * dyndb,isc_mem_t * mctx,const dns_dyndbctx_t * dctx)1668 configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
1669 		const dns_dyndbctx_t *dctx) {
1670 	isc_result_t result = ISC_R_SUCCESS;
1671 	const cfg_obj_t *obj;
1672 	const char *name, *library;
1673 
1674 	/* Get the name of the dyndb instance and the library path . */
1675 	name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name"));
1676 	library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library"));
1677 
1678 	obj = cfg_tuple_get(dyndb, "parameters");
1679 	if (obj != NULL) {
1680 		result = dns_dyndb_load(library, name, cfg_obj_asstring(obj),
1681 					cfg_obj_file(obj), cfg_obj_line(obj),
1682 					mctx, dctx);
1683 	}
1684 
1685 	if (result != ISC_R_SUCCESS) {
1686 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1687 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1688 			      "dynamic database '%s' configuration failed: %s",
1689 			      name, isc_result_totext(result));
1690 	}
1691 	return (result);
1692 }
1693 #endif /* ifdef HAVE_DLOPEN */
1694 
1695 static isc_result_t
disable_algorithms(const cfg_obj_t * disabled,dns_resolver_t * resolver)1696 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1697 	isc_result_t result;
1698 	const cfg_obj_t *algorithms;
1699 	const cfg_listelt_t *element;
1700 	const char *str;
1701 	dns_fixedname_t fixed;
1702 	dns_name_t *name;
1703 	isc_buffer_t b;
1704 
1705 	name = dns_fixedname_initname(&fixed);
1706 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1707 	isc_buffer_constinit(&b, str, strlen(str));
1708 	isc_buffer_add(&b, strlen(str));
1709 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1710 
1711 	algorithms = cfg_tuple_get(disabled, "algorithms");
1712 	for (element = cfg_list_first(algorithms); element != NULL;
1713 	     element = cfg_list_next(element))
1714 	{
1715 		isc_textregion_t r;
1716 		dns_secalg_t alg;
1717 
1718 		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1719 		r.length = strlen(r.base);
1720 
1721 		result = dns_secalg_fromtext(&alg, &r);
1722 		if (result != ISC_R_SUCCESS) {
1723 			uint8_t ui;
1724 			result = isc_parse_uint8(&ui, r.base, 10);
1725 			alg = ui;
1726 		}
1727 		if (result != ISC_R_SUCCESS) {
1728 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1729 				    ISC_LOG_ERROR, "invalid algorithm");
1730 			CHECK(result);
1731 		}
1732 		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1733 	}
1734 cleanup:
1735 	return (result);
1736 }
1737 
1738 static isc_result_t
disable_ds_digests(const cfg_obj_t * disabled,dns_resolver_t * resolver)1739 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1740 	isc_result_t result;
1741 	const cfg_obj_t *digests;
1742 	const cfg_listelt_t *element;
1743 	const char *str;
1744 	dns_fixedname_t fixed;
1745 	dns_name_t *name;
1746 	isc_buffer_t b;
1747 
1748 	name = dns_fixedname_initname(&fixed);
1749 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1750 	isc_buffer_constinit(&b, str, strlen(str));
1751 	isc_buffer_add(&b, strlen(str));
1752 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1753 
1754 	digests = cfg_tuple_get(disabled, "digests");
1755 	for (element = cfg_list_first(digests); element != NULL;
1756 	     element = cfg_list_next(element))
1757 	{
1758 		isc_textregion_t r;
1759 		dns_dsdigest_t digest;
1760 
1761 		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1762 		r.length = strlen(r.base);
1763 
1764 		/* disable_ds_digests handles numeric values. */
1765 		result = dns_dsdigest_fromtext(&digest, &r);
1766 		if (result != ISC_R_SUCCESS) {
1767 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1768 				    ISC_LOG_ERROR, "invalid algorithm");
1769 			CHECK(result);
1770 		}
1771 		CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
1772 	}
1773 cleanup:
1774 	return (result);
1775 }
1776 
1777 static bool
on_disable_list(const cfg_obj_t * disablelist,dns_name_t * zonename)1778 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1779 	const cfg_listelt_t *element;
1780 	dns_fixedname_t fixed;
1781 	dns_name_t *name;
1782 	isc_result_t result;
1783 	const cfg_obj_t *value;
1784 	const char *str;
1785 	isc_buffer_t b;
1786 
1787 	name = dns_fixedname_initname(&fixed);
1788 
1789 	for (element = cfg_list_first(disablelist); element != NULL;
1790 	     element = cfg_list_next(element))
1791 	{
1792 		value = cfg_listelt_value(element);
1793 		str = cfg_obj_asstring(value);
1794 		isc_buffer_constinit(&b, str, strlen(str));
1795 		isc_buffer_add(&b, strlen(str));
1796 		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
1797 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1798 		if (dns_name_equal(name, zonename)) {
1799 			return (true);
1800 		}
1801 	}
1802 	return (false);
1803 }
1804 
1805 static isc_result_t
check_dbtype(dns_zone_t * zone,unsigned int dbtypec,const char ** dbargv,isc_mem_t * mctx)1806 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
1807 	     isc_mem_t *mctx) {
1808 	char **argv = NULL;
1809 	unsigned int i;
1810 	isc_result_t result = ISC_R_SUCCESS;
1811 
1812 	CHECK(dns_zone_getdbtype(zone, &argv, mctx));
1813 
1814 	/*
1815 	 * Check that all the arguments match.
1816 	 */
1817 	for (i = 0; i < dbtypec; i++) {
1818 		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
1819 			CHECK(ISC_R_FAILURE);
1820 
1821 			/*
1822 			 * Check that there are not extra arguments.
1823 			 */
1824 		}
1825 	}
1826 
1827 	/*
1828 	 * Check that there are not extra arguments.
1829 	 */
1830 	if (i == dbtypec && argv[i] != NULL) {
1831 		result = ISC_R_FAILURE;
1832 	}
1833 
1834 cleanup:
1835 	isc_mem_free(mctx, argv);
1836 	return (result);
1837 }
1838 
1839 static isc_result_t
setquerystats(dns_zone_t * zone,isc_mem_t * mctx,dns_zonestat_level_t level)1840 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
1841 	isc_result_t result;
1842 	isc_stats_t *zoneqrystats;
1843 
1844 	dns_zone_setstatlevel(zone, level);
1845 
1846 	zoneqrystats = NULL;
1847 	if (level == dns_zonestat_full) {
1848 		result = isc_stats_create(mctx, &zoneqrystats,
1849 					  ns_statscounter_max);
1850 		if (result != ISC_R_SUCCESS) {
1851 			return (result);
1852 		}
1853 	}
1854 	dns_zone_setrequeststats(zone, zoneqrystats);
1855 	if (zoneqrystats != NULL) {
1856 		isc_stats_detach(&zoneqrystats);
1857 	}
1858 
1859 	return (ISC_R_SUCCESS);
1860 }
1861 
1862 static named_cache_t *
cachelist_find(named_cachelist_t * cachelist,const char * cachename,dns_rdataclass_t rdclass)1863 cachelist_find(named_cachelist_t *cachelist, const char *cachename,
1864 	       dns_rdataclass_t rdclass) {
1865 	named_cache_t *nsc;
1866 
1867 	for (nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
1868 	     nsc = ISC_LIST_NEXT(nsc, link))
1869 	{
1870 		if (nsc->rdclass == rdclass &&
1871 		    strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1872 		{
1873 			return (nsc);
1874 		}
1875 	}
1876 
1877 	return (NULL);
1878 }
1879 
1880 static bool
cache_reusable(dns_view_t * originview,dns_view_t * view,bool new_zero_no_soattl)1881 cache_reusable(dns_view_t *originview, dns_view_t *view,
1882 	       bool new_zero_no_soattl) {
1883 	if (originview->rdclass != view->rdclass ||
1884 	    originview->checknames != view->checknames ||
1885 	    dns_resolver_getzeronosoattl(originview->resolver) !=
1886 		    new_zero_no_soattl ||
1887 	    originview->acceptexpired != view->acceptexpired ||
1888 	    originview->enablevalidation != view->enablevalidation ||
1889 	    originview->maxcachettl != view->maxcachettl ||
1890 	    originview->maxncachettl != view->maxncachettl)
1891 	{
1892 		return (false);
1893 	}
1894 
1895 	return (true);
1896 }
1897 
1898 static bool
cache_sharable(dns_view_t * originview,dns_view_t * view,bool new_zero_no_soattl,uint64_t new_max_cache_size,uint32_t new_stale_ttl,uint32_t new_stale_refresh_time)1899 cache_sharable(dns_view_t *originview, dns_view_t *view,
1900 	       bool new_zero_no_soattl, uint64_t new_max_cache_size,
1901 	       uint32_t new_stale_ttl, uint32_t new_stale_refresh_time) {
1902 	/*
1903 	 * If the cache cannot even reused for the same view, it cannot be
1904 	 * shared with other views.
1905 	 */
1906 	if (!cache_reusable(originview, view, new_zero_no_soattl)) {
1907 		return (false);
1908 	}
1909 
1910 	/*
1911 	 * Check other cache related parameters that must be consistent among
1912 	 * the sharing views.
1913 	 */
1914 	if (dns_cache_getservestalettl(originview->cache) != new_stale_ttl ||
1915 	    dns_cache_getservestalerefresh(originview->cache) !=
1916 		    new_stale_refresh_time ||
1917 	    dns_cache_getcachesize(originview->cache) != new_max_cache_size)
1918 	{
1919 		return (false);
1920 	}
1921 
1922 	return (true);
1923 }
1924 
1925 /*
1926  * Callback from DLZ configure when the driver sets up a writeable zone
1927  */
1928 static isc_result_t
dlzconfigure_callback(dns_view_t * view,dns_dlzdb_t * dlzdb,dns_zone_t * zone)1929 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
1930 	dns_name_t *origin = dns_zone_getorigin(zone);
1931 	dns_rdataclass_t zclass = view->rdclass;
1932 	isc_result_t result;
1933 
1934 	result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
1935 	if (result != ISC_R_SUCCESS) {
1936 		return (result);
1937 	}
1938 	dns_zone_setstats(zone, named_g_server->zonestats);
1939 
1940 	return (named_zone_configure_writeable_dlz(dlzdb, zone, zclass,
1941 						   origin));
1942 }
1943 
1944 static isc_result_t
dns64_reverse(dns_view_t * view,isc_mem_t * mctx,isc_netaddr_t * na,unsigned int prefixlen,const char * server,const char * contact)1945 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1946 	      unsigned int prefixlen, const char *server, const char *contact) {
1947 	char reverse[48 + sizeof("ip6.arpa.")] = { 0 };
1948 	char buf[sizeof("x.x.")];
1949 	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1950 	const char *sep = ": view ";
1951 	const char *viewname = view->name;
1952 	const unsigned char *s6;
1953 	dns_fixedname_t fixed;
1954 	dns_name_t *name;
1955 	dns_zone_t *zone = NULL;
1956 	int dns64_dbtypec = 4;
1957 	isc_buffer_t b;
1958 	isc_result_t result;
1959 
1960 	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1961 		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1962 
1963 	if (!strcmp(viewname, "_default")) {
1964 		sep = "";
1965 		viewname = "";
1966 	}
1967 
1968 	/*
1969 	 * Construct the reverse name of the zone.
1970 	 */
1971 	s6 = na->type.in6.s6_addr;
1972 	while (prefixlen > 0) {
1973 		prefixlen -= 8;
1974 		snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen / 8] & 0xf,
1975 			 (s6[prefixlen / 8] >> 4) & 0xf);
1976 		strlcat(reverse, buf, sizeof(reverse));
1977 	}
1978 	strlcat(reverse, "ip6.arpa.", sizeof(reverse));
1979 
1980 	/*
1981 	 * Create the actual zone.
1982 	 */
1983 	if (server != NULL) {
1984 		dns64_dbtype[2] = server;
1985 	}
1986 	if (contact != NULL) {
1987 		dns64_dbtype[3] = contact;
1988 	}
1989 	name = dns_fixedname_initname(&fixed);
1990 	isc_buffer_constinit(&b, reverse, strlen(reverse));
1991 	isc_buffer_add(&b, strlen(reverse));
1992 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1993 	CHECK(dns_zone_create(&zone, mctx));
1994 	CHECK(dns_zone_setorigin(zone, name));
1995 	dns_zone_setview(zone, view);
1996 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
1997 	dns_zone_setclass(zone, view->rdclass);
1998 	dns_zone_settype(zone, dns_zone_primary);
1999 	dns_zone_setstats(zone, named_g_server->zonestats);
2000 	dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype);
2001 	if (view->queryacl != NULL) {
2002 		dns_zone_setqueryacl(zone, view->queryacl);
2003 	}
2004 	if (view->queryonacl != NULL) {
2005 		dns_zone_setqueryonacl(zone, view->queryonacl);
2006 	}
2007 	dns_zone_setdialup(zone, dns_dialuptype_no);
2008 	dns_zone_setnotifytype(zone, dns_notifytype_no);
2009 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
2010 	CHECK(setquerystats(zone, mctx, dns_zonestat_none)); /* XXXMPA */
2011 	CHECK(dns_view_addzone(view, zone));
2012 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2013 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
2014 		      "dns64 reverse zone%s%s: %s", sep, viewname, reverse);
2015 
2016 cleanup:
2017 	if (zone != NULL) {
2018 		dns_zone_detach(&zone);
2019 	}
2020 	return (result);
2021 }
2022 
2023 #ifdef USE_DNSRPS
2024 typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
2025 struct conf_dnsrps_ctx {
2026 	isc_result_t result;
2027 	char *cstr;
2028 	size_t cstr_size;
2029 	isc_mem_t *mctx;
2030 };
2031 
2032 /*
2033  * Add to the DNSRPS configuration string.
2034  */
2035 static bool
conf_dnsrps_sadd(conf_dnsrps_ctx_t * ctx,const char * p,...)2036 conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
2037 	size_t new_len, cur_len, new_cstr_size;
2038 	char *new_cstr;
2039 	va_list args;
2040 
2041 	if (ctx->cstr == NULL) {
2042 		ctx->cstr = isc_mem_get(ctx->mctx, 256);
2043 		ctx->cstr[0] = '\0';
2044 		ctx->cstr_size = 256;
2045 	}
2046 
2047 	cur_len = strlen(ctx->cstr);
2048 	va_start(args, p);
2049 	new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p,
2050 			    args) +
2051 		  1;
2052 	va_end(args);
2053 
2054 	if (cur_len + new_len <= ctx->cstr_size) {
2055 		return (true);
2056 	}
2057 
2058 	new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256;
2059 	new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
2060 
2061 	memmove(new_cstr, ctx->cstr, cur_len);
2062 	isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
2063 	ctx->cstr_size = new_cstr_size;
2064 	ctx->cstr = new_cstr;
2065 
2066 	/* cannot use args twice after a single va_start()on some systems */
2067 	va_start(args, p);
2068 	vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
2069 	va_end(args);
2070 	return (true);
2071 }
2072 
2073 /*
2074  * Get an DNSRPS configuration value using the global and view options
2075  * for the default.  Return false upon failure.
2076  */
2077 static bool
conf_dnsrps_get(const cfg_obj_t ** sub_obj,const cfg_obj_t ** maps,const cfg_obj_t * obj,const char * name,conf_dnsrps_ctx_t * ctx)2078 conf_dnsrps_get(const cfg_obj_t **sub_obj, const cfg_obj_t **maps,
2079 		const cfg_obj_t *obj, const char *name,
2080 		conf_dnsrps_ctx_t *ctx) {
2081 	if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
2082 		*sub_obj = NULL;
2083 		return (false);
2084 	}
2085 
2086 	*sub_obj = cfg_tuple_get(obj, name);
2087 	if (cfg_obj_isvoid(*sub_obj)) {
2088 		*sub_obj = NULL;
2089 		if (maps != NULL &&
2090 		    ISC_R_SUCCESS != named_config_get(maps, name, sub_obj))
2091 		{
2092 			*sub_obj = NULL;
2093 		}
2094 	}
2095 	return (true);
2096 }
2097 
2098 /*
2099  * Handle a DNSRPS boolean configuration value with the global and view
2100  * options providing the default.
2101  */
2102 static void
conf_dnsrps_yes_no(const cfg_obj_t * obj,const char * name,conf_dnsrps_ctx_t * ctx)2103 conf_dnsrps_yes_no(const cfg_obj_t *obj, const char *name,
2104 		   conf_dnsrps_ctx_t *ctx) {
2105 	const cfg_obj_t *sub_obj;
2106 
2107 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2108 		return;
2109 	}
2110 	if (sub_obj == NULL) {
2111 		return;
2112 	}
2113 	if (ctx == NULL) {
2114 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2115 			    "\"%s\" without \"dnsrps-enable yes\"", name);
2116 		return;
2117 	}
2118 
2119 	conf_dnsrps_sadd(ctx, " %s %s", name,
2120 			 cfg_obj_asboolean(sub_obj) ? "yes" : "no");
2121 }
2122 
2123 static void
conf_dnsrps_num(const cfg_obj_t * obj,const char * name,conf_dnsrps_ctx_t * ctx)2124 conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
2125 		conf_dnsrps_ctx_t *ctx) {
2126 	const cfg_obj_t *sub_obj;
2127 
2128 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2129 		return;
2130 	}
2131 	if (sub_obj == NULL) {
2132 		return;
2133 	}
2134 	if (ctx == NULL) {
2135 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2136 			    "\"%s\" without \"dnsrps-enable yes\"", name);
2137 		return;
2138 	}
2139 
2140 	if (cfg_obj_isduration(sub_obj)) {
2141 		conf_dnsrps_sadd(ctx, " %s %d", name,
2142 				 cfg_obj_asduration(sub_obj));
2143 	} else {
2144 		conf_dnsrps_sadd(ctx, " %s %d", name,
2145 				 cfg_obj_asuint32(sub_obj));
2146 	}
2147 }
2148 
2149 /*
2150  * Convert the parsed RPZ configuration statement to a string for
2151  * dns_rpz_new_zones().
2152  */
2153 static isc_result_t
conf_dnsrps(dns_view_t * view,const cfg_obj_t ** maps,bool nsip_enabled,bool nsdname_enabled,dns_rpz_zbits_t * nsip_on,dns_rpz_zbits_t * nsdname_on,char ** rps_cstr,size_t * rps_cstr_size,const cfg_obj_t * rpz_obj,const cfg_listelt_t * zone_element)2154 conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps, bool nsip_enabled,
2155 	    bool nsdname_enabled, dns_rpz_zbits_t *nsip_on,
2156 	    dns_rpz_zbits_t *nsdname_on, char **rps_cstr, size_t *rps_cstr_size,
2157 	    const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element) {
2158 	conf_dnsrps_ctx_t ctx;
2159 	const cfg_obj_t *zone_obj, *obj;
2160 	dns_rpz_num_t rpz_num;
2161 	bool on;
2162 	const char *s;
2163 
2164 	memset(&ctx, 0, sizeof(ctx));
2165 	ctx.result = ISC_R_SUCCESS;
2166 	ctx.mctx = view->mctx;
2167 
2168 	for (rpz_num = 0; zone_element != NULL && ctx.result == ISC_R_SUCCESS;
2169 	     ++rpz_num)
2170 	{
2171 		zone_obj = cfg_listelt_value(zone_element);
2172 
2173 		s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
2174 		conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
2175 
2176 		obj = cfg_tuple_get(zone_obj, "policy");
2177 		if (!cfg_obj_isvoid(obj)) {
2178 			s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2179 			conf_dnsrps_sadd(&ctx, " policy %s", s);
2180 			if (strcasecmp(s, "cname") == 0) {
2181 				s = cfg_obj_asstring(
2182 					cfg_tuple_get(obj, "cname"));
2183 				conf_dnsrps_sadd(&ctx, " %s", s);
2184 			}
2185 		}
2186 
2187 		conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
2188 		conf_dnsrps_yes_no(zone_obj, "log", &ctx);
2189 		conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
2190 		obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2191 		if (!cfg_obj_isvoid(obj)) {
2192 			if (cfg_obj_asboolean(obj)) {
2193 				*nsip_on |= DNS_RPZ_ZBIT(rpz_num);
2194 			} else {
2195 				*nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
2196 			}
2197 		}
2198 		on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2199 		if (nsip_enabled != on) {
2200 			conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes "
2201 						  : " nsip-enable no ");
2202 		}
2203 		obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2204 		if (!cfg_obj_isvoid(obj)) {
2205 			if (cfg_obj_asboolean(obj)) {
2206 				*nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
2207 			} else {
2208 				*nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
2209 			}
2210 		}
2211 		on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2212 		if (nsdname_enabled != on) {
2213 			conf_dnsrps_sadd(&ctx, on ? " nsdname-enable yes "
2214 						  : " nsdname-enable no ");
2215 		}
2216 		conf_dnsrps_sadd(&ctx, ";\n");
2217 		zone_element = cfg_list_next(zone_element);
2218 	}
2219 
2220 	conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
2221 	conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
2222 	conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
2223 	conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
2224 	conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
2225 	if (!nsip_enabled) {
2226 		conf_dnsrps_sadd(&ctx, " nsip-enable no ");
2227 	}
2228 	if (!nsdname_enabled) {
2229 		conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
2230 	}
2231 
2232 	/*
2233 	 * Get the general dnsrpzd parameters from the response-policy
2234 	 * statement in the view and the general options.
2235 	 */
2236 	if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
2237 	    obj != NULL)
2238 	{
2239 		conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
2240 	}
2241 
2242 	if (ctx.result == ISC_R_SUCCESS) {
2243 		*rps_cstr = ctx.cstr;
2244 		*rps_cstr_size = ctx.cstr_size;
2245 	} else {
2246 		if (ctx.cstr != NULL) {
2247 			isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
2248 		}
2249 		*rps_cstr = NULL;
2250 		*rps_cstr_size = 0;
2251 	}
2252 	return (ctx.result);
2253 }
2254 #endif /* ifdef USE_DNSRPS */
2255 
2256 static isc_result_t
configure_rpz_name(dns_view_t * view,const cfg_obj_t * obj,dns_name_t * name,const char * str,const char * msg)2257 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2258 		   const char *str, const char *msg) {
2259 	isc_result_t result;
2260 
2261 	result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx);
2262 	if (result != ISC_R_SUCCESS) {
2263 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2264 			    "invalid %s '%s'", msg, str);
2265 	}
2266 	return (result);
2267 }
2268 
2269 static isc_result_t
configure_rpz_name2(dns_view_t * view,const cfg_obj_t * obj,dns_name_t * name,const char * str,const dns_name_t * origin)2270 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2271 		    const char *str, const dns_name_t *origin) {
2272 	isc_result_t result;
2273 
2274 	result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE,
2275 				      view->mctx);
2276 	if (result != ISC_R_SUCCESS) {
2277 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2278 			    "invalid zone '%s'", str);
2279 	}
2280 	return (result);
2281 }
2282 
2283 static isc_result_t
configure_rpz_zone(dns_view_t * view,const cfg_listelt_t * element,bool recursive_only_default,bool add_soa_default,dns_ttl_t ttl_default,uint32_t minupdateinterval_default,const dns_rpz_zone_t * old,bool * old_rpz_okp)2284 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
2285 		   bool recursive_only_default, bool add_soa_default,
2286 		   dns_ttl_t ttl_default, uint32_t minupdateinterval_default,
2287 		   const dns_rpz_zone_t *old, bool *old_rpz_okp) {
2288 	const cfg_obj_t *rpz_obj, *obj;
2289 	const char *str;
2290 	dns_rpz_zone_t *zone = NULL;
2291 	isc_result_t result;
2292 	dns_rpz_num_t rpz_num;
2293 
2294 	REQUIRE(old != NULL || !*old_rpz_okp);
2295 
2296 	rpz_obj = cfg_listelt_value(element);
2297 
2298 	if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
2299 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2300 			    "limit of %d response policy zones exceeded",
2301 			    DNS_RPZ_MAX_ZONES);
2302 		return (ISC_R_FAILURE);
2303 	}
2304 
2305 	result = dns_rpz_new_zone(view->rpzs, &zone);
2306 	if (result != ISC_R_SUCCESS) {
2307 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2308 			    "Error creating new RPZ zone : %s",
2309 			    isc_result_totext(result));
2310 		return (result);
2311 	}
2312 
2313 	obj = cfg_tuple_get(rpz_obj, "recursive-only");
2314 	if (cfg_obj_isvoid(obj) ? recursive_only_default
2315 				: cfg_obj_asboolean(obj))
2316 	{
2317 		view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num);
2318 	} else {
2319 		view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num);
2320 	}
2321 
2322 	obj = cfg_tuple_get(rpz_obj, "log");
2323 	if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) {
2324 		view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num);
2325 	} else {
2326 		view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num);
2327 	}
2328 
2329 	obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2330 	if (cfg_obj_isduration(obj)) {
2331 		zone->max_policy_ttl = cfg_obj_asduration(obj);
2332 	} else {
2333 		zone->max_policy_ttl = ttl_default;
2334 	}
2335 	if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl) {
2336 		*old_rpz_okp = false;
2337 	}
2338 
2339 	obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2340 	if (cfg_obj_isduration(obj)) {
2341 		zone->min_update_interval = cfg_obj_asduration(obj);
2342 	} else {
2343 		zone->min_update_interval = minupdateinterval_default;
2344 	}
2345 	if (*old_rpz_okp &&
2346 	    zone->min_update_interval != old->min_update_interval)
2347 	{
2348 		*old_rpz_okp = false;
2349 	}
2350 
2351 	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
2352 	result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone");
2353 	if (result != ISC_R_SUCCESS) {
2354 		return (result);
2355 	}
2356 	if (dns_name_equal(&zone->origin, dns_rootname)) {
2357 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2358 			    "invalid zone name '%s'", str);
2359 		return (DNS_R_EMPTYLABEL);
2360 	}
2361 	if (!view->rpzs->p.dnsrps_enabled) {
2362 		for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1;
2363 		     ++rpz_num)
2364 		{
2365 			if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
2366 					   &zone->origin))
2367 			{
2368 				cfg_obj_log(rpz_obj, named_g_lctx,
2369 					    DNS_RPZ_ERROR_LEVEL,
2370 					    "duplicate '%s'", str);
2371 				result = DNS_R_DUPLICATE;
2372 				return (result);
2373 			}
2374 		}
2375 	}
2376 	if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) {
2377 		*old_rpz_okp = false;
2378 	}
2379 
2380 	result = configure_rpz_name2(view, rpz_obj, &zone->client_ip,
2381 				     DNS_RPZ_CLIENT_IP_ZONE, &zone->origin);
2382 	if (result != ISC_R_SUCCESS) {
2383 		return (result);
2384 	}
2385 
2386 	result = configure_rpz_name2(view, rpz_obj, &zone->ip, DNS_RPZ_IP_ZONE,
2387 				     &zone->origin);
2388 	if (result != ISC_R_SUCCESS) {
2389 		return (result);
2390 	}
2391 
2392 	result = configure_rpz_name2(view, rpz_obj, &zone->nsdname,
2393 				     DNS_RPZ_NSDNAME_ZONE, &zone->origin);
2394 	if (result != ISC_R_SUCCESS) {
2395 		return (result);
2396 	}
2397 
2398 	result = configure_rpz_name2(view, rpz_obj, &zone->nsip,
2399 				     DNS_RPZ_NSIP_ZONE, &zone->origin);
2400 	if (result != ISC_R_SUCCESS) {
2401 		return (result);
2402 	}
2403 
2404 	result = configure_rpz_name(view, rpz_obj, &zone->passthru,
2405 				    DNS_RPZ_PASSTHRU_NAME, "name");
2406 	if (result != ISC_R_SUCCESS) {
2407 		return (result);
2408 	}
2409 
2410 	result = configure_rpz_name(view, rpz_obj, &zone->drop,
2411 				    DNS_RPZ_DROP_NAME, "name");
2412 	if (result != ISC_R_SUCCESS) {
2413 		return (result);
2414 	}
2415 
2416 	result = configure_rpz_name(view, rpz_obj, &zone->tcp_only,
2417 				    DNS_RPZ_TCP_ONLY_NAME, "name");
2418 	if (result != ISC_R_SUCCESS) {
2419 		return (result);
2420 	}
2421 
2422 	obj = cfg_tuple_get(rpz_obj, "policy");
2423 	if (cfg_obj_isvoid(obj)) {
2424 		zone->policy = DNS_RPZ_POLICY_GIVEN;
2425 	} else {
2426 		str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2427 		zone->policy = dns_rpz_str2policy(str);
2428 		INSIST(zone->policy != DNS_RPZ_POLICY_ERROR);
2429 		if (zone->policy == DNS_RPZ_POLICY_CNAME) {
2430 			str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
2431 			result = configure_rpz_name(view, rpz_obj, &zone->cname,
2432 						    str, "cname");
2433 			if (result != ISC_R_SUCCESS) {
2434 				return (result);
2435 			}
2436 		}
2437 	}
2438 	if (*old_rpz_okp && (zone->policy != old->policy ||
2439 			     !dns_name_equal(&old->cname, &zone->cname)))
2440 	{
2441 		*old_rpz_okp = false;
2442 	}
2443 
2444 	obj = cfg_tuple_get(rpz_obj, "add-soa");
2445 	if (cfg_obj_isvoid(obj)) {
2446 		zone->addsoa = add_soa_default;
2447 	} else {
2448 		zone->addsoa = cfg_obj_asboolean(obj);
2449 	}
2450 	if (*old_rpz_okp && zone->addsoa != old->addsoa) {
2451 		*old_rpz_okp = false;
2452 	}
2453 
2454 	return (ISC_R_SUCCESS);
2455 }
2456 
2457 static isc_result_t
configure_rpz(dns_view_t * view,dns_view_t * pview,const cfg_obj_t ** maps,const cfg_obj_t * rpz_obj,bool * old_rpz_okp)2458 configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
2459 	      const cfg_obj_t *rpz_obj, bool *old_rpz_okp) {
2460 	bool dnsrps_enabled;
2461 	const cfg_listelt_t *zone_element;
2462 	char *rps_cstr;
2463 	size_t rps_cstr_size;
2464 	const cfg_obj_t *sub_obj;
2465 	bool recursive_only_default, add_soa_default;
2466 	bool nsip_enabled, nsdname_enabled;
2467 	dns_rpz_zbits_t nsip_on, nsdname_on;
2468 	dns_ttl_t ttl_default;
2469 	uint32_t minupdateinterval_default;
2470 	dns_rpz_zones_t *zones;
2471 	const dns_rpz_zones_t *old;
2472 	bool pview_must_detach = false;
2473 	const dns_rpz_zone_t *old_zone;
2474 	isc_result_t result;
2475 	int i;
2476 
2477 	*old_rpz_okp = false;
2478 
2479 	zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
2480 	if (zone_element == NULL) {
2481 		return (ISC_R_SUCCESS);
2482 	}
2483 
2484 	nsip_enabled = true;
2485 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2486 	if (!cfg_obj_isvoid(sub_obj)) {
2487 		nsip_enabled = cfg_obj_asboolean(sub_obj);
2488 	}
2489 	nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2490 
2491 	nsdname_enabled = true;
2492 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2493 	if (!cfg_obj_isvoid(sub_obj)) {
2494 		nsdname_enabled = cfg_obj_asboolean(sub_obj);
2495 	}
2496 	nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2497 
2498 	/*
2499 	 * "dnsrps-enable yes|no" can be either a global or response-policy
2500 	 * clause.
2501 	 */
2502 	dnsrps_enabled = false;
2503 	rps_cstr = NULL;
2504 	rps_cstr_size = 0;
2505 	sub_obj = NULL;
2506 	(void)named_config_get(maps, "dnsrps-enable", &sub_obj);
2507 	if (sub_obj != NULL) {
2508 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2509 	}
2510 	sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
2511 	if (!cfg_obj_isvoid(sub_obj)) {
2512 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2513 	}
2514 #ifndef USE_DNSRPS
2515 	if (dnsrps_enabled) {
2516 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2517 			    "\"dnsrps-enable yes\" but"
2518 			    " without `./configure --enable-dnsrps`");
2519 		return (ISC_R_FAILURE);
2520 	}
2521 #else  /* ifndef USE_DNSRPS */
2522 	if (dnsrps_enabled) {
2523 		if (librpz == NULL) {
2524 			cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2525 				    "\"dnsrps-enable yes\" but %s",
2526 				    librpz_lib_open_emsg.c);
2527 			return (ISC_R_FAILURE);
2528 		}
2529 
2530 		/*
2531 		 * Generate the DNS Response Policy Service
2532 		 * configuration string.
2533 		 */
2534 		result = conf_dnsrps(view, maps, nsip_enabled, nsdname_enabled,
2535 				     &nsip_on, &nsdname_on, &rps_cstr,
2536 				     &rps_cstr_size, rpz_obj, zone_element);
2537 		if (result != ISC_R_SUCCESS) {
2538 			return (result);
2539 		}
2540 	}
2541 #endif /* ifndef USE_DNSRPS */
2542 
2543 	result = dns_rpz_new_zones(&view->rpzs, rps_cstr, rps_cstr_size,
2544 				   view->mctx, named_g_taskmgr,
2545 				   named_g_timermgr);
2546 	if (result != ISC_R_SUCCESS) {
2547 		return (result);
2548 	}
2549 
2550 	zones = view->rpzs;
2551 
2552 	zones->p.nsip_on = nsip_on;
2553 	zones->p.nsdname_on = nsdname_on;
2554 
2555 	sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
2556 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2557 		recursive_only_default = false;
2558 	} else {
2559 		recursive_only_default = true;
2560 	}
2561 
2562 	sub_obj = cfg_tuple_get(rpz_obj, "add-soa");
2563 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2564 		add_soa_default = false;
2565 	} else {
2566 		add_soa_default = true;
2567 	}
2568 
2569 	sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
2570 	if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
2571 		zones->p.break_dnssec = true;
2572 	} else {
2573 		zones->p.break_dnssec = false;
2574 	}
2575 
2576 	sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2577 	if (cfg_obj_isduration(sub_obj)) {
2578 		ttl_default = cfg_obj_asduration(sub_obj);
2579 	} else {
2580 		ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
2581 	}
2582 
2583 	sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2584 	if (cfg_obj_isduration(sub_obj)) {
2585 		minupdateinterval_default = cfg_obj_asduration(sub_obj);
2586 	} else {
2587 		minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
2588 	}
2589 
2590 	sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
2591 	if (cfg_obj_isuint32(sub_obj)) {
2592 		zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
2593 	} else {
2594 		zones->p.min_ns_labels = 2;
2595 	}
2596 
2597 	sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
2598 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2599 		zones->p.qname_wait_recurse = true;
2600 	} else {
2601 		zones->p.qname_wait_recurse = false;
2602 	}
2603 
2604 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse");
2605 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2606 		zones->p.nsip_wait_recurse = true;
2607 	} else {
2608 		zones->p.nsip_wait_recurse = false;
2609 	}
2610 
2611 	if (pview != NULL) {
2612 		old = pview->rpzs;
2613 	} else {
2614 		result = dns_viewlist_find(&named_g_server->viewlist,
2615 					   view->name, view->rdclass, &pview);
2616 		if (result == ISC_R_SUCCESS) {
2617 			pview_must_detach = true;
2618 			old = pview->rpzs;
2619 		} else {
2620 			old = NULL;
2621 		}
2622 	}
2623 
2624 	if (old == NULL) {
2625 		*old_rpz_okp = false;
2626 	} else {
2627 		*old_rpz_okp = true;
2628 	}
2629 
2630 	for (i = 0; zone_element != NULL;
2631 	     ++i, zone_element = cfg_list_next(zone_element))
2632 	{
2633 		INSIST(!*old_rpz_okp || old != NULL);
2634 		if (*old_rpz_okp && i < old->p.num_zones) {
2635 			old_zone = old->zones[i];
2636 		} else {
2637 			*old_rpz_okp = false;
2638 			old_zone = NULL;
2639 		}
2640 		result = configure_rpz_zone(
2641 			view, zone_element, recursive_only_default,
2642 			add_soa_default, ttl_default, minupdateinterval_default,
2643 			old_zone, old_rpz_okp);
2644 		if (result != ISC_R_SUCCESS) {
2645 			if (pview_must_detach) {
2646 				dns_view_detach(&pview);
2647 			}
2648 			return (result);
2649 		}
2650 	}
2651 
2652 	/*
2653 	 * If this is a reloading and the parameters and list of policy
2654 	 * zones are unchanged, then use the same policy data.
2655 	 * Data for individual zones that must be reloaded will be merged.
2656 	 */
2657 	if (*old_rpz_okp) {
2658 		if (old != NULL &&
2659 		    memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
2660 		{
2661 			*old_rpz_okp = false;
2662 		} else if ((old == NULL || old->rps_cstr == NULL) !=
2663 			   (zones->rps_cstr == NULL))
2664 		{
2665 			*old_rpz_okp = false;
2666 		} else if (old != NULL && zones->rps_cstr != NULL &&
2667 			   strcmp(old->rps_cstr, zones->rps_cstr) != 0)
2668 		{
2669 			*old_rpz_okp = false;
2670 		}
2671 	}
2672 
2673 	if (*old_rpz_okp) {
2674 		dns_rpz_detach_rpzs(&view->rpzs);
2675 		dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
2676 		dns_rpz_detach_rpzs(&pview->rpzs);
2677 	} else if (old != NULL && pview != NULL) {
2678 		++pview->rpzs->rpz_ver;
2679 		view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
2680 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
2681 			    "updated RPZ policy: version %d",
2682 			    view->rpzs->rpz_ver);
2683 	}
2684 
2685 	if (pview_must_detach) {
2686 		dns_view_detach(&pview);
2687 	}
2688 
2689 	return (ISC_R_SUCCESS);
2690 }
2691 
2692 static void
catz_addmodzone_taskaction(isc_task_t * task,isc_event_t * event0)2693 catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2694 	catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2695 	isc_result_t result;
2696 	isc_buffer_t namebuf;
2697 	isc_buffer_t *confbuf;
2698 	char nameb[DNS_NAME_FORMATSIZE];
2699 	const cfg_obj_t *zlist = NULL;
2700 	cfg_obj_t *zoneconf = NULL;
2701 	cfg_obj_t *zoneobj = NULL;
2702 	ns_cfgctx_t *cfg;
2703 	dns_zone_t *zone = NULL;
2704 
2705 	cfg = (ns_cfgctx_t *)ev->view->new_zone_config;
2706 	if (cfg == NULL) {
2707 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2708 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2709 			      "catz: allow-new-zones statement missing from "
2710 			      "config; cannot add zone from the catalog");
2711 		goto cleanup;
2712 	}
2713 
2714 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
2715 	dns_name_totext(dns_catz_entry_getname(ev->entry), true, &namebuf);
2716 	isc_buffer_putuint8(&namebuf, 0);
2717 
2718 	/* Zone shouldn't already exist */
2719 	result = dns_zt_find(ev->view->zonetable,
2720 			     dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
2721 
2722 	if (ev->mod) {
2723 		if (result != ISC_R_SUCCESS) {
2724 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2725 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2726 				      "catz: error \"%s\" while trying to "
2727 				      "modify zone \"%s\"",
2728 				      isc_result_totext(result), nameb);
2729 			goto cleanup;
2730 		} else {
2731 			if (!dns_zone_getadded(zone)) {
2732 				isc_log_write(
2733 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2734 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2735 					"catz: "
2736 					"catz_addmodzone_taskaction: "
2737 					"zone '%s' is not a dynamically "
2738 					"added zone",
2739 					nameb);
2740 				goto cleanup;
2741 			}
2742 			if (dns_zone_get_parentcatz(zone) != ev->origin) {
2743 				isc_log_write(
2744 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2745 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2746 					"catz: catz_delzone_taskaction: "
2747 					"zone '%s' exists in multiple "
2748 					"catalog zones",
2749 					nameb);
2750 				goto cleanup;
2751 			}
2752 			dns_zone_detach(&zone);
2753 		}
2754 	} else {
2755 		if (result == ISC_R_SUCCESS) {
2756 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2757 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
2758 				      "catz: zone \"%s\" is overridden "
2759 				      "by explicitly configured zone",
2760 				      nameb);
2761 			goto cleanup;
2762 		} else if (result != ISC_R_NOTFOUND &&
2763 			   result != DNS_R_PARTIALMATCH)
2764 		{
2765 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2766 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2767 				      "catz: error \"%s\" while trying to "
2768 				      "add zone \"%s\"",
2769 				      isc_result_totext(result), nameb);
2770 			goto cleanup;
2771 		} else { /* this can happen in case of DNS_R_PARTIALMATCH */
2772 			if (zone != NULL) {
2773 				dns_zone_detach(&zone);
2774 			}
2775 		}
2776 	}
2777 	RUNTIME_CHECK(zone == NULL);
2778 	/* Create a config for new zone */
2779 	confbuf = NULL;
2780 	result = dns_catz_generate_zonecfg(ev->origin, ev->entry, &confbuf);
2781 	if (result == ISC_R_SUCCESS) {
2782 		cfg_parser_reset(cfg->add_parser);
2783 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
2784 					  &cfg_type_addzoneconf, 0, &zoneconf);
2785 		isc_buffer_free(&confbuf);
2786 	}
2787 	/*
2788 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer3()
2789 	 * failed.
2790 	 */
2791 	if (result != ISC_R_SUCCESS) {
2792 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2793 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2794 			      "catz: error \"%s\" while trying to generate "
2795 			      "config for zone \"%s\"",
2796 			      isc_result_totext(result), nameb);
2797 		goto cleanup;
2798 	}
2799 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
2800 	if (!cfg_obj_islist(zlist)) {
2801 		CHECK(ISC_R_FAILURE);
2802 	}
2803 
2804 	/* For now we only support adding one zone at a time */
2805 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
2806 
2807 	/* Mark view unfrozen so that zone can be added */
2808 
2809 	result = isc_task_beginexclusive(task);
2810 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2811 	dns_view_thaw(ev->view);
2812 	result = configure_zone(
2813 		cfg->config, zoneobj, cfg->vconfig, ev->cbd->server->mctx,
2814 		ev->view, &ev->cbd->server->viewlist,
2815 		&ev->cbd->server->kasplist, cfg->actx, true, false, ev->mod);
2816 	dns_view_freeze(ev->view);
2817 	isc_task_endexclusive(task);
2818 
2819 	if (result != ISC_R_SUCCESS) {
2820 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2821 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2822 			      "catz: failed to configure zone \"%s\" - %d",
2823 			      nameb, result);
2824 		goto cleanup;
2825 	}
2826 
2827 	/* Is it there yet? */
2828 	CHECK(dns_zt_find(ev->view->zonetable,
2829 			  dns_catz_entry_getname(ev->entry), 0, NULL, &zone));
2830 
2831 	/*
2832 	 * Load the zone from the master file.	If this fails, we'll
2833 	 * need to undo the configuration we've done already.
2834 	 */
2835 	result = dns_zone_load(zone, true);
2836 	if (result != ISC_R_SUCCESS) {
2837 		dns_db_t *dbp = NULL;
2838 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2839 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2840 			      "catz: dns_zone_load() failed "
2841 			      "with %s; reverting.",
2842 			      isc_result_totext(result));
2843 
2844 		/* If the zone loaded partially, unload it */
2845 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2846 			dns_db_detach(&dbp);
2847 			dns_zone_unload(zone);
2848 		}
2849 
2850 		/* Remove the zone from the zone table */
2851 		dns_zt_unmount(ev->view->zonetable, zone);
2852 		goto cleanup;
2853 	}
2854 
2855 	/* Flag the zone as having been added at runtime */
2856 	dns_zone_setadded(zone, true);
2857 	dns_zone_set_parentcatz(zone, ev->origin);
2858 
2859 cleanup:
2860 	if (zone != NULL) {
2861 		dns_zone_detach(&zone);
2862 	}
2863 	if (zoneconf != NULL) {
2864 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
2865 	}
2866 	dns_catz_entry_detach(ev->origin, &ev->entry);
2867 	dns_catz_zone_detach(&ev->origin);
2868 	dns_view_detach(&ev->view);
2869 	isc_event_free(ISC_EVENT_PTR(&ev));
2870 }
2871 
2872 static void
catz_delzone_taskaction(isc_task_t * task,isc_event_t * event0)2873 catz_delzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2874 	catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2875 	isc_result_t result;
2876 	dns_zone_t *zone = NULL;
2877 	dns_db_t *dbp = NULL;
2878 	char cname[DNS_NAME_FORMATSIZE];
2879 	const char *file;
2880 
2881 	result = isc_task_beginexclusive(task);
2882 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2883 
2884 	dns_name_format(dns_catz_entry_getname(ev->entry), cname,
2885 			DNS_NAME_FORMATSIZE);
2886 	result = dns_zt_find(ev->view->zonetable,
2887 			     dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
2888 	if (result != ISC_R_SUCCESS) {
2889 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2890 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2891 			      "catz: catz_delzone_taskaction: "
2892 			      "zone '%s' not found",
2893 			      cname);
2894 		goto cleanup;
2895 	}
2896 
2897 	if (!dns_zone_getadded(zone)) {
2898 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2899 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2900 			      "catz: catz_delzone_taskaction: "
2901 			      "zone '%s' is not a dynamically added zone",
2902 			      cname);
2903 		goto cleanup;
2904 	}
2905 
2906 	if (dns_zone_get_parentcatz(zone) != ev->origin) {
2907 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2908 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2909 			      "catz: catz_delzone_taskaction: zone "
2910 			      "'%s' exists in multiple catalog zones",
2911 			      cname);
2912 		goto cleanup;
2913 	}
2914 
2915 	/* Stop answering for this zone */
2916 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2917 		dns_db_detach(&dbp);
2918 		dns_zone_unload(zone);
2919 	}
2920 
2921 	CHECK(dns_zt_unmount(ev->view->zonetable, zone));
2922 	file = dns_zone_getfile(zone);
2923 	if (file != NULL) {
2924 		isc_file_remove(file);
2925 		file = dns_zone_getjournal(zone);
2926 		if (file != NULL) {
2927 			isc_file_remove(file);
2928 		}
2929 	}
2930 
2931 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2932 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2933 		      "catz: catz_delzone_taskaction: "
2934 		      "zone '%s' deleted",
2935 		      cname);
2936 cleanup:
2937 	isc_task_endexclusive(task);
2938 	if (zone != NULL) {
2939 		dns_zone_detach(&zone);
2940 	}
2941 	dns_catz_entry_detach(ev->origin, &ev->entry);
2942 	dns_catz_zone_detach(&ev->origin);
2943 	dns_view_detach(&ev->view);
2944 	isc_event_free(ISC_EVENT_PTR(&ev));
2945 }
2946 
2947 static isc_result_t
catz_create_chg_task(dns_catz_entry_t * entry,dns_catz_zone_t * origin,dns_view_t * view,isc_taskmgr_t * taskmgr,void * udata,isc_eventtype_t type)2948 catz_create_chg_task(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
2949 		     dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata,
2950 		     isc_eventtype_t type) {
2951 	catz_chgzone_event_t *event = NULL;
2952 	isc_task_t *task = NULL;
2953 	isc_result_t result;
2954 	isc_taskaction_t action = NULL;
2955 
2956 	result = isc_taskmgr_excltask(taskmgr, &task);
2957 	if (result != ISC_R_SUCCESS) {
2958 		return (result);
2959 	}
2960 
2961 	switch (type) {
2962 	case DNS_EVENT_CATZADDZONE:
2963 	case DNS_EVENT_CATZMODZONE:
2964 		action = catz_addmodzone_taskaction;
2965 		break;
2966 	case DNS_EVENT_CATZDELZONE:
2967 		action = catz_delzone_taskaction;
2968 		break;
2969 	default:
2970 		REQUIRE(0);
2971 		UNREACHABLE();
2972 	}
2973 
2974 	event = (catz_chgzone_event_t *)isc_event_allocate(
2975 		view->mctx, origin, type, action, NULL, sizeof(*event));
2976 
2977 	event->cbd = (catz_cb_data_t *)udata;
2978 	event->entry = NULL;
2979 	event->origin = NULL;
2980 	event->view = NULL;
2981 	event->mod = (type == DNS_EVENT_CATZMODZONE);
2982 
2983 	dns_catz_entry_attach(entry, &event->entry);
2984 	dns_catz_zone_attach(origin, &event->origin);
2985 	dns_view_attach(view, &event->view);
2986 
2987 	isc_task_send(task, ISC_EVENT_PTR(&event));
2988 	isc_task_detach(&task);
2989 
2990 	return (ISC_R_SUCCESS);
2991 }
2992 
2993 static isc_result_t
catz_addzone(dns_catz_entry_t * entry,dns_catz_zone_t * origin,dns_view_t * view,isc_taskmgr_t * taskmgr,void * udata)2994 catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
2995 	     isc_taskmgr_t *taskmgr, void *udata) {
2996 	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
2997 				     DNS_EVENT_CATZADDZONE));
2998 }
2999 
3000 static isc_result_t
catz_delzone(dns_catz_entry_t * entry,dns_catz_zone_t * origin,dns_view_t * view,isc_taskmgr_t * taskmgr,void * udata)3001 catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3002 	     isc_taskmgr_t *taskmgr, void *udata) {
3003 	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3004 				     DNS_EVENT_CATZDELZONE));
3005 }
3006 
3007 static isc_result_t
catz_modzone(dns_catz_entry_t * entry,dns_catz_zone_t * origin,dns_view_t * view,isc_taskmgr_t * taskmgr,void * udata)3008 catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3009 	     isc_taskmgr_t *taskmgr, void *udata) {
3010 	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3011 				     DNS_EVENT_CATZMODZONE));
3012 }
3013 
3014 static isc_result_t
configure_catz_zone(dns_view_t * view,dns_view_t * pview,const cfg_obj_t * config,const cfg_listelt_t * element)3015 configure_catz_zone(dns_view_t *view, dns_view_t *pview,
3016 		    const cfg_obj_t *config, const cfg_listelt_t *element) {
3017 	const cfg_obj_t *catz_obj, *obj;
3018 	dns_catz_zone_t *zone = NULL;
3019 	const char *str;
3020 	isc_result_t result;
3021 	dns_name_t origin;
3022 	dns_catz_options_t *opts;
3023 
3024 	dns_name_init(&origin, NULL);
3025 	catz_obj = cfg_listelt_value(element);
3026 
3027 	str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
3028 
3029 	result = dns_name_fromstring(&origin, str, DNS_NAME_DOWNCASE,
3030 				     view->mctx);
3031 	if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname)) {
3032 		result = DNS_R_EMPTYLABEL;
3033 	}
3034 
3035 	if (result != ISC_R_SUCCESS) {
3036 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3037 			    "catz: invalid zone name '%s'", str);
3038 		goto cleanup;
3039 	}
3040 
3041 	result = dns_catz_add_zone(view->catzs, &origin, &zone);
3042 	if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
3043 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3044 			    "catz: unable to create catalog zone '%s', "
3045 			    "error %s",
3046 			    str, isc_result_totext(result));
3047 		goto cleanup;
3048 	}
3049 
3050 	if (result == ISC_R_EXISTS) {
3051 		isc_ht_iter_t *it = NULL;
3052 
3053 		RUNTIME_CHECK(pview != NULL);
3054 
3055 		/*
3056 		 * xxxwpk todo: reconfigure the zone!!!!
3057 		 */
3058 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3059 			    "catz: catalog zone '%s' will not be reconfigured",
3060 			    str);
3061 		/*
3062 		 * We have to walk through all the member zones and attach
3063 		 * them to current view
3064 		 */
3065 		dns_catz_get_iterator(zone, &it);
3066 
3067 		for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
3068 		     result = isc_ht_iter_next(it))
3069 		{
3070 			dns_name_t *name = NULL;
3071 			dns_zone_t *dnszone = NULL;
3072 			dns_catz_entry_t *entry = NULL;
3073 			isc_result_t tresult;
3074 
3075 			isc_ht_iter_current(it, (void **)&entry);
3076 			name = dns_catz_entry_getname(entry);
3077 
3078 			tresult = dns_view_findzone(pview, name, &dnszone);
3079 			if (tresult != ISC_R_SUCCESS) {
3080 				continue;
3081 			}
3082 
3083 			dns_zone_setview(dnszone, view);
3084 			dns_view_addzone(view, dnszone);
3085 
3086 			/*
3087 			 * The dns_view_findzone() call above increments the
3088 			 * zone's reference count, which we need to decrement
3089 			 * back.  However, as dns_zone_detach() sets the
3090 			 * supplied pointer to NULL, calling it is deferred
3091 			 * until the dnszone variable is no longer used.
3092 			 */
3093 			dns_zone_detach(&dnszone);
3094 		}
3095 
3096 		isc_ht_iter_destroy(&it);
3097 
3098 		result = ISC_R_SUCCESS;
3099 	}
3100 
3101 	dns_catz_zone_resetdefoptions(zone);
3102 	opts = dns_catz_zone_getdefoptions(zone);
3103 
3104 	obj = cfg_tuple_get(catz_obj, "default-masters");
3105 	if (obj != NULL && cfg_obj_istuple(obj)) {
3106 		result = named_config_getipandkeylist(
3107 			config, "primaries", obj, view->mctx, &opts->masters);
3108 	}
3109 
3110 	obj = cfg_tuple_get(catz_obj, "in-memory");
3111 	if (obj != NULL && cfg_obj_isboolean(obj)) {
3112 		opts->in_memory = cfg_obj_asboolean(obj);
3113 	}
3114 
3115 	obj = cfg_tuple_get(catz_obj, "zone-directory");
3116 	if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) {
3117 		opts->zonedir = isc_mem_strdup(view->mctx,
3118 					       cfg_obj_asstring(obj));
3119 		if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) {
3120 			cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3121 				    "catz: zone-directory '%s' "
3122 				    "not found; zone files will not be "
3123 				    "saved",
3124 				    opts->zonedir);
3125 			opts->in_memory = true;
3126 		}
3127 	}
3128 
3129 	obj = cfg_tuple_get(catz_obj, "min-update-interval");
3130 	if (obj != NULL && cfg_obj_isduration(obj)) {
3131 		opts->min_update_interval = cfg_obj_asduration(obj);
3132 	}
3133 
3134 cleanup:
3135 	dns_name_free(&origin, view->mctx);
3136 
3137 	return (result);
3138 }
3139 
3140 static catz_cb_data_t ns_catz_cbdata;
3141 static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
3142 	catz_addzone, catz_modzone, catz_delzone, &ns_catz_cbdata
3143 };
3144 
3145 static isc_result_t
configure_catz(dns_view_t * view,dns_view_t * pview,const cfg_obj_t * config,const cfg_obj_t * catz_obj)3146 configure_catz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t *config,
3147 	       const cfg_obj_t *catz_obj) {
3148 	const cfg_listelt_t *zone_element;
3149 	const dns_catz_zones_t *old = NULL;
3150 	bool pview_must_detach = false;
3151 	isc_result_t result;
3152 
3153 	/* xxxwpk TODO do it cleaner, once, somewhere */
3154 	ns_catz_cbdata.server = named_g_server;
3155 
3156 	zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
3157 	if (zone_element == NULL) {
3158 		return (ISC_R_SUCCESS);
3159 	}
3160 
3161 	CHECK(dns_catz_new_zones(&view->catzs, &ns_catz_zonemodmethods,
3162 				 view->mctx, named_g_taskmgr,
3163 				 named_g_timermgr));
3164 
3165 	if (pview != NULL) {
3166 		old = pview->catzs;
3167 	} else {
3168 		result = dns_viewlist_find(&named_g_server->viewlist,
3169 					   view->name, view->rdclass, &pview);
3170 		if (result == ISC_R_SUCCESS) {
3171 			pview_must_detach = true;
3172 			old = pview->catzs;
3173 		}
3174 	}
3175 
3176 	if (old != NULL) {
3177 		dns_catz_catzs_detach(&view->catzs);
3178 		dns_catz_catzs_attach(pview->catzs, &view->catzs);
3179 		dns_catz_catzs_detach(&pview->catzs);
3180 		dns_catz_prereconfig(view->catzs);
3181 	}
3182 
3183 	while (zone_element != NULL) {
3184 		CHECK(configure_catz_zone(view, pview, config, zone_element));
3185 		zone_element = cfg_list_next(zone_element);
3186 	}
3187 
3188 	if (old != NULL) {
3189 		dns_catz_postreconfig(view->catzs);
3190 	}
3191 
3192 	result = ISC_R_SUCCESS;
3193 
3194 cleanup:
3195 	if (pview_must_detach) {
3196 		dns_view_detach(&pview);
3197 	}
3198 
3199 	return (result);
3200 }
3201 
3202 #define CHECK_RRL(cond, pat, val1, val2)                                   \
3203 	do {                                                               \
3204 		if (!(cond)) {                                             \
3205 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, pat, \
3206 				    val1, val2);                           \
3207 			result = ISC_R_RANGE;                              \
3208 			goto cleanup;                                      \
3209 		}                                                          \
3210 	} while (0)
3211 
3212 #define CHECK_RRL_RATE(rate, def, max_rate, name)                           \
3213 	do {                                                                \
3214 		obj = NULL;                                                 \
3215 		rrl->rate.str = name;                                       \
3216 		result = cfg_map_get(map, name, &obj);                      \
3217 		if (result == ISC_R_SUCCESS) {                              \
3218 			rrl->rate.r = cfg_obj_asuint32(obj);                \
3219 			CHECK_RRL(rrl->rate.r <= max_rate, name " %d > %d", \
3220 				  rrl->rate.r, max_rate);                   \
3221 		} else {                                                    \
3222 			rrl->rate.r = def;                                  \
3223 		}                                                           \
3224 		rrl->rate.scaled = rrl->rate.r;                             \
3225 	} while (0)
3226 
3227 static isc_result_t
configure_rrl(dns_view_t * view,const cfg_obj_t * config,const cfg_obj_t * map)3228 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
3229 	const cfg_obj_t *obj;
3230 	dns_rrl_t *rrl;
3231 	isc_result_t result;
3232 	int min_entries, i, j;
3233 
3234 	/*
3235 	 * Most DNS servers have few clients, but intentinally open
3236 	 * recursive and authoritative servers often have many.
3237 	 * So start with a small number of entries unless told otherwise
3238 	 * to reduce cold-start costs.
3239 	 */
3240 	min_entries = 500;
3241 	obj = NULL;
3242 	result = cfg_map_get(map, "min-table-size", &obj);
3243 	if (result == ISC_R_SUCCESS) {
3244 		min_entries = cfg_obj_asuint32(obj);
3245 		if (min_entries < 1) {
3246 			min_entries = 1;
3247 		}
3248 	}
3249 	result = dns_rrl_init(&rrl, view, min_entries);
3250 	if (result != ISC_R_SUCCESS) {
3251 		return (result);
3252 	}
3253 
3254 	i = ISC_MAX(20000, min_entries);
3255 	obj = NULL;
3256 	result = cfg_map_get(map, "max-table-size", &obj);
3257 	if (result == ISC_R_SUCCESS) {
3258 		i = cfg_obj_asuint32(obj);
3259 		CHECK_RRL(i >= min_entries,
3260 			  "max-table-size %d < min-table-size %d", i,
3261 			  min_entries);
3262 	}
3263 	rrl->max_entries = i;
3264 
3265 	CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
3266 		       "responses-per-second");
3267 	CHECK_RRL_RATE(referrals_per_second, rrl->responses_per_second.r,
3268 		       DNS_RRL_MAX_RATE, "referrals-per-second");
3269 	CHECK_RRL_RATE(nodata_per_second, rrl->responses_per_second.r,
3270 		       DNS_RRL_MAX_RATE, "nodata-per-second");
3271 	CHECK_RRL_RATE(nxdomains_per_second, rrl->responses_per_second.r,
3272 		       DNS_RRL_MAX_RATE, "nxdomains-per-second");
3273 	CHECK_RRL_RATE(errors_per_second, rrl->responses_per_second.r,
3274 		       DNS_RRL_MAX_RATE, "errors-per-second");
3275 
3276 	CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
3277 
3278 	CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
3279 
3280 	i = 15;
3281 	obj = NULL;
3282 	result = cfg_map_get(map, "window", &obj);
3283 	if (result == ISC_R_SUCCESS) {
3284 		i = cfg_obj_asuint32(obj);
3285 		CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
3286 			  "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
3287 	}
3288 	rrl->window = i;
3289 
3290 	i = 0;
3291 	obj = NULL;
3292 	result = cfg_map_get(map, "qps-scale", &obj);
3293 	if (result == ISC_R_SUCCESS) {
3294 		i = cfg_obj_asuint32(obj);
3295 		CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
3296 	}
3297 	rrl->qps_scale = i;
3298 	rrl->qps = 1.0;
3299 
3300 	i = 24;
3301 	obj = NULL;
3302 	result = cfg_map_get(map, "ipv4-prefix-length", &obj);
3303 	if (result == ISC_R_SUCCESS) {
3304 		i = cfg_obj_asuint32(obj);
3305 		CHECK_RRL(i >= 8 && i <= 32,
3306 			  "invalid 'ipv4-prefix-length %d'%s", i, "");
3307 	}
3308 	rrl->ipv4_prefixlen = i;
3309 	if (i == 32) {
3310 		rrl->ipv4_mask = 0xffffffff;
3311 	} else {
3312 		rrl->ipv4_mask = htonl(0xffffffff << (32 - i));
3313 	}
3314 
3315 	i = 56;
3316 	obj = NULL;
3317 	result = cfg_map_get(map, "ipv6-prefix-length", &obj);
3318 	if (result == ISC_R_SUCCESS) {
3319 		i = cfg_obj_asuint32(obj);
3320 		CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
3321 			  "ipv6-prefix-length %d < 16 or > %d", i,
3322 			  DNS_RRL_MAX_PREFIX);
3323 	}
3324 	rrl->ipv6_prefixlen = i;
3325 	for (j = 0; j < 4; ++j) {
3326 		if (i <= 0) {
3327 			rrl->ipv6_mask[j] = 0;
3328 		} else if (i < 32) {
3329 			rrl->ipv6_mask[j] = htonl(0xffffffff << (32 - i));
3330 		} else {
3331 			rrl->ipv6_mask[j] = 0xffffffff;
3332 		}
3333 		i -= 32;
3334 	}
3335 
3336 	obj = NULL;
3337 	result = cfg_map_get(map, "exempt-clients", &obj);
3338 	if (result == ISC_R_SUCCESS) {
3339 		result = cfg_acl_fromconfig(obj, config, named_g_lctx,
3340 					    named_g_aclconfctx, named_g_mctx, 0,
3341 					    &rrl->exempt);
3342 		CHECK_RRL(result == ISC_R_SUCCESS, "invalid %s%s",
3343 			  "address match list", "");
3344 	}
3345 
3346 	obj = NULL;
3347 	result = cfg_map_get(map, "log-only", &obj);
3348 	if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) {
3349 		rrl->log_only = true;
3350 	} else {
3351 		rrl->log_only = false;
3352 	}
3353 
3354 	return (ISC_R_SUCCESS);
3355 
3356 cleanup:
3357 	dns_rrl_view_destroy(view);
3358 	return (result);
3359 }
3360 
3361 static isc_result_t
add_soa(dns_db_t * db,dns_dbversion_t * version,const dns_name_t * name,const dns_name_t * origin,const dns_name_t * contact)3362 add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3363 	const dns_name_t *origin, const dns_name_t *contact) {
3364 	dns_dbnode_t *node = NULL;
3365 	dns_rdata_t rdata = DNS_RDATA_INIT;
3366 	dns_rdatalist_t rdatalist;
3367 	dns_rdataset_t rdataset;
3368 	isc_result_t result;
3369 	unsigned char buf[DNS_SOA_BUFFERSIZE];
3370 
3371 	CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 0, 28800,
3372 				 7200, 604800, 86400, buf, &rdata));
3373 
3374 	dns_rdatalist_init(&rdatalist);
3375 	rdatalist.type = rdata.type;
3376 	rdatalist.rdclass = rdata.rdclass;
3377 	rdatalist.ttl = 86400;
3378 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3379 
3380 	dns_rdataset_init(&rdataset);
3381 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3382 	CHECK(dns_db_findnode(db, name, true, &node));
3383 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3384 
3385 cleanup:
3386 	if (node != NULL) {
3387 		dns_db_detachnode(db, &node);
3388 	}
3389 	return (result);
3390 }
3391 
3392 static isc_result_t
add_ns(dns_db_t * db,dns_dbversion_t * version,const dns_name_t * name,const dns_name_t * nsname)3393 add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3394        const dns_name_t *nsname) {
3395 	dns_dbnode_t *node = NULL;
3396 	dns_rdata_ns_t ns;
3397 	dns_rdata_t rdata = DNS_RDATA_INIT;
3398 	dns_rdatalist_t rdatalist;
3399 	dns_rdataset_t rdataset;
3400 	isc_result_t result;
3401 	isc_buffer_t b;
3402 	unsigned char buf[DNS_NAME_MAXWIRE];
3403 
3404 	isc_buffer_init(&b, buf, sizeof(buf));
3405 
3406 	ns.common.rdtype = dns_rdatatype_ns;
3407 	ns.common.rdclass = dns_db_class(db);
3408 	ns.mctx = NULL;
3409 	dns_name_init(&ns.name, NULL);
3410 	dns_name_clone(nsname, &ns.name);
3411 	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
3412 				   &ns, &b));
3413 
3414 	dns_rdatalist_init(&rdatalist);
3415 	rdatalist.type = rdata.type;
3416 	rdatalist.rdclass = rdata.rdclass;
3417 	rdatalist.ttl = 86400;
3418 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3419 
3420 	dns_rdataset_init(&rdataset);
3421 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3422 	CHECK(dns_db_findnode(db, name, true, &node));
3423 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3424 
3425 cleanup:
3426 	if (node != NULL) {
3427 		dns_db_detachnode(db, &node);
3428 	}
3429 	return (result);
3430 }
3431 
3432 static isc_result_t
create_empty_zone(dns_zone_t * zone,dns_name_t * name,dns_view_t * view,const cfg_obj_t * zonelist,const char ** empty_dbtype,int empty_dbtypec,dns_zonestat_level_t statlevel)3433 create_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view,
3434 		  const cfg_obj_t *zonelist, const char **empty_dbtype,
3435 		  int empty_dbtypec, dns_zonestat_level_t statlevel) {
3436 	char namebuf[DNS_NAME_FORMATSIZE];
3437 	const cfg_listelt_t *element;
3438 	const cfg_obj_t *obj;
3439 	const cfg_obj_t *zconfig;
3440 	const cfg_obj_t *zoptions;
3441 	const char *rbt_dbtype[4] = { "rbt" };
3442 	const char *sep = ": view ";
3443 	const char *str;
3444 	const char *viewname = view->name;
3445 	dns_db_t *db = NULL;
3446 	dns_dbversion_t *version = NULL;
3447 	dns_fixedname_t cfixed;
3448 	dns_fixedname_t fixed;
3449 	dns_fixedname_t nsfixed;
3450 	dns_name_t *contact;
3451 	dns_name_t *ns;
3452 	dns_name_t *zname;
3453 	dns_zone_t *myzone = NULL;
3454 	int rbt_dbtypec = 1;
3455 	isc_result_t result;
3456 	dns_namereln_t namereln;
3457 	int order;
3458 	unsigned int nlabels;
3459 
3460 	zname = dns_fixedname_initname(&fixed);
3461 	ns = dns_fixedname_initname(&nsfixed);
3462 	contact = dns_fixedname_initname(&cfixed);
3463 
3464 	/*
3465 	 * Look for forward "zones" beneath this empty zone and if so
3466 	 * create a custom db for the empty zone.
3467 	 */
3468 	for (element = cfg_list_first(zonelist); element != NULL;
3469 	     element = cfg_list_next(element))
3470 	{
3471 		zconfig = cfg_listelt_value(element);
3472 		str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3473 		CHECK(dns_name_fromstring(zname, str, 0, NULL));
3474 		namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
3475 		if (namereln != dns_namereln_subdomain) {
3476 			continue;
3477 		}
3478 
3479 		zoptions = cfg_tuple_get(zconfig, "options");
3480 
3481 		obj = NULL;
3482 		(void)cfg_map_get(zoptions, "type", &obj);
3483 		if (obj != NULL &&
3484 		    strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
3485 		{
3486 			obj = NULL;
3487 			(void)cfg_map_get(zoptions, "forward", &obj);
3488 			if (obj == NULL) {
3489 				continue;
3490 			}
3491 			if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) {
3492 				continue;
3493 			}
3494 		}
3495 		if (db == NULL) {
3496 			CHECK(dns_db_create(view->mctx, "rbt", name,
3497 					    dns_dbtype_zone, view->rdclass, 0,
3498 					    NULL, &db));
3499 			CHECK(dns_db_newversion(db, &version));
3500 			if (strcmp(empty_dbtype[2], "@") == 0) {
3501 				dns_name_clone(name, ns);
3502 			} else {
3503 				CHECK(dns_name_fromstring(ns, empty_dbtype[2],
3504 							  0, NULL));
3505 			}
3506 			CHECK(dns_name_fromstring(contact, empty_dbtype[3], 0,
3507 						  NULL));
3508 			CHECK(add_soa(db, version, name, ns, contact));
3509 			CHECK(add_ns(db, version, name, ns));
3510 		}
3511 		CHECK(add_ns(db, version, zname, dns_rootname));
3512 	}
3513 
3514 	/*
3515 	 * Is the existing zone the ok to use?
3516 	 */
3517 	if (zone != NULL) {
3518 		unsigned int typec;
3519 		const char **dbargv;
3520 
3521 		if (db != NULL) {
3522 			typec = rbt_dbtypec;
3523 			dbargv = rbt_dbtype;
3524 		} else {
3525 			typec = empty_dbtypec;
3526 			dbargv = empty_dbtype;
3527 		}
3528 
3529 		result = check_dbtype(zone, typec, dbargv, view->mctx);
3530 		if (result != ISC_R_SUCCESS) {
3531 			zone = NULL;
3532 		}
3533 
3534 		if (zone != NULL && dns_zone_gettype(zone) != dns_zone_primary)
3535 		{
3536 			zone = NULL;
3537 		}
3538 		if (zone != NULL && dns_zone_getfile(zone) != NULL) {
3539 			zone = NULL;
3540 		}
3541 		if (zone != NULL) {
3542 			dns_zone_getraw(zone, &myzone);
3543 			if (myzone != NULL) {
3544 				dns_zone_detach(&myzone);
3545 				zone = NULL;
3546 			}
3547 		}
3548 	}
3549 
3550 	if (zone == NULL) {
3551 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &myzone));
3552 		zone = myzone;
3553 		CHECK(dns_zone_setorigin(zone, name));
3554 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3555 		if (db == NULL) {
3556 			dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype);
3557 		}
3558 		dns_zone_setclass(zone, view->rdclass);
3559 		dns_zone_settype(zone, dns_zone_primary);
3560 		dns_zone_setstats(zone, named_g_server->zonestats);
3561 	}
3562 
3563 	dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
3564 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3565 	dns_zone_setnotifytype(zone, dns_notifytype_no);
3566 	dns_zone_setdialup(zone, dns_dialuptype_no);
3567 	dns_zone_setautomatic(zone, true);
3568 	if (view->queryacl != NULL) {
3569 		dns_zone_setqueryacl(zone, view->queryacl);
3570 	} else {
3571 		dns_zone_clearqueryacl(zone);
3572 	}
3573 	if (view->queryonacl != NULL) {
3574 		dns_zone_setqueryonacl(zone, view->queryonacl);
3575 	} else {
3576 		dns_zone_clearqueryonacl(zone);
3577 	}
3578 	dns_zone_clearupdateacl(zone);
3579 	if (view->transferacl != NULL) {
3580 		dns_zone_setxfracl(zone, view->transferacl);
3581 	} else {
3582 		dns_zone_clearxfracl(zone);
3583 	}
3584 
3585 	CHECK(setquerystats(zone, view->mctx, statlevel));
3586 	if (db != NULL) {
3587 		dns_db_closeversion(db, &version, true);
3588 		CHECK(dns_zone_replacedb(zone, db, false));
3589 	}
3590 	dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true);
3591 	dns_zone_setview(zone, view);
3592 	CHECK(dns_view_addzone(view, zone));
3593 
3594 	if (!strcmp(viewname, "_default")) {
3595 		sep = "";
3596 		viewname = "";
3597 	}
3598 	dns_name_format(name, namebuf, sizeof(namebuf));
3599 	isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD,
3600 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3601 		      "automatic empty zone%s%s: %s", sep, viewname, namebuf);
3602 
3603 cleanup:
3604 	if (myzone != NULL) {
3605 		dns_zone_detach(&myzone);
3606 	}
3607 	if (version != NULL) {
3608 		dns_db_closeversion(db, &version, false);
3609 	}
3610 	if (db != NULL) {
3611 		dns_db_detach(&db);
3612 	}
3613 
3614 	INSIST(version == NULL);
3615 
3616 	return (result);
3617 }
3618 
3619 #ifdef HAVE_DNSTAP
3620 static isc_result_t
configure_dnstap(const cfg_obj_t ** maps,dns_view_t * view)3621 configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
3622 	isc_result_t result;
3623 	const cfg_obj_t *obj, *obj2;
3624 	const cfg_listelt_t *element;
3625 	const char *dpath;
3626 	const cfg_obj_t *dlist = NULL;
3627 	dns_dtmsgtype_t dttypes = 0;
3628 	unsigned int i;
3629 	struct fstrm_iothr_options *fopt = NULL;
3630 
3631 	result = named_config_get(maps, "dnstap", &dlist);
3632 	if (result != ISC_R_SUCCESS) {
3633 		return (ISC_R_SUCCESS);
3634 	}
3635 
3636 	for (element = cfg_list_first(dlist); element != NULL;
3637 	     element = cfg_list_next(element))
3638 	{
3639 		const char *str;
3640 		dns_dtmsgtype_t dt = 0;
3641 
3642 		obj = cfg_listelt_value(element);
3643 		obj2 = cfg_tuple_get(obj, "type");
3644 		str = cfg_obj_asstring(obj2);
3645 		if (strcasecmp(str, "client") == 0) {
3646 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR;
3647 		} else if (strcasecmp(str, "auth") == 0) {
3648 			dt |= DNS_DTTYPE_AQ | DNS_DTTYPE_AR;
3649 		} else if (strcasecmp(str, "resolver") == 0) {
3650 			dt |= DNS_DTTYPE_RQ | DNS_DTTYPE_RR;
3651 		} else if (strcasecmp(str, "forwarder") == 0) {
3652 			dt |= DNS_DTTYPE_FQ | DNS_DTTYPE_FR;
3653 		} else if (strcasecmp(str, "update") == 0) {
3654 			dt |= DNS_DTTYPE_UQ | DNS_DTTYPE_UR;
3655 		} else if (strcasecmp(str, "all") == 0) {
3656 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR | DNS_DTTYPE_AQ |
3657 			      DNS_DTTYPE_AR | DNS_DTTYPE_RQ | DNS_DTTYPE_RR |
3658 			      DNS_DTTYPE_FQ | DNS_DTTYPE_FR | DNS_DTTYPE_UQ |
3659 			      DNS_DTTYPE_UR;
3660 		}
3661 
3662 		obj2 = cfg_tuple_get(obj, "mode");
3663 		if (obj2 == NULL || cfg_obj_isvoid(obj2)) {
3664 			dttypes |= dt;
3665 			continue;
3666 		}
3667 
3668 		str = cfg_obj_asstring(obj2);
3669 		if (strcasecmp(str, "query") == 0) {
3670 			dt &= ~DNS_DTTYPE_RESPONSE;
3671 		} else if (strcasecmp(str, "response") == 0) {
3672 			dt &= ~DNS_DTTYPE_QUERY;
3673 		}
3674 
3675 		dttypes |= dt;
3676 	}
3677 
3678 	if (named_g_server->dtenv == NULL && dttypes != 0) {
3679 		dns_dtmode_t dmode;
3680 		uint64_t max_size = 0;
3681 		uint32_t rolls = 0;
3682 		isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment;
3683 
3684 		obj = NULL;
3685 		CHECKM(named_config_get(maps, "dnstap-output", &obj),
3686 		       "'dnstap-output' must be set if 'dnstap' is set");
3687 
3688 		obj2 = cfg_tuple_get(obj, "mode");
3689 		if (obj2 == NULL) {
3690 			CHECKM(ISC_R_FAILURE, "dnstap-output mode not found");
3691 		}
3692 		if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) {
3693 			dmode = dns_dtmode_file;
3694 		} else {
3695 			dmode = dns_dtmode_unix;
3696 		}
3697 
3698 		obj2 = cfg_tuple_get(obj, "path");
3699 		if (obj2 == NULL) {
3700 			CHECKM(ISC_R_FAILURE, "dnstap-output path not found");
3701 		}
3702 
3703 		dpath = cfg_obj_asstring(obj2);
3704 
3705 		obj2 = cfg_tuple_get(obj, "size");
3706 		if (obj2 != NULL && cfg_obj_isuint64(obj2)) {
3707 			max_size = cfg_obj_asuint64(obj2);
3708 			if (max_size > SIZE_MAX) {
3709 				cfg_obj_log(obj2, named_g_lctx, ISC_LOG_WARNING,
3710 					    "'dnstap-output size "
3711 					    "%" PRIu64 "' "
3712 					    "is too large for this "
3713 					    "system; reducing to %lu",
3714 					    max_size, (unsigned long)SIZE_MAX);
3715 				max_size = SIZE_MAX;
3716 			}
3717 		}
3718 
3719 		obj2 = cfg_tuple_get(obj, "versions");
3720 		if (obj2 != NULL && cfg_obj_isuint32(obj2)) {
3721 			rolls = cfg_obj_asuint32(obj2);
3722 		} else {
3723 			rolls = ISC_LOG_ROLLINFINITE;
3724 		}
3725 
3726 		obj2 = cfg_tuple_get(obj, "suffix");
3727 		if (obj2 != NULL && cfg_obj_isstring(obj2) &&
3728 		    strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0)
3729 		{
3730 			suffix = isc_log_rollsuffix_timestamp;
3731 		}
3732 
3733 		fopt = fstrm_iothr_options_init();
3734 		/*
3735 		 * Both network threads and worker threads may log dnstap data.
3736 		 */
3737 		fstrm_iothr_options_set_num_input_queues(fopt,
3738 							 2 * named_g_cpus);
3739 		fstrm_iothr_options_set_queue_model(
3740 			fopt, FSTRM_IOTHR_QUEUE_MODEL_MPSC);
3741 
3742 		obj = NULL;
3743 		result = named_config_get(maps, "fstrm-set-buffer-hint", &obj);
3744 		if (result == ISC_R_SUCCESS) {
3745 			i = cfg_obj_asuint32(obj);
3746 			fstrm_iothr_options_set_buffer_hint(fopt, i);
3747 		}
3748 
3749 		obj = NULL;
3750 		result = named_config_get(maps, "fstrm-set-flush-timeout",
3751 					  &obj);
3752 		if (result == ISC_R_SUCCESS) {
3753 			i = cfg_obj_asuint32(obj);
3754 			fstrm_iothr_options_set_flush_timeout(fopt, i);
3755 		}
3756 
3757 		obj = NULL;
3758 		result = named_config_get(maps, "fstrm-set-input-queue-size",
3759 					  &obj);
3760 		if (result == ISC_R_SUCCESS) {
3761 			i = cfg_obj_asuint32(obj);
3762 			fstrm_iothr_options_set_input_queue_size(fopt, i);
3763 		}
3764 
3765 		obj = NULL;
3766 		result = named_config_get(
3767 			maps, "fstrm-set-output-notify-threshold", &obj);
3768 		if (result == ISC_R_SUCCESS) {
3769 			i = cfg_obj_asuint32(obj);
3770 			fstrm_iothr_options_set_queue_notify_threshold(fopt, i);
3771 		}
3772 
3773 		obj = NULL;
3774 		result = named_config_get(maps, "fstrm-set-output-queue-model",
3775 					  &obj);
3776 		if (result == ISC_R_SUCCESS) {
3777 			if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0) {
3778 				i = FSTRM_IOTHR_QUEUE_MODEL_SPSC;
3779 			} else {
3780 				i = FSTRM_IOTHR_QUEUE_MODEL_MPSC;
3781 			}
3782 			fstrm_iothr_options_set_queue_model(fopt, i);
3783 		}
3784 
3785 		obj = NULL;
3786 		result = named_config_get(maps, "fstrm-set-output-queue-size",
3787 					  &obj);
3788 		if (result == ISC_R_SUCCESS) {
3789 			i = cfg_obj_asuint32(obj);
3790 			fstrm_iothr_options_set_output_queue_size(fopt, i);
3791 		}
3792 
3793 		obj = NULL;
3794 		result = named_config_get(maps, "fstrm-set-reopen-interval",
3795 					  &obj);
3796 		if (result == ISC_R_SUCCESS) {
3797 			i = cfg_obj_asduration(obj);
3798 			fstrm_iothr_options_set_reopen_interval(fopt, i);
3799 		}
3800 
3801 		CHECKM(dns_dt_create(named_g_mctx, dmode, dpath, &fopt,
3802 				     named_g_server->task,
3803 				     &named_g_server->dtenv),
3804 		       "unable to create dnstap environment");
3805 
3806 		CHECKM(dns_dt_setupfile(named_g_server->dtenv, max_size, rolls,
3807 					suffix),
3808 		       "unable to set up dnstap logfile");
3809 	}
3810 
3811 	if (named_g_server->dtenv == NULL) {
3812 		return (ISC_R_SUCCESS);
3813 	}
3814 
3815 	obj = NULL;
3816 	result = named_config_get(maps, "dnstap-version", &obj);
3817 	if (result != ISC_R_SUCCESS) {
3818 		/* not specified; use the product and version */
3819 		dns_dt_setversion(named_g_server->dtenv, PRODUCT " " VERSION);
3820 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3821 		/* Quoted string */
3822 		dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj));
3823 	}
3824 
3825 	obj = NULL;
3826 	result = named_config_get(maps, "dnstap-identity", &obj);
3827 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
3828 		/* "hostname" is interpreted as boolean true */
3829 		char buf[256];
3830 		result = named_os_gethostname(buf, sizeof(buf));
3831 		if (result == ISC_R_SUCCESS) {
3832 			dns_dt_setidentity(named_g_server->dtenv, buf);
3833 		}
3834 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3835 		/* Quoted string */
3836 		dns_dt_setidentity(named_g_server->dtenv,
3837 				   cfg_obj_asstring(obj));
3838 	}
3839 
3840 	dns_dt_attach(named_g_server->dtenv, &view->dtenv);
3841 	view->dttypes = dttypes;
3842 
3843 	result = ISC_R_SUCCESS;
3844 
3845 cleanup:
3846 	if (fopt != NULL) {
3847 		fstrm_iothr_options_destroy(&fopt);
3848 	}
3849 
3850 	return (result);
3851 }
3852 #endif /* HAVE_DNSTAP */
3853 
3854 static isc_result_t
create_mapped_acl(void)3855 create_mapped_acl(void) {
3856 	isc_result_t result;
3857 	dns_acl_t *acl = NULL;
3858 	struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT;
3859 	isc_netaddr_t addr;
3860 
3861 	isc_netaddr_fromin6(&addr, &in6);
3862 
3863 	result = dns_acl_create(named_g_mctx, 1, &acl);
3864 	if (result != ISC_R_SUCCESS) {
3865 		return (result);
3866 	}
3867 
3868 	result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
3869 	if (result == ISC_R_SUCCESS) {
3870 		dns_acl_attach(acl, &named_g_mapped);
3871 	}
3872 	dns_acl_detach(&acl);
3873 	return (result);
3874 }
3875 
3876 #ifdef HAVE_DLOPEN
3877 /*%
3878  * A callback for the cfg_pluginlist_foreach() call in configure_view() below.
3879  * If registering any plugin fails, registering subsequent ones is not
3880  * attempted.
3881  */
3882 static isc_result_t
register_one_plugin(const cfg_obj_t * config,const cfg_obj_t * obj,const char * plugin_path,const char * parameters,void * callback_data)3883 register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
3884 		    const char *plugin_path, const char *parameters,
3885 		    void *callback_data) {
3886 	dns_view_t *view = callback_data;
3887 	char full_path[PATH_MAX];
3888 	isc_result_t result;
3889 
3890 	result = ns_plugin_expandpath(plugin_path, full_path,
3891 				      sizeof(full_path));
3892 	if (result != ISC_R_SUCCESS) {
3893 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3894 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3895 			      "%s: plugin configuration failed: "
3896 			      "unable to get full plugin path: %s",
3897 			      plugin_path, isc_result_totext(result));
3898 		return (result);
3899 	}
3900 
3901 	result = ns_plugin_register(full_path, parameters, config,
3902 				    cfg_obj_file(obj), cfg_obj_line(obj),
3903 				    named_g_mctx, named_g_lctx,
3904 				    named_g_aclconfctx, view);
3905 	if (result != ISC_R_SUCCESS) {
3906 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3907 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3908 			      "%s: plugin configuration failed: %s", full_path,
3909 			      isc_result_totext(result));
3910 	}
3911 
3912 	return (result);
3913 }
3914 #endif /* ifdef HAVE_DLOPEN */
3915 
3916 /*
3917  * Determine if a minimal-sized cache can be used for a given view, according
3918  * to 'maps' (implicit defaults, global options, view options) and 'optionmaps'
3919  * (global options, view options).  This is only allowed for views which have
3920  * recursion disabled and do not have "max-cache-size" set explicitly.  Using
3921  * minimal-sized caches prevents a situation in which all explicitly configured
3922  * and built-in views inherit the default "max-cache-size 90%;" setting, which
3923  * could lead to memory exhaustion with multiple views configured.
3924  */
3925 static bool
minimal_cache_allowed(const cfg_obj_t * maps[4],const cfg_obj_t * optionmaps[3])3926 minimal_cache_allowed(const cfg_obj_t *maps[4],
3927 		      const cfg_obj_t *optionmaps[3]) {
3928 	const cfg_obj_t *obj;
3929 
3930 	/*
3931 	 * Do not use a minimal-sized cache for a view with recursion enabled.
3932 	 */
3933 	obj = NULL;
3934 	(void)named_config_get(maps, "recursion", &obj);
3935 	INSIST(obj != NULL);
3936 	if (cfg_obj_asboolean(obj)) {
3937 		return (false);
3938 	}
3939 
3940 	/*
3941 	 * Do not use a minimal-sized cache if a specific size was requested.
3942 	 */
3943 	obj = NULL;
3944 	(void)named_config_get(optionmaps, "max-cache-size", &obj);
3945 	if (obj != NULL) {
3946 		return (false);
3947 	}
3948 
3949 	return (true);
3950 }
3951 
3952 static const char *const response_synonyms[] = { "response", NULL };
3953 
3954 /*
3955  * Configure 'view' according to 'vconfig', taking defaults from 'config'
3956  * where values are missing in 'vconfig'.
3957  *
3958  * When configuring the default view, 'vconfig' will be NULL and the
3959  * global defaults in 'config' used exclusively.
3960  */
3961 static isc_result_t
configure_view(dns_view_t * view,dns_viewlist_t * viewlist,cfg_obj_t * config,cfg_obj_t * vconfig,named_cachelist_t * cachelist,dns_kasplist_t * kasplist,const cfg_obj_t * bindkeys,isc_mem_t * mctx,cfg_aclconfctx_t * actx,bool need_hints)3962 configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
3963 	       cfg_obj_t *vconfig, named_cachelist_t *cachelist,
3964 	       dns_kasplist_t *kasplist, const cfg_obj_t *bindkeys,
3965 	       isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints) {
3966 	const cfg_obj_t *maps[4];
3967 	const cfg_obj_t *cfgmaps[3];
3968 	const cfg_obj_t *optionmaps[3];
3969 	const cfg_obj_t *options = NULL;
3970 	const cfg_obj_t *voptions = NULL;
3971 	const cfg_obj_t *forwardtype;
3972 	const cfg_obj_t *forwarders;
3973 	const cfg_obj_t *alternates;
3974 	const cfg_obj_t *zonelist;
3975 	const cfg_obj_t *dlzlist;
3976 	const cfg_obj_t *dlz;
3977 	const cfg_obj_t *prefetch_trigger;
3978 	const cfg_obj_t *prefetch_eligible;
3979 	unsigned int dlzargc;
3980 	char **dlzargv;
3981 	const cfg_obj_t *dyndb_list, *plugin_list;
3982 	const cfg_obj_t *disabled;
3983 	const cfg_obj_t *obj, *obj2;
3984 	const cfg_listelt_t *element = NULL;
3985 	const cfg_listelt_t *zone_element_latest = NULL;
3986 	in_port_t port;
3987 	dns_cache_t *cache = NULL;
3988 	isc_result_t result;
3989 	size_t max_cache_size;
3990 	uint32_t max_cache_size_percent = 0;
3991 	size_t max_adb_size;
3992 	uint32_t lame_ttl, fail_ttl;
3993 	uint32_t max_stale_ttl = 0;
3994 	uint32_t stale_refresh_time = 0;
3995 	dns_tsig_keyring_t *ring = NULL;
3996 	dns_view_t *pview = NULL; /* Production view */
3997 	isc_mem_t *cmctx = NULL, *hmctx = NULL;
3998 	dns_dispatch_t *dispatch4 = NULL;
3999 	dns_dispatch_t *dispatch6 = NULL;
4000 	bool rpz_configured = false;
4001 	bool catz_configured = false;
4002 	bool reused_cache = false;
4003 	bool shared_cache = false;
4004 	int i = 0, j = 0, k = 0;
4005 	const char *str;
4006 	const char *cachename = NULL;
4007 	dns_order_t *order = NULL;
4008 	uint32_t udpsize;
4009 	uint32_t maxbits;
4010 	unsigned int resopts = 0;
4011 	dns_zone_t *zone = NULL;
4012 	uint32_t max_clients_per_query;
4013 	bool empty_zones_enable;
4014 	const cfg_obj_t *disablelist = NULL;
4015 	isc_stats_t *resstats = NULL;
4016 	dns_stats_t *resquerystats = NULL;
4017 	bool auto_root = false;
4018 	named_cache_t *nsc;
4019 	bool zero_no_soattl;
4020 	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
4021 	unsigned int query_timeout, ndisp;
4022 	bool old_rpz_ok = false;
4023 	isc_dscp_t dscp4 = -1, dscp6 = -1;
4024 	dns_dyndbctx_t *dctx = NULL;
4025 	unsigned int resolver_param;
4026 	dns_ntatable_t *ntatable = NULL;
4027 	const char *qminmode = NULL;
4028 
4029 	REQUIRE(DNS_VIEW_VALID(view));
4030 
4031 	if (config != NULL) {
4032 		(void)cfg_map_get(config, "options", &options);
4033 	}
4034 
4035 	/*
4036 	 * maps: view options, options, defaults
4037 	 * cfgmaps: view options, config
4038 	 * optionmaps: view options, options
4039 	 */
4040 	if (vconfig != NULL) {
4041 		voptions = cfg_tuple_get(vconfig, "options");
4042 		maps[i++] = voptions;
4043 		optionmaps[j++] = voptions;
4044 		cfgmaps[k++] = voptions;
4045 	}
4046 	if (options != NULL) {
4047 		maps[i++] = options;
4048 		optionmaps[j++] = options;
4049 	}
4050 
4051 	maps[i++] = named_g_defaults;
4052 	maps[i] = NULL;
4053 	optionmaps[j] = NULL;
4054 	if (config != NULL) {
4055 		cfgmaps[k++] = config;
4056 	}
4057 	cfgmaps[k] = NULL;
4058 
4059 	/*
4060 	 * Set the view's port number for outgoing queries.
4061 	 */
4062 	CHECKM(named_config_getport(config, &port), "port");
4063 	dns_view_setdstport(view, port);
4064 
4065 	/*
4066 	 * Make the list of response policy zone names for a view that
4067 	 * is used for real lookups and so cares about hints.
4068 	 */
4069 	obj = NULL;
4070 	if (view->rdclass == dns_rdataclass_in && need_hints &&
4071 	    named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS)
4072 	{
4073 		CHECK(configure_rpz(view, NULL, maps, obj, &old_rpz_ok));
4074 		rpz_configured = true;
4075 	}
4076 
4077 	obj = NULL;
4078 	if (view->rdclass == dns_rdataclass_in && need_hints &&
4079 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
4080 	{
4081 		CHECK(configure_catz(view, NULL, config, obj));
4082 		catz_configured = true;
4083 	}
4084 
4085 	/*
4086 	 * Configure the zones.
4087 	 */
4088 	zonelist = NULL;
4089 	if (voptions != NULL) {
4090 		(void)cfg_map_get(voptions, "zone", &zonelist);
4091 	} else {
4092 		(void)cfg_map_get(config, "zone", &zonelist);
4093 	}
4094 
4095 	/*
4096 	 * Load zone configuration
4097 	 */
4098 	for (element = cfg_list_first(zonelist); element != NULL;
4099 	     element = cfg_list_next(element))
4100 	{
4101 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
4102 		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
4103 				     viewlist, kasplist, actx, false,
4104 				     old_rpz_ok, false));
4105 		zone_element_latest = element;
4106 	}
4107 
4108 	/*
4109 	 * Check that a master or slave zone was found for each
4110 	 * zone named in the response policy statement
4111 	 * unless we are using RPZ service interface.
4112 	 */
4113 	if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
4114 		dns_rpz_num_t n;
4115 
4116 		for (n = 0; n < view->rpzs->p.num_zones; ++n) {
4117 			if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
4118 				char namebuf[DNS_NAME_FORMATSIZE];
4119 
4120 				dns_name_format(&view->rpzs->zones[n]->origin,
4121 						namebuf, sizeof(namebuf));
4122 				isc_log_write(named_g_lctx,
4123 					      NAMED_LOGCATEGORY_GENERAL,
4124 					      NAMED_LOGMODULE_SERVER,
4125 					      DNS_RPZ_ERROR_LEVEL,
4126 					      "rpz '%s'"
4127 					      " is not a master or slave zone",
4128 					      namebuf);
4129 				result = ISC_R_NOTFOUND;
4130 				goto cleanup;
4131 			}
4132 		}
4133 	}
4134 
4135 	/*
4136 	 * If we're allowing added zones, then load zone configuration
4137 	 * from the newzone file for zones that were added during previous
4138 	 * runs.
4139 	 */
4140 	CHECK(configure_newzones(view, config, vconfig, mctx, actx));
4141 
4142 	/*
4143 	 * Create Dynamically Loadable Zone driver.
4144 	 */
4145 	dlzlist = NULL;
4146 	if (voptions != NULL) {
4147 		(void)cfg_map_get(voptions, "dlz", &dlzlist);
4148 	} else {
4149 		(void)cfg_map_get(config, "dlz", &dlzlist);
4150 	}
4151 
4152 	for (element = cfg_list_first(dlzlist); element != NULL;
4153 	     element = cfg_list_next(element))
4154 	{
4155 		dlz = cfg_listelt_value(element);
4156 
4157 		obj = NULL;
4158 		(void)cfg_map_get(dlz, "database", &obj);
4159 		if (obj != NULL) {
4160 			dns_dlzdb_t *dlzdb = NULL;
4161 			const cfg_obj_t *name, *search = NULL;
4162 			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
4163 
4164 			if (s == NULL) {
4165 				result = ISC_R_NOMEMORY;
4166 				goto cleanup;
4167 			}
4168 
4169 			result = isc_commandline_strtoargv(mctx, s, &dlzargc,
4170 							   &dlzargv, 0);
4171 			if (result != ISC_R_SUCCESS) {
4172 				isc_mem_free(mctx, s);
4173 				goto cleanup;
4174 			}
4175 
4176 			name = cfg_map_getname(dlz);
4177 			result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
4178 					       dlzargv[0], dlzargc, dlzargv,
4179 					       &dlzdb);
4180 			isc_mem_free(mctx, s);
4181 			isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
4182 			if (result != ISC_R_SUCCESS) {
4183 				goto cleanup;
4184 			}
4185 
4186 			/*
4187 			 * If the DLZ backend supports configuration,
4188 			 * and is searchable, then call its configure
4189 			 * method now.  If not searchable, we'll take
4190 			 * care of it when we process the zone statement.
4191 			 */
4192 			(void)cfg_map_get(dlz, "search", &search);
4193 			if (search == NULL || cfg_obj_asboolean(search)) {
4194 				dlzdb->search = true;
4195 				result = dns_dlzconfigure(
4196 					view, dlzdb, dlzconfigure_callback);
4197 				if (result != ISC_R_SUCCESS) {
4198 					goto cleanup;
4199 				}
4200 				ISC_LIST_APPEND(view->dlz_searched, dlzdb,
4201 						link);
4202 			} else {
4203 				dlzdb->search = false;
4204 				ISC_LIST_APPEND(view->dlz_unsearched, dlzdb,
4205 						link);
4206 			}
4207 		}
4208 	}
4209 
4210 	/*
4211 	 * Obtain configuration parameters that affect the decision of whether
4212 	 * we can reuse/share an existing cache.
4213 	 */
4214 	obj = NULL;
4215 	result = named_config_get(maps, "max-cache-size", &obj);
4216 	INSIST(result == ISC_R_SUCCESS);
4217 	/*
4218 	 * If "-T maxcachesize=..." is in effect, it overrides any other
4219 	 * "max-cache-size" setting found in configuration, either implicit or
4220 	 * explicit.  For simplicity, the value passed to that command line
4221 	 * option is always treated as the number of bytes to set
4222 	 * "max-cache-size" to.
4223 	 */
4224 	if (named_g_maxcachesize != 0) {
4225 		max_cache_size = named_g_maxcachesize;
4226 	} else if (minimal_cache_allowed(maps, optionmaps)) {
4227 		/*
4228 		 * dns_cache_setcachesize() will adjust this to the smallest
4229 		 * allowed value.
4230 		 */
4231 		max_cache_size = 1;
4232 	} else if (cfg_obj_isstring(obj)) {
4233 		str = cfg_obj_asstring(obj);
4234 		INSIST(strcasecmp(str, "unlimited") == 0);
4235 		max_cache_size = 0;
4236 	} else if (cfg_obj_ispercentage(obj)) {
4237 		max_cache_size = SIZE_AS_PERCENT;
4238 		max_cache_size_percent = cfg_obj_aspercentage(obj);
4239 	} else {
4240 		isc_resourcevalue_t value;
4241 		value = cfg_obj_asuint64(obj);
4242 		if (value > SIZE_MAX) {
4243 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4244 				    "'max-cache-size "
4245 				    "%" PRIu64 "' "
4246 				    "is too large for this "
4247 				    "system; reducing to %lu",
4248 				    value, (unsigned long)SIZE_MAX);
4249 			value = SIZE_MAX;
4250 		}
4251 		max_cache_size = (size_t)value;
4252 	}
4253 
4254 	if (max_cache_size == SIZE_AS_PERCENT) {
4255 		uint64_t totalphys = isc_meminfo_totalphys();
4256 
4257 		max_cache_size =
4258 			(size_t)(totalphys * max_cache_size_percent / 100);
4259 		if (totalphys == 0) {
4260 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4261 				    "Unable to determine amount of physical "
4262 				    "memory, setting 'max-cache-size' to "
4263 				    "unlimited");
4264 		} else {
4265 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
4266 				    "'max-cache-size %d%%' "
4267 				    "- setting to %" PRIu64 "MB "
4268 				    "(out of %" PRIu64 "MB)",
4269 				    max_cache_size_percent,
4270 				    (uint64_t)(max_cache_size / (1024 * 1024)),
4271 				    totalphys / (1024 * 1024));
4272 		}
4273 	}
4274 
4275 	/* Check-names. */
4276 	obj = NULL;
4277 	result = named_checknames_get(maps, response_synonyms, &obj);
4278 	INSIST(result == ISC_R_SUCCESS);
4279 
4280 	str = cfg_obj_asstring(obj);
4281 	if (strcasecmp(str, "fail") == 0) {
4282 		resopts |= DNS_RESOLVER_CHECKNAMES |
4283 			   DNS_RESOLVER_CHECKNAMESFAIL;
4284 		view->checknames = true;
4285 	} else if (strcasecmp(str, "warn") == 0) {
4286 		resopts |= DNS_RESOLVER_CHECKNAMES;
4287 		view->checknames = false;
4288 	} else if (strcasecmp(str, "ignore") == 0) {
4289 		view->checknames = false;
4290 	} else {
4291 		UNREACHABLE();
4292 	}
4293 
4294 	obj = NULL;
4295 	result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj);
4296 	INSIST(result == ISC_R_SUCCESS);
4297 	zero_no_soattl = cfg_obj_asboolean(obj);
4298 
4299 	obj = NULL;
4300 	result = named_config_get(maps, "dns64", &obj);
4301 	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
4302 	    strcmp(view->name, "_meta"))
4303 	{
4304 		isc_netaddr_t na, suffix, *sp;
4305 		unsigned int prefixlen;
4306 		const char *server, *contact;
4307 		const cfg_obj_t *myobj;
4308 
4309 		myobj = NULL;
4310 		result = named_config_get(maps, "dns64-server", &myobj);
4311 		if (result == ISC_R_SUCCESS) {
4312 			server = cfg_obj_asstring(myobj);
4313 		} else {
4314 			server = NULL;
4315 		}
4316 
4317 		myobj = NULL;
4318 		result = named_config_get(maps, "dns64-contact", &myobj);
4319 		if (result == ISC_R_SUCCESS) {
4320 			contact = cfg_obj_asstring(myobj);
4321 		} else {
4322 			contact = NULL;
4323 		}
4324 
4325 		for (element = cfg_list_first(obj); element != NULL;
4326 		     element = cfg_list_next(element))
4327 		{
4328 			const cfg_obj_t *map = cfg_listelt_value(element);
4329 			dns_dns64_t *dns64 = NULL;
4330 			unsigned int dns64options = 0;
4331 
4332 			cfg_obj_asnetprefix(cfg_map_getname(map), &na,
4333 					    &prefixlen);
4334 
4335 			obj = NULL;
4336 			(void)cfg_map_get(map, "suffix", &obj);
4337 			if (obj != NULL) {
4338 				sp = &suffix;
4339 				isc_netaddr_fromsockaddr(
4340 					sp, cfg_obj_assockaddr(obj));
4341 			} else {
4342 				sp = NULL;
4343 			}
4344 
4345 			clients = mapped = excluded = NULL;
4346 			obj = NULL;
4347 			(void)cfg_map_get(map, "clients", &obj);
4348 			if (obj != NULL) {
4349 				result = cfg_acl_fromconfig(obj, config,
4350 							    named_g_lctx, actx,
4351 							    mctx, 0, &clients);
4352 				if (result != ISC_R_SUCCESS) {
4353 					goto cleanup;
4354 				}
4355 			}
4356 			obj = NULL;
4357 			(void)cfg_map_get(map, "mapped", &obj);
4358 			if (obj != NULL) {
4359 				result = cfg_acl_fromconfig(obj, config,
4360 							    named_g_lctx, actx,
4361 							    mctx, 0, &mapped);
4362 				if (result != ISC_R_SUCCESS) {
4363 					goto cleanup;
4364 				}
4365 			}
4366 			obj = NULL;
4367 			(void)cfg_map_get(map, "exclude", &obj);
4368 			if (obj != NULL) {
4369 				result = cfg_acl_fromconfig(obj, config,
4370 							    named_g_lctx, actx,
4371 							    mctx, 0, &excluded);
4372 				if (result != ISC_R_SUCCESS) {
4373 					goto cleanup;
4374 				}
4375 			} else {
4376 				if (named_g_mapped == NULL) {
4377 					result = create_mapped_acl();
4378 					if (result != ISC_R_SUCCESS) {
4379 						goto cleanup;
4380 					}
4381 				}
4382 				dns_acl_attach(named_g_mapped, &excluded);
4383 			}
4384 
4385 			obj = NULL;
4386 			(void)cfg_map_get(map, "recursive-only", &obj);
4387 			if (obj != NULL && cfg_obj_asboolean(obj)) {
4388 				dns64options |= DNS_DNS64_RECURSIVE_ONLY;
4389 			}
4390 
4391 			obj = NULL;
4392 			(void)cfg_map_get(map, "break-dnssec", &obj);
4393 			if (obj != NULL && cfg_obj_asboolean(obj)) {
4394 				dns64options |= DNS_DNS64_BREAK_DNSSEC;
4395 			}
4396 
4397 			result = dns_dns64_create(mctx, &na, prefixlen, sp,
4398 						  clients, mapped, excluded,
4399 						  dns64options, &dns64);
4400 			if (result != ISC_R_SUCCESS) {
4401 				goto cleanup;
4402 			}
4403 			dns_dns64_append(&view->dns64, dns64);
4404 			view->dns64cnt++;
4405 			result = dns64_reverse(view, mctx, &na, prefixlen,
4406 					       server, contact);
4407 			if (result != ISC_R_SUCCESS) {
4408 				goto cleanup;
4409 			}
4410 			if (clients != NULL) {
4411 				dns_acl_detach(&clients);
4412 			}
4413 			if (mapped != NULL) {
4414 				dns_acl_detach(&mapped);
4415 			}
4416 			if (excluded != NULL) {
4417 				dns_acl_detach(&excluded);
4418 			}
4419 		}
4420 	}
4421 
4422 	obj = NULL;
4423 	result = named_config_get(maps, "dnssec-accept-expired", &obj);
4424 	INSIST(result == ISC_R_SUCCESS);
4425 	view->acceptexpired = cfg_obj_asboolean(obj);
4426 
4427 	obj = NULL;
4428 	/* 'optionmaps', not 'maps': don't check named_g_defaults yet */
4429 	(void)named_config_get(optionmaps, "dnssec-validation", &obj);
4430 	if (obj == NULL) {
4431 		/*
4432 		 * Default to VALIDATION_DEFAULT as set in config.c.
4433 		 */
4434 		(void)cfg_map_get(named_g_defaults, "dnssec-validation", &obj);
4435 		INSIST(obj != NULL);
4436 	}
4437 	if (obj != NULL) {
4438 		if (cfg_obj_isboolean(obj)) {
4439 			view->enablevalidation = cfg_obj_asboolean(obj);
4440 		} else {
4441 			/*
4442 			 * If dnssec-validation is set but not boolean,
4443 			 * then it must be "auto"
4444 			 */
4445 			view->enablevalidation = true;
4446 			auto_root = true;
4447 		}
4448 	}
4449 
4450 	obj = NULL;
4451 	result = named_config_get(maps, "max-cache-ttl", &obj);
4452 	INSIST(result == ISC_R_SUCCESS);
4453 	view->maxcachettl = cfg_obj_asduration(obj);
4454 
4455 	obj = NULL;
4456 	result = named_config_get(maps, "max-ncache-ttl", &obj);
4457 	INSIST(result == ISC_R_SUCCESS);
4458 	view->maxncachettl = cfg_obj_asduration(obj);
4459 
4460 	obj = NULL;
4461 	result = named_config_get(maps, "min-cache-ttl", &obj);
4462 	INSIST(result == ISC_R_SUCCESS);
4463 	view->mincachettl = cfg_obj_asduration(obj);
4464 
4465 	obj = NULL;
4466 	result = named_config_get(maps, "min-ncache-ttl", &obj);
4467 	INSIST(result == ISC_R_SUCCESS);
4468 	view->minncachettl = cfg_obj_asduration(obj);
4469 
4470 	obj = NULL;
4471 	result = named_config_get(maps, "synth-from-dnssec", &obj);
4472 	INSIST(result == ISC_R_SUCCESS);
4473 	view->synthfromdnssec = cfg_obj_asboolean(obj);
4474 
4475 	obj = NULL;
4476 	result = named_config_get(maps, "stale-cache-enable", &obj);
4477 	INSIST(result == ISC_R_SUCCESS);
4478 	if (cfg_obj_asboolean(obj)) {
4479 		obj = NULL;
4480 		result = named_config_get(maps, "max-stale-ttl", &obj);
4481 		INSIST(result == ISC_R_SUCCESS);
4482 		max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4483 	}
4484 	/*
4485 	 * If 'stale-cache-enable' is false, max_stale_ttl is set to 0,
4486 	 * meaning keeping stale RRsets in cache is disabled.
4487 	 */
4488 
4489 	obj = NULL;
4490 	result = named_config_get(maps, "stale-answer-enable", &obj);
4491 	INSIST(result == ISC_R_SUCCESS);
4492 	view->staleanswersenable = cfg_obj_asboolean(obj);
4493 
4494 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
4495 				   view->rdclass, &pview);
4496 	if (result == ISC_R_SUCCESS) {
4497 		view->staleanswersok = pview->staleanswersok;
4498 		dns_view_detach(&pview);
4499 	} else {
4500 		view->staleanswersok = dns_stale_answer_conf;
4501 	}
4502 
4503 	obj = NULL;
4504 	result = named_config_get(maps, "stale-answer-client-timeout", &obj);
4505 	INSIST(result == ISC_R_SUCCESS);
4506 	if (cfg_obj_isstring(obj)) {
4507 		/*
4508 		 * The only string values available for this option
4509 		 * are "disabled" and "off".
4510 		 * We use (uint32_t) -1 to represent disabled since
4511 		 * a value of zero means that stale data can be used
4512 		 * to promptly answer the query, while an attempt to
4513 		 * refresh the RRset will still be made in background.
4514 		 */
4515 		view->staleanswerclienttimeout = (uint32_t)-1;
4516 	} else {
4517 		view->staleanswerclienttimeout = cfg_obj_asuint32(obj);
4518 	}
4519 
4520 	obj = NULL;
4521 	result = named_config_get(maps, "stale-refresh-time", &obj);
4522 	INSIST(result == ISC_R_SUCCESS);
4523 	stale_refresh_time = cfg_obj_asduration(obj);
4524 
4525 	/*
4526 	 * Configure the view's cache.
4527 	 *
4528 	 * First, check to see if there are any attach-cache options.  If yes,
4529 	 * attempt to lookup an existing cache at attach it to the view.  If
4530 	 * there is not one, then try to reuse an existing cache if possible;
4531 	 * otherwise create a new cache.
4532 	 *
4533 	 * Note that the ADB is not preserved or shared in either case.
4534 	 *
4535 	 * When a matching view is found, the associated statistics are also
4536 	 * retrieved and reused.
4537 	 *
4538 	 * XXX Determining when it is safe to reuse or share a cache is tricky.
4539 	 * When the view's configuration changes, the cached data may become
4540 	 * invalid because it reflects our old view of the world.  We check
4541 	 * some of the configuration parameters that could invalidate the cache
4542 	 * or otherwise make it unshareable, but there are other configuration
4543 	 * options that should be checked.  For example, if a view uses a
4544 	 * forwarder, changes in the forwarder configuration may invalidate
4545 	 * the cache.  At the moment, it's the administrator's responsibility to
4546 	 * ensure these configuration options don't invalidate reusing/sharing.
4547 	 */
4548 	obj = NULL;
4549 	result = named_config_get(maps, "attach-cache", &obj);
4550 	if (result == ISC_R_SUCCESS) {
4551 		cachename = cfg_obj_asstring(obj);
4552 	} else {
4553 		cachename = view->name;
4554 	}
4555 	cache = NULL;
4556 	nsc = cachelist_find(cachelist, cachename, view->rdclass);
4557 	if (nsc != NULL) {
4558 		if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
4559 				    max_cache_size, max_stale_ttl,
4560 				    stale_refresh_time))
4561 		{
4562 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4563 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4564 				      "views %s and %s can't share the cache "
4565 				      "due to configuration parameter mismatch",
4566 				      nsc->primaryview->name, view->name);
4567 			result = ISC_R_FAILURE;
4568 			goto cleanup;
4569 		}
4570 		dns_cache_attach(nsc->cache, &cache);
4571 		shared_cache = true;
4572 	} else {
4573 		if (strcmp(cachename, view->name) == 0) {
4574 			result = dns_viewlist_find(&named_g_server->viewlist,
4575 						   cachename, view->rdclass,
4576 						   &pview);
4577 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4578 			{
4579 				goto cleanup;
4580 			}
4581 			if (pview != NULL) {
4582 				if (!cache_reusable(pview, view,
4583 						    zero_no_soattl))
4584 				{
4585 					isc_log_write(named_g_lctx,
4586 						      NAMED_LOGCATEGORY_GENERAL,
4587 						      NAMED_LOGMODULE_SERVER,
4588 						      ISC_LOG_DEBUG(1),
4589 						      "cache cannot be reused "
4590 						      "for view %s due to "
4591 						      "configuration parameter "
4592 						      "mismatch",
4593 						      view->name);
4594 				} else {
4595 					INSIST(pview->cache != NULL);
4596 					isc_log_write(named_g_lctx,
4597 						      NAMED_LOGCATEGORY_GENERAL,
4598 						      NAMED_LOGMODULE_SERVER,
4599 						      ISC_LOG_DEBUG(3),
4600 						      "reusing existing cache");
4601 					reused_cache = true;
4602 					dns_cache_attach(pview->cache, &cache);
4603 				}
4604 				dns_view_getresstats(pview, &resstats);
4605 				dns_view_getresquerystats(pview,
4606 							  &resquerystats);
4607 				dns_view_detach(&pview);
4608 			}
4609 		}
4610 		if (cache == NULL) {
4611 			/*
4612 			 * Create a cache with the desired name.  This normally
4613 			 * equals the view name, but may also be a forward
4614 			 * reference to a view that share the cache with this
4615 			 * view but is not yet configured.  If it is not the
4616 			 * view name but not a forward reference either, then it
4617 			 * is simply a named cache that is not shared.
4618 			 *
4619 			 * We use two separate memory contexts for the
4620 			 * cache, for the main cache memory and the heap
4621 			 * memory.
4622 			 */
4623 			isc_mem_create(&cmctx);
4624 			isc_mem_setname(cmctx, "cache", NULL);
4625 			isc_mem_create(&hmctx);
4626 			isc_mem_setname(hmctx, "cache_heap", NULL);
4627 			CHECK(dns_cache_create(cmctx, hmctx, named_g_taskmgr,
4628 					       named_g_timermgr, view->rdclass,
4629 					       cachename, "rbt", 0, NULL,
4630 					       &cache));
4631 			isc_mem_detach(&cmctx);
4632 			isc_mem_detach(&hmctx);
4633 		}
4634 		nsc = isc_mem_get(mctx, sizeof(*nsc));
4635 		nsc->cache = NULL;
4636 		dns_cache_attach(cache, &nsc->cache);
4637 		nsc->primaryview = view;
4638 		nsc->needflush = false;
4639 		nsc->adbsizeadjusted = false;
4640 		nsc->rdclass = view->rdclass;
4641 		ISC_LINK_INIT(nsc, link);
4642 		ISC_LIST_APPEND(*cachelist, nsc, link);
4643 	}
4644 	dns_view_setcache(view, cache, shared_cache);
4645 
4646 	/*
4647 	 * cache-file cannot be inherited if views are present, but this
4648 	 * should be caught by the configuration checking stage.
4649 	 */
4650 	obj = NULL;
4651 	result = named_config_get(maps, "cache-file", &obj);
4652 	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
4653 		CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
4654 		if (!reused_cache && !shared_cache) {
4655 			CHECK(dns_cache_load(cache));
4656 		}
4657 	}
4658 
4659 	dns_cache_setcachesize(cache, max_cache_size);
4660 	dns_cache_setservestalettl(cache, max_stale_ttl);
4661 	dns_cache_setservestalerefresh(cache, stale_refresh_time);
4662 
4663 	dns_cache_detach(&cache);
4664 
4665 	obj = NULL;
4666 	result = named_config_get(maps, "stale-answer-ttl", &obj);
4667 	INSIST(result == ISC_R_SUCCESS);
4668 	view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4669 
4670 	/*
4671 	 * Resolver.
4672 	 *
4673 	 * XXXRTH  Hardwired number of tasks.
4674 	 */
4675 	CHECK(get_view_querysource_dispatch(
4676 		maps, AF_INET, &dispatch4, &dscp4,
4677 		(ISC_LIST_PREV(view, link) == NULL)));
4678 	CHECK(get_view_querysource_dispatch(
4679 		maps, AF_INET6, &dispatch6, &dscp6,
4680 		(ISC_LIST_PREV(view, link) == NULL)));
4681 	if (dispatch4 == NULL && dispatch6 == NULL) {
4682 		UNEXPECTED_ERROR(__FILE__, __LINE__,
4683 				 "unable to obtain neither an IPv4 nor"
4684 				 " an IPv6 dispatch");
4685 		result = ISC_R_UNEXPECTED;
4686 		goto cleanup;
4687 	}
4688 
4689 	if (resstats == NULL) {
4690 		CHECK(isc_stats_create(mctx, &resstats,
4691 				       dns_resstatscounter_max));
4692 	}
4693 	dns_view_setresstats(view, resstats);
4694 	if (resquerystats == NULL) {
4695 		CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
4696 	}
4697 	dns_view_setresquerystats(view, resquerystats);
4698 
4699 	ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH);
4700 	CHECK(dns_view_createresolver(
4701 		view, named_g_taskmgr, RESOLVER_NTASKS_PERCPU * named_g_cpus,
4702 		ndisp, named_g_socketmgr, named_g_timermgr, resopts,
4703 		named_g_dispatchmgr, dispatch4, dispatch6));
4704 
4705 	if (dscp4 == -1) {
4706 		dscp4 = named_g_dscp;
4707 	}
4708 	if (dscp6 == -1) {
4709 		dscp6 = named_g_dscp;
4710 	}
4711 	if (dscp4 != -1) {
4712 		dns_resolver_setquerydscp4(view->resolver, dscp4);
4713 	}
4714 	if (dscp6 != -1) {
4715 		dns_resolver_setquerydscp6(view->resolver, dscp6);
4716 	}
4717 
4718 	/*
4719 	 * Set the ADB cache size to 1/8th of the max-cache-size or
4720 	 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
4721 	 */
4722 	max_adb_size = 0;
4723 	if (max_cache_size != 0U) {
4724 		max_adb_size = max_cache_size / 8;
4725 		if (max_adb_size == 0U) {
4726 			max_adb_size = 1; /* Force minimum. */
4727 		}
4728 		if (view != nsc->primaryview &&
4729 		    max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE)
4730 		{
4731 			max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
4732 			if (!nsc->adbsizeadjusted) {
4733 				dns_adb_setadbsize(nsc->primaryview->adb,
4734 						   MAX_ADB_SIZE_FOR_CACHESHARE);
4735 				nsc->adbsizeadjusted = true;
4736 			}
4737 		}
4738 	}
4739 	dns_adb_setadbsize(view->adb, max_adb_size);
4740 
4741 	/*
4742 	 * Set up ADB quotas
4743 	 */
4744 	{
4745 		uint32_t fps, freq;
4746 		double low, high, discount;
4747 
4748 		obj = NULL;
4749 		result = named_config_get(maps, "fetches-per-server", &obj);
4750 		INSIST(result == ISC_R_SUCCESS);
4751 		obj2 = cfg_tuple_get(obj, "fetches");
4752 		fps = cfg_obj_asuint32(obj2);
4753 		obj2 = cfg_tuple_get(obj, "response");
4754 		if (!cfg_obj_isvoid(obj2)) {
4755 			const char *resp = cfg_obj_asstring(obj2);
4756 			isc_result_t r = DNS_R_SERVFAIL;
4757 
4758 			if (strcasecmp(resp, "drop") == 0) {
4759 				r = DNS_R_DROP;
4760 			} else if (strcasecmp(resp, "fail") == 0) {
4761 				r = DNS_R_SERVFAIL;
4762 			} else {
4763 				UNREACHABLE();
4764 			}
4765 
4766 			dns_resolver_setquotaresponse(view->resolver,
4767 						      dns_quotatype_server, r);
4768 		}
4769 
4770 		obj = NULL;
4771 		result = named_config_get(maps, "fetch-quota-params", &obj);
4772 		INSIST(result == ISC_R_SUCCESS);
4773 
4774 		obj2 = cfg_tuple_get(obj, "frequency");
4775 		freq = cfg_obj_asuint32(obj2);
4776 
4777 		obj2 = cfg_tuple_get(obj, "low");
4778 		low = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4779 
4780 		obj2 = cfg_tuple_get(obj, "high");
4781 		high = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4782 
4783 		obj2 = cfg_tuple_get(obj, "discount");
4784 		discount = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4785 
4786 		dns_adb_setquota(view->adb, fps, freq, low, high, discount);
4787 	}
4788 
4789 	/*
4790 	 * Set resolver's lame-ttl.
4791 	 */
4792 	obj = NULL;
4793 	result = named_config_get(maps, "lame-ttl", &obj);
4794 	INSIST(result == ISC_R_SUCCESS);
4795 	lame_ttl = cfg_obj_asduration(obj);
4796 	if (lame_ttl > 0) {
4797 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4798 			    "disabling lame cache despite lame-ttl > 0 as it "
4799 			    "may cause performance issues");
4800 		lame_ttl = 0;
4801 	}
4802 	dns_resolver_setlamettl(view->resolver, lame_ttl);
4803 
4804 	/*
4805 	 * Set the resolver's query timeout.
4806 	 */
4807 	obj = NULL;
4808 	result = named_config_get(maps, "resolver-query-timeout", &obj);
4809 	INSIST(result == ISC_R_SUCCESS);
4810 	query_timeout = cfg_obj_asuint32(obj);
4811 	dns_resolver_settimeout(view->resolver, query_timeout);
4812 
4813 	/*
4814 	 * Adjust stale-answer-client-timeout upper bound
4815 	 * to be resolver-query-timeout - 1s.
4816 	 * This assignment is safe as dns_resolver_settimeout()
4817 	 * ensures that resolver->querytimeout value will be in the
4818 	 * [MINIMUM_QUERY_TIMEOUT, MAXIMUM_QUERY_TIMEOUT] range and
4819 	 * MINIMUM_QUERY_TIMEOUT is > 1000 (in ms).
4820 	 */
4821 	if (view->staleanswerclienttimeout != (uint32_t)-1 &&
4822 	    view->staleanswerclienttimeout >
4823 		    (dns_resolver_gettimeout(view->resolver) - 1000))
4824 	{
4825 		view->staleanswerclienttimeout =
4826 			dns_resolver_gettimeout(view->resolver) - 1000;
4827 		isc_log_write(
4828 			named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4829 			NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
4830 			"stale-answer-client-timeout adjusted to %" PRIu32,
4831 			view->staleanswerclienttimeout);
4832 	}
4833 
4834 	/* Specify whether to use 0-TTL for negative response for SOA query */
4835 	dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
4836 
4837 	/*
4838 	 * Set the resolver's EDNS UDP size.
4839 	 */
4840 	obj = NULL;
4841 	result = named_config_get(maps, "edns-udp-size", &obj);
4842 	INSIST(result == ISC_R_SUCCESS);
4843 	udpsize = cfg_obj_asuint32(obj);
4844 	if (udpsize < 512) {
4845 		udpsize = 512;
4846 	}
4847 	if (udpsize > 4096) {
4848 		udpsize = 4096;
4849 	}
4850 	dns_resolver_setudpsize(view->resolver, (uint16_t)udpsize);
4851 
4852 	/*
4853 	 * Set the maximum UDP response size.
4854 	 */
4855 	obj = NULL;
4856 	result = named_config_get(maps, "max-udp-size", &obj);
4857 	INSIST(result == ISC_R_SUCCESS);
4858 	udpsize = cfg_obj_asuint32(obj);
4859 	if (udpsize < 512) {
4860 		udpsize = 512;
4861 	}
4862 	if (udpsize > 4096) {
4863 		udpsize = 4096;
4864 	}
4865 	view->maxudp = udpsize;
4866 
4867 	/*
4868 	 * Set the maximum UDP when a COOKIE is not provided.
4869 	 */
4870 	obj = NULL;
4871 	result = named_config_get(maps, "nocookie-udp-size", &obj);
4872 	INSIST(result == ISC_R_SUCCESS);
4873 	udpsize = cfg_obj_asuint32(obj);
4874 	if (udpsize < 128) {
4875 		udpsize = 128;
4876 	}
4877 	if (udpsize > view->maxudp) {
4878 		udpsize = view->maxudp;
4879 	}
4880 	view->nocookieudp = udpsize;
4881 
4882 	/*
4883 	 * Set the maximum rsa exponent bits.
4884 	 */
4885 	obj = NULL;
4886 	result = named_config_get(maps, "max-rsa-exponent-size", &obj);
4887 	INSIST(result == ISC_R_SUCCESS);
4888 	maxbits = cfg_obj_asuint32(obj);
4889 	if (maxbits != 0 && maxbits < 35) {
4890 		maxbits = 35;
4891 	}
4892 	if (maxbits > 4096) {
4893 		maxbits = 4096;
4894 	}
4895 	view->maxbits = maxbits;
4896 
4897 	/*
4898 	 * Set resolver retry parameters.
4899 	 */
4900 	obj = NULL;
4901 	CHECK(named_config_get(maps, "resolver-retry-interval", &obj));
4902 	resolver_param = cfg_obj_asuint32(obj);
4903 	if (resolver_param > 0) {
4904 		dns_resolver_setretryinterval(view->resolver, resolver_param);
4905 	}
4906 
4907 	obj = NULL;
4908 	CHECK(named_config_get(maps, "resolver-nonbackoff-tries", &obj));
4909 	resolver_param = cfg_obj_asuint32(obj);
4910 	if (resolver_param > 0) {
4911 		dns_resolver_setnonbackofftries(view->resolver, resolver_param);
4912 	}
4913 
4914 	/*
4915 	 * Set supported DNSSEC algorithms.
4916 	 */
4917 	dns_resolver_reset_algorithms(view->resolver);
4918 	disabled = NULL;
4919 	(void)named_config_get(maps, "disable-algorithms", &disabled);
4920 	if (disabled != NULL) {
4921 		for (element = cfg_list_first(disabled); element != NULL;
4922 		     element = cfg_list_next(element))
4923 		{
4924 			CHECK(disable_algorithms(cfg_listelt_value(element),
4925 						 view->resolver));
4926 		}
4927 	}
4928 
4929 	/*
4930 	 * Set supported DS digest types.
4931 	 */
4932 	dns_resolver_reset_ds_digests(view->resolver);
4933 	disabled = NULL;
4934 	(void)named_config_get(maps, "disable-ds-digests", &disabled);
4935 	if (disabled != NULL) {
4936 		for (element = cfg_list_first(disabled); element != NULL;
4937 		     element = cfg_list_next(element))
4938 		{
4939 			CHECK(disable_ds_digests(cfg_listelt_value(element),
4940 						 view->resolver));
4941 		}
4942 	}
4943 
4944 	/*
4945 	 * A global or view "forwarders" option, if present,
4946 	 * creates an entry for "." in the forwarding table.
4947 	 */
4948 	forwardtype = NULL;
4949 	forwarders = NULL;
4950 	(void)named_config_get(maps, "forward", &forwardtype);
4951 	(void)named_config_get(maps, "forwarders", &forwarders);
4952 	if (forwarders != NULL) {
4953 		CHECK(configure_forward(config, view, dns_rootname, forwarders,
4954 					forwardtype));
4955 	}
4956 
4957 	/*
4958 	 * Dual Stack Servers.
4959 	 */
4960 	alternates = NULL;
4961 	(void)named_config_get(maps, "dual-stack-servers", &alternates);
4962 	if (alternates != NULL) {
4963 		CHECK(configure_alternates(config, view, alternates));
4964 	}
4965 
4966 	/*
4967 	 * We have default hints for class IN if we need them.
4968 	 */
4969 	if (view->rdclass == dns_rdataclass_in && view->hints == NULL) {
4970 		dns_view_sethints(view, named_g_server->in_roothints);
4971 	}
4972 
4973 	/*
4974 	 * If we still have no hints, this is a non-IN view with no
4975 	 * "hints zone" configured.  Issue a warning, except if this
4976 	 * is a root server.  Root servers never need to consult
4977 	 * their hints, so it's no point requiring users to configure
4978 	 * them.
4979 	 */
4980 	if (view->hints == NULL) {
4981 		dns_zone_t *rootzone = NULL;
4982 		(void)dns_view_findzone(view, dns_rootname, &rootzone);
4983 		if (rootzone != NULL) {
4984 			dns_zone_detach(&rootzone);
4985 			need_hints = false;
4986 		}
4987 		if (need_hints) {
4988 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4989 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
4990 				      "no root hints for view '%s'",
4991 				      view->name);
4992 		}
4993 	}
4994 
4995 	/*
4996 	 * Configure the view's TSIG keys.
4997 	 */
4998 	CHECK(named_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
4999 	if (named_g_server->sessionkey != NULL) {
5000 		CHECK(dns_tsigkeyring_add(ring, named_g_server->session_keyname,
5001 					  named_g_server->sessionkey));
5002 	}
5003 	dns_view_setkeyring(view, ring);
5004 	dns_tsigkeyring_detach(&ring);
5005 
5006 	/*
5007 	 * See if we can re-use a dynamic key ring.
5008 	 */
5009 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
5010 				   view->rdclass, &pview);
5011 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
5012 		goto cleanup;
5013 	}
5014 	if (pview != NULL) {
5015 		dns_view_getdynamickeyring(pview, &ring);
5016 		if (ring != NULL) {
5017 			dns_view_setdynamickeyring(view, ring);
5018 		}
5019 		dns_tsigkeyring_detach(&ring);
5020 		dns_view_detach(&pview);
5021 	} else {
5022 		dns_view_restorekeyring(view);
5023 	}
5024 
5025 	/*
5026 	 * Configure the view's peer list.
5027 	 */
5028 	{
5029 		const cfg_obj_t *peers = NULL;
5030 		dns_peerlist_t *newpeers = NULL;
5031 
5032 		(void)named_config_get(cfgmaps, "server", &peers);
5033 		CHECK(dns_peerlist_new(mctx, &newpeers));
5034 		for (element = cfg_list_first(peers); element != NULL;
5035 		     element = cfg_list_next(element))
5036 		{
5037 			const cfg_obj_t *cpeer = cfg_listelt_value(element);
5038 			dns_peer_t *peer;
5039 
5040 			CHECK(configure_peer(cpeer, mctx, &peer));
5041 			dns_peerlist_addpeer(newpeers, peer);
5042 			dns_peer_detach(&peer);
5043 		}
5044 		dns_peerlist_detach(&view->peers);
5045 		view->peers = newpeers; /* Transfer ownership. */
5046 	}
5047 
5048 	/*
5049 	 *	Configure the views rrset-order.
5050 	 */
5051 	{
5052 		const cfg_obj_t *rrsetorder = NULL;
5053 
5054 		(void)named_config_get(maps, "rrset-order", &rrsetorder);
5055 		CHECK(dns_order_create(mctx, &order));
5056 		for (element = cfg_list_first(rrsetorder); element != NULL;
5057 		     element = cfg_list_next(element))
5058 		{
5059 			const cfg_obj_t *ent = cfg_listelt_value(element);
5060 
5061 			CHECK(configure_order(order, ent));
5062 		}
5063 		if (view->order != NULL) {
5064 			dns_order_detach(&view->order);
5065 		}
5066 		dns_order_attach(order, &view->order);
5067 		dns_order_detach(&order);
5068 	}
5069 	/*
5070 	 * Copy the aclenv object.
5071 	 */
5072 	dns_aclenv_copy(&view->aclenv, ns_interfacemgr_getaclenv(
5073 					       named_g_server->interfacemgr));
5074 
5075 	/*
5076 	 * Configure the "match-clients" and "match-destinations" ACL.
5077 	 * (These are only meaningful at the view level, but 'config'
5078 	 * must be passed so that named ACLs defined at the global level
5079 	 * can be retrieved.)
5080 	 */
5081 	CHECK(configure_view_acl(vconfig, config, NULL, "match-clients", NULL,
5082 				 actx, named_g_mctx, &view->matchclients));
5083 	CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations",
5084 				 NULL, actx, named_g_mctx,
5085 				 &view->matchdestinations));
5086 
5087 	/*
5088 	 * Configure the "match-recursive-only" option.
5089 	 */
5090 	obj = NULL;
5091 	(void)named_config_get(maps, "match-recursive-only", &obj);
5092 	if (obj != NULL && cfg_obj_asboolean(obj)) {
5093 		view->matchrecursiveonly = true;
5094 	} else {
5095 		view->matchrecursiveonly = false;
5096 	}
5097 
5098 	/*
5099 	 * Configure other configurable data.
5100 	 */
5101 	obj = NULL;
5102 	result = named_config_get(maps, "recursion", &obj);
5103 	INSIST(result == ISC_R_SUCCESS);
5104 	view->recursion = cfg_obj_asboolean(obj);
5105 
5106 	obj = NULL;
5107 	result = named_config_get(maps, "qname-minimization", &obj);
5108 	INSIST(result == ISC_R_SUCCESS);
5109 	qminmode = cfg_obj_asstring(obj);
5110 	INSIST(qminmode != NULL);
5111 	if (!strcmp(qminmode, "strict")) {
5112 		view->qminimization = true;
5113 		view->qmin_strict = true;
5114 	} else if (!strcmp(qminmode, "relaxed")) {
5115 		view->qminimization = true;
5116 		view->qmin_strict = false;
5117 	} else { /* "disabled" or "off" */
5118 		view->qminimization = false;
5119 		view->qmin_strict = false;
5120 	}
5121 
5122 	obj = NULL;
5123 	result = named_config_get(maps, "auth-nxdomain", &obj);
5124 	INSIST(result == ISC_R_SUCCESS);
5125 	view->auth_nxdomain = cfg_obj_asboolean(obj);
5126 
5127 	obj = NULL;
5128 	result = named_config_get(maps, "glue-cache", &obj);
5129 	INSIST(result == ISC_R_SUCCESS);
5130 	view->use_glue_cache = cfg_obj_asboolean(obj);
5131 
5132 	obj = NULL;
5133 	result = named_config_get(maps, "minimal-any", &obj);
5134 	INSIST(result == ISC_R_SUCCESS);
5135 	view->minimal_any = cfg_obj_asboolean(obj);
5136 
5137 	obj = NULL;
5138 	result = named_config_get(maps, "minimal-responses", &obj);
5139 	INSIST(result == ISC_R_SUCCESS);
5140 	if (cfg_obj_isboolean(obj)) {
5141 		if (cfg_obj_asboolean(obj)) {
5142 			view->minimalresponses = dns_minimal_yes;
5143 		} else {
5144 			view->minimalresponses = dns_minimal_no;
5145 		}
5146 	} else {
5147 		str = cfg_obj_asstring(obj);
5148 		if (strcasecmp(str, "no-auth") == 0) {
5149 			view->minimalresponses = dns_minimal_noauth;
5150 		} else if (strcasecmp(str, "no-auth-recursive") == 0) {
5151 			view->minimalresponses = dns_minimal_noauthrec;
5152 		} else {
5153 			UNREACHABLE();
5154 		}
5155 	}
5156 
5157 	obj = NULL;
5158 	result = named_config_get(maps, "transfer-format", &obj);
5159 	INSIST(result == ISC_R_SUCCESS);
5160 	str = cfg_obj_asstring(obj);
5161 	if (strcasecmp(str, "many-answers") == 0) {
5162 		view->transfer_format = dns_many_answers;
5163 	} else if (strcasecmp(str, "one-answer") == 0) {
5164 		view->transfer_format = dns_one_answer;
5165 	} else {
5166 		UNREACHABLE();
5167 	}
5168 
5169 	obj = NULL;
5170 	result = named_config_get(maps, "trust-anchor-telemetry", &obj);
5171 	INSIST(result == ISC_R_SUCCESS);
5172 	view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
5173 
5174 	obj = NULL;
5175 	result = named_config_get(maps, "root-key-sentinel", &obj);
5176 	INSIST(result == ISC_R_SUCCESS);
5177 	view->root_key_sentinel = cfg_obj_asboolean(obj);
5178 
5179 	/*
5180 	 * Set the "allow-query", "allow-query-cache", "allow-recursion",
5181 	 * "allow-recursion-on" and "allow-query-cache-on" ACLs if
5182 	 * configured in named.conf, but NOT from the global defaults.
5183 	 * This is done by leaving the third argument to configure_view_acl()
5184 	 * NULL.
5185 	 *
5186 	 * We ignore the global defaults here because these ACLs
5187 	 * can inherit from each other.  If any are still unset after
5188 	 * applying the inheritance rules, we'll look up the defaults at
5189 	 * that time.
5190 	 */
5191 
5192 	/* named.conf only */
5193 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query", NULL,
5194 				 actx, named_g_mctx, &view->queryacl));
5195 
5196 	/* named.conf only */
5197 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache",
5198 				 NULL, actx, named_g_mctx, &view->cacheacl));
5199 	/* named.conf only */
5200 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
5201 				 NULL, actx, named_g_mctx, &view->cacheonacl));
5202 
5203 	if (strcmp(view->name, "_bind") != 0 &&
5204 	    view->rdclass != dns_rdataclass_chaos)
5205 	{
5206 		/* named.conf only */
5207 		CHECK(configure_view_acl(vconfig, config, NULL,
5208 					 "allow-recursion", NULL, actx,
5209 					 named_g_mctx, &view->recursionacl));
5210 		/* named.conf only */
5211 		CHECK(configure_view_acl(vconfig, config, NULL,
5212 					 "allow-recursion-on", NULL, actx,
5213 					 named_g_mctx, &view->recursiononacl));
5214 	}
5215 
5216 	if (view->recursion) {
5217 		/*
5218 		 * "allow-query-cache" inherits from "allow-recursion" if set,
5219 		 * otherwise from "allow-query" if set.
5220 		 */
5221 		if (view->cacheacl == NULL) {
5222 			if (view->recursionacl != NULL) {
5223 				dns_acl_attach(view->recursionacl,
5224 					       &view->cacheacl);
5225 			} else if (view->queryacl != NULL) {
5226 				dns_acl_attach(view->queryacl, &view->cacheacl);
5227 			}
5228 		}
5229 
5230 		/*
5231 		 * "allow-recursion" inherits from "allow-query-cache" if set,
5232 		 * otherwise from "allow-query" if set.
5233 		 */
5234 		if (view->recursionacl == NULL) {
5235 			if (view->cacheacl != NULL) {
5236 				dns_acl_attach(view->cacheacl,
5237 					       &view->recursionacl);
5238 			} else if (view->queryacl != NULL) {
5239 				dns_acl_attach(view->queryacl,
5240 					       &view->recursionacl);
5241 			}
5242 		}
5243 
5244 		/*
5245 		 * "allow-query-cache-on" inherits from "allow-recursion-on"
5246 		 * if set.
5247 		 */
5248 		if (view->cacheonacl == NULL) {
5249 			if (view->recursiononacl != NULL) {
5250 				dns_acl_attach(view->recursiononacl,
5251 					       &view->cacheonacl);
5252 			}
5253 		}
5254 
5255 		/*
5256 		 * "allow-recursion-on" inherits from "allow-query-cache-on"
5257 		 * if set.
5258 		 */
5259 		if (view->recursiononacl == NULL) {
5260 			if (view->cacheonacl != NULL) {
5261 				dns_acl_attach(view->cacheonacl,
5262 					       &view->recursiononacl);
5263 			}
5264 		}
5265 
5266 		/*
5267 		 * If any are still unset at this point, we now get default
5268 		 * values for from the global config.
5269 		 */
5270 
5271 		if (view->recursionacl == NULL) {
5272 			/* global default only */
5273 			CHECK(configure_view_acl(
5274 				NULL, NULL, named_g_config, "allow-recursion",
5275 				NULL, actx, named_g_mctx, &view->recursionacl));
5276 		}
5277 		if (view->recursiononacl == NULL) {
5278 			/* global default only */
5279 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5280 						 "allow-recursion-on", NULL,
5281 						 actx, named_g_mctx,
5282 						 &view->recursiononacl));
5283 		}
5284 		if (view->cacheacl == NULL) {
5285 			/* global default only */
5286 			CHECK(configure_view_acl(
5287 				NULL, NULL, named_g_config, "allow-query-cache",
5288 				NULL, actx, named_g_mctx, &view->cacheacl));
5289 		}
5290 		if (view->cacheonacl == NULL) {
5291 			/* global default only */
5292 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5293 						 "allow-query-cache-on", NULL,
5294 						 actx, named_g_mctx,
5295 						 &view->cacheonacl));
5296 		}
5297 	} else {
5298 		/*
5299 		 * We're not recursive; if the query-cache ACLs haven't
5300 		 * been set at the options/view level, set them to none.
5301 		 */
5302 		if (view->cacheacl == NULL) {
5303 			CHECK(dns_acl_none(mctx, &view->cacheacl));
5304 		}
5305 		if (view->cacheonacl == NULL) {
5306 			CHECK(dns_acl_none(mctx, &view->cacheonacl));
5307 		}
5308 	}
5309 
5310 	/*
5311 	 * Finished setting recursion and query-cache ACLs, so now we
5312 	 * can get the allow-query default if it wasn't set in named.conf
5313 	 */
5314 	if (view->queryacl == NULL) {
5315 		/* global default only */
5316 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5317 					 "allow-query", NULL, actx,
5318 					 named_g_mctx, &view->queryacl));
5319 	}
5320 
5321 	/*
5322 	 * Ignore case when compressing responses to the specified
5323 	 * clients. This causes case not always to be preserved,
5324 	 * and is needed by some broken clients.
5325 	 */
5326 	CHECK(configure_view_acl(vconfig, config, named_g_config,
5327 				 "no-case-compress", NULL, actx, named_g_mctx,
5328 				 &view->nocasecompress));
5329 
5330 	/*
5331 	 * Disable name compression completely, this is a tradeoff
5332 	 * between CPU and network usage.
5333 	 */
5334 	obj = NULL;
5335 	result = named_config_get(maps, "message-compression", &obj);
5336 	INSIST(result == ISC_R_SUCCESS);
5337 	view->msgcompression = cfg_obj_asboolean(obj);
5338 
5339 	/*
5340 	 * Filter setting on addresses in the answer section.
5341 	 */
5342 	CHECK(configure_view_acl(vconfig, config, named_g_config,
5343 				 "deny-answer-addresses", "acl", actx,
5344 				 named_g_mctx, &view->denyansweracl));
5345 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
5346 				       "except-from", named_g_mctx,
5347 				       &view->answeracl_exclude));
5348 
5349 	/*
5350 	 * Filter setting on names (CNAME/DNAME targets) in the answer section.
5351 	 */
5352 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5353 				       "name", named_g_mctx,
5354 				       &view->denyanswernames));
5355 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5356 				       "except-from", named_g_mctx,
5357 				       &view->answernames_exclude));
5358 
5359 	/*
5360 	 * Configure sortlist, if set
5361 	 */
5362 	CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx,
5363 				      &view->sortlist));
5364 
5365 	/*
5366 	 * Configure default allow-update and allow-update-forwarding ACLs,
5367 	 * so they can be inherited by zones. (XXX: These are not
5368 	 * read from the options/view level here. However, they may be
5369 	 * read from there in zoneconf.c:configure_zone_acl() later.)
5370 	 */
5371 	if (view->updateacl == NULL) {
5372 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5373 					 "allow-update", NULL, actx,
5374 					 named_g_mctx, &view->updateacl));
5375 	}
5376 	if (view->upfwdacl == NULL) {
5377 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5378 					 "allow-update-forwarding", NULL, actx,
5379 					 named_g_mctx, &view->upfwdacl));
5380 	}
5381 
5382 	/*
5383 	 * Configure default allow-transfer and allow-notify ACLs so they
5384 	 * can be inherited by zones.
5385 	 */
5386 	if (view->transferacl == NULL) {
5387 		CHECK(configure_view_acl(vconfig, config, named_g_config,
5388 					 "allow-transfer", NULL, actx,
5389 					 named_g_mctx, &view->transferacl));
5390 	}
5391 	if (view->notifyacl == NULL) {
5392 		CHECK(configure_view_acl(vconfig, config, named_g_config,
5393 					 "allow-notify", NULL, actx,
5394 					 named_g_mctx, &view->notifyacl));
5395 	}
5396 
5397 	obj = NULL;
5398 	result = named_config_get(maps, "provide-ixfr", &obj);
5399 	INSIST(result == ISC_R_SUCCESS);
5400 	view->provideixfr = cfg_obj_asboolean(obj);
5401 
5402 	obj = NULL;
5403 	result = named_config_get(maps, "request-nsid", &obj);
5404 	INSIST(result == ISC_R_SUCCESS);
5405 	view->requestnsid = cfg_obj_asboolean(obj);
5406 
5407 	obj = NULL;
5408 	result = named_config_get(maps, "send-cookie", &obj);
5409 	INSIST(result == ISC_R_SUCCESS);
5410 	view->sendcookie = cfg_obj_asboolean(obj);
5411 
5412 	obj = NULL;
5413 	if (view->pad_acl != NULL) {
5414 		dns_acl_detach(&view->pad_acl);
5415 	}
5416 	result = named_config_get(optionmaps, "response-padding", &obj);
5417 	if (result == ISC_R_SUCCESS) {
5418 		const cfg_obj_t *padobj = cfg_tuple_get(obj, "block-size");
5419 		const cfg_obj_t *aclobj = cfg_tuple_get(obj, "acl");
5420 		uint32_t padding = cfg_obj_asuint32(padobj);
5421 
5422 		if (padding > 512U) {
5423 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
5424 				    "response-padding block-size cannot "
5425 				    "exceed 512: lowering");
5426 			padding = 512U;
5427 		}
5428 		view->padding = (uint16_t)padding;
5429 		CHECK(cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx,
5430 					 named_g_mctx, 0, &view->pad_acl));
5431 	}
5432 
5433 	obj = NULL;
5434 	result = named_config_get(maps, "require-server-cookie", &obj);
5435 	INSIST(result == ISC_R_SUCCESS);
5436 	view->requireservercookie = cfg_obj_asboolean(obj);
5437 
5438 	obj = NULL;
5439 	result = named_config_get(maps, "v6-bias", &obj);
5440 	INSIST(result == ISC_R_SUCCESS);
5441 	view->v6bias = cfg_obj_asuint32(obj) * 1000;
5442 
5443 	obj = NULL;
5444 	result = named_config_get(maps, "max-clients-per-query", &obj);
5445 	INSIST(result == ISC_R_SUCCESS);
5446 	max_clients_per_query = cfg_obj_asuint32(obj);
5447 
5448 	obj = NULL;
5449 	result = named_config_get(maps, "clients-per-query", &obj);
5450 	INSIST(result == ISC_R_SUCCESS);
5451 	dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj),
5452 					max_clients_per_query);
5453 
5454 	obj = NULL;
5455 	result = named_config_get(maps, "max-recursion-depth", &obj);
5456 	INSIST(result == ISC_R_SUCCESS);
5457 	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
5458 
5459 	obj = NULL;
5460 	result = named_config_get(maps, "max-recursion-queries", &obj);
5461 	INSIST(result == ISC_R_SUCCESS);
5462 	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
5463 
5464 	obj = NULL;
5465 	result = named_config_get(maps, "fetches-per-zone", &obj);
5466 	INSIST(result == ISC_R_SUCCESS);
5467 	obj2 = cfg_tuple_get(obj, "fetches");
5468 	dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
5469 	obj2 = cfg_tuple_get(obj, "response");
5470 	if (!cfg_obj_isvoid(obj2)) {
5471 		const char *resp = cfg_obj_asstring(obj2);
5472 		isc_result_t r = DNS_R_SERVFAIL;
5473 
5474 		if (strcasecmp(resp, "drop") == 0) {
5475 			r = DNS_R_DROP;
5476 		} else if (strcasecmp(resp, "fail") == 0) {
5477 			r = DNS_R_SERVFAIL;
5478 		} else {
5479 			UNREACHABLE();
5480 		}
5481 
5482 		dns_resolver_setquotaresponse(view->resolver,
5483 					      dns_quotatype_zone, r);
5484 	}
5485 
5486 	obj = NULL;
5487 	result = named_config_get(maps, "prefetch", &obj);
5488 	INSIST(result == ISC_R_SUCCESS);
5489 	prefetch_trigger = cfg_tuple_get(obj, "trigger");
5490 	view->prefetch_trigger = cfg_obj_asuint32(prefetch_trigger);
5491 	if (view->prefetch_trigger > 10) {
5492 		view->prefetch_trigger = 10;
5493 	}
5494 	prefetch_eligible = cfg_tuple_get(obj, "eligible");
5495 	if (cfg_obj_isvoid(prefetch_eligible)) {
5496 		int m;
5497 		for (m = 1; maps[m] != NULL; m++) {
5498 			obj = NULL;
5499 			result = named_config_get(&maps[m], "prefetch", &obj);
5500 			INSIST(result == ISC_R_SUCCESS);
5501 			prefetch_eligible = cfg_tuple_get(obj, "eligible");
5502 			if (cfg_obj_isuint32(prefetch_eligible)) {
5503 				break;
5504 			}
5505 		}
5506 		INSIST(cfg_obj_isuint32(prefetch_eligible));
5507 	}
5508 	view->prefetch_eligible = cfg_obj_asuint32(prefetch_eligible);
5509 	if (view->prefetch_eligible < view->prefetch_trigger + 6) {
5510 		view->prefetch_eligible = view->prefetch_trigger + 6;
5511 	}
5512 
5513 	/*
5514 	 * For now, there is only one kind of trusted keys, the
5515 	 * "security roots".
5516 	 */
5517 	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
5518 					auto_root, mctx));
5519 	dns_resolver_resetmustbesecure(view->resolver);
5520 	obj = NULL;
5521 	result = named_config_get(maps, "dnssec-must-be-secure", &obj);
5522 	if (result == ISC_R_SUCCESS) {
5523 		CHECK(mustbesecure(obj, view->resolver));
5524 	}
5525 
5526 	obj = NULL;
5527 	result = named_config_get(maps, "nta-recheck", &obj);
5528 	INSIST(result == ISC_R_SUCCESS);
5529 	view->nta_recheck = cfg_obj_asduration(obj);
5530 
5531 	obj = NULL;
5532 	result = named_config_get(maps, "nta-lifetime", &obj);
5533 	INSIST(result == ISC_R_SUCCESS);
5534 	view->nta_lifetime = cfg_obj_asduration(obj);
5535 
5536 	obj = NULL;
5537 	result = named_config_get(maps, "preferred-glue", &obj);
5538 	if (result == ISC_R_SUCCESS) {
5539 		str = cfg_obj_asstring(obj);
5540 		if (strcasecmp(str, "a") == 0) {
5541 			view->preferred_glue = dns_rdatatype_a;
5542 		} else if (strcasecmp(str, "aaaa") == 0) {
5543 			view->preferred_glue = dns_rdatatype_aaaa;
5544 		} else {
5545 			view->preferred_glue = 0;
5546 		}
5547 	} else {
5548 		view->preferred_glue = 0;
5549 	}
5550 
5551 	obj = NULL;
5552 	result = named_config_get(maps, "root-delegation-only", &obj);
5553 	if (result == ISC_R_SUCCESS) {
5554 		dns_view_setrootdelonly(view, true);
5555 	}
5556 	if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
5557 		const cfg_obj_t *exclude;
5558 		dns_fixedname_t fixed;
5559 		dns_name_t *name;
5560 
5561 		name = dns_fixedname_initname(&fixed);
5562 		for (element = cfg_list_first(obj); element != NULL;
5563 		     element = cfg_list_next(element))
5564 		{
5565 			exclude = cfg_listelt_value(element);
5566 			CHECK(dns_name_fromstring(
5567 				name, cfg_obj_asstring(exclude), 0, NULL));
5568 			CHECK(dns_view_excludedelegationonly(view, name));
5569 		}
5570 	} else {
5571 		dns_view_setrootdelonly(view, false);
5572 	}
5573 
5574 	/*
5575 	 * Load DynDB modules.
5576 	 */
5577 	dyndb_list = NULL;
5578 	if (voptions != NULL) {
5579 		(void)cfg_map_get(voptions, "dyndb", &dyndb_list);
5580 	} else {
5581 		(void)cfg_map_get(config, "dyndb", &dyndb_list);
5582 	}
5583 
5584 #ifdef HAVE_DLOPEN
5585 	for (element = cfg_list_first(dyndb_list); element != NULL;
5586 	     element = cfg_list_next(element))
5587 	{
5588 		const cfg_obj_t *dyndb = cfg_listelt_value(element);
5589 
5590 		if (dctx == NULL) {
5591 			const void *hashinit = isc_hash_get_initializer();
5592 			CHECK(dns_dyndb_createctx(mctx, hashinit, named_g_lctx,
5593 						  view, named_g_server->zonemgr,
5594 						  named_g_server->task,
5595 						  named_g_timermgr, &dctx));
5596 		}
5597 
5598 		CHECK(configure_dyndb(dyndb, mctx, dctx));
5599 	}
5600 #endif /* ifdef HAVE_DLOPEN */
5601 
5602 	/*
5603 	 * Load plugins.
5604 	 */
5605 	plugin_list = NULL;
5606 	if (voptions != NULL) {
5607 		(void)cfg_map_get(voptions, "plugin", &plugin_list);
5608 	} else {
5609 		(void)cfg_map_get(config, "plugin", &plugin_list);
5610 	}
5611 
5612 #ifdef HAVE_DLOPEN
5613 	if (plugin_list != NULL) {
5614 		INSIST(view->hooktable == NULL);
5615 		CHECK(ns_hooktable_create(view->mctx,
5616 					  (ns_hooktable_t **)&view->hooktable));
5617 		view->hooktable_free = ns_hooktable_free;
5618 
5619 		ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
5620 		view->plugins_free = ns_plugins_free;
5621 
5622 		CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
5623 					     register_one_plugin, view));
5624 	}
5625 #endif /* ifdef HAVE_DLOPEN */
5626 
5627 	/*
5628 	 * Setup automatic empty zones.  If recursion is off then
5629 	 * they are disabled by default.
5630 	 */
5631 	obj = NULL;
5632 	(void)named_config_get(maps, "empty-zones-enable", &obj);
5633 	(void)named_config_get(maps, "disable-empty-zone", &disablelist);
5634 	if (obj == NULL && disablelist == NULL &&
5635 	    view->rdclass == dns_rdataclass_in)
5636 	{
5637 		empty_zones_enable = view->recursion;
5638 	} else if (view->rdclass == dns_rdataclass_in) {
5639 		if (obj != NULL) {
5640 			empty_zones_enable = cfg_obj_asboolean(obj);
5641 		} else {
5642 			empty_zones_enable = view->recursion;
5643 		}
5644 	} else {
5645 		empty_zones_enable = false;
5646 	}
5647 
5648 	if (empty_zones_enable) {
5649 		const char *empty;
5650 		int empty_zone = 0;
5651 		dns_fixedname_t fixed;
5652 		dns_name_t *name;
5653 		isc_buffer_t buffer;
5654 		char server[DNS_NAME_FORMATSIZE + 1];
5655 		char contact[DNS_NAME_FORMATSIZE + 1];
5656 		const char *empty_dbtype[4] = { "_builtin", "empty", NULL,
5657 						NULL };
5658 		int empty_dbtypec = 4;
5659 		dns_zonestat_level_t statlevel = dns_zonestat_none;
5660 
5661 		name = dns_fixedname_initname(&fixed);
5662 
5663 		obj = NULL;
5664 		result = named_config_get(maps, "empty-server", &obj);
5665 		if (result == ISC_R_SUCCESS) {
5666 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5667 						  0, NULL));
5668 			isc_buffer_init(&buffer, server, sizeof(server) - 1);
5669 			CHECK(dns_name_totext(name, false, &buffer));
5670 			server[isc_buffer_usedlength(&buffer)] = 0;
5671 			empty_dbtype[2] = server;
5672 		} else {
5673 			empty_dbtype[2] = "@";
5674 		}
5675 
5676 		obj = NULL;
5677 		result = named_config_get(maps, "empty-contact", &obj);
5678 		if (result == ISC_R_SUCCESS) {
5679 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5680 						  0, NULL));
5681 			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
5682 			CHECK(dns_name_totext(name, false, &buffer));
5683 			contact[isc_buffer_usedlength(&buffer)] = 0;
5684 			empty_dbtype[3] = contact;
5685 		} else {
5686 			empty_dbtype[3] = ".";
5687 		}
5688 
5689 		obj = NULL;
5690 		result = named_config_get(maps, "zone-statistics", &obj);
5691 		INSIST(result == ISC_R_SUCCESS);
5692 		if (cfg_obj_isboolean(obj)) {
5693 			if (cfg_obj_asboolean(obj)) {
5694 				statlevel = dns_zonestat_full;
5695 			} else {
5696 				statlevel = dns_zonestat_none;
5697 			}
5698 		} else {
5699 			const char *levelstr = cfg_obj_asstring(obj);
5700 			if (strcasecmp(levelstr, "full") == 0) {
5701 				statlevel = dns_zonestat_full;
5702 			} else if (strcasecmp(levelstr, "terse") == 0) {
5703 				statlevel = dns_zonestat_terse;
5704 			} else if (strcasecmp(levelstr, "none") == 0) {
5705 				statlevel = dns_zonestat_none;
5706 			} else {
5707 				UNREACHABLE();
5708 			}
5709 		}
5710 
5711 		for (empty = empty_zones[empty_zone]; empty != NULL;
5712 		     empty = empty_zones[++empty_zone])
5713 		{
5714 			dns_forwarders_t *dnsforwarders = NULL;
5715 
5716 			/*
5717 			 * Look for zone on drop list.
5718 			 */
5719 			CHECK(dns_name_fromstring(name, empty, 0, NULL));
5720 			if (disablelist != NULL &&
5721 			    on_disable_list(disablelist, name))
5722 			{
5723 				continue;
5724 			}
5725 
5726 			/*
5727 			 * This zone already exists.
5728 			 */
5729 			(void)dns_view_findzone(view, name, &zone);
5730 			if (zone != NULL) {
5731 				dns_zone_detach(&zone);
5732 				continue;
5733 			}
5734 
5735 			/*
5736 			 * If we would forward this name don't add a
5737 			 * empty zone for it.
5738 			 */
5739 			result = dns_fwdtable_find(view->fwdtable, name, NULL,
5740 						   &dnsforwarders);
5741 			if (result == ISC_R_SUCCESS &&
5742 			    dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
5743 			{
5744 				continue;
5745 			}
5746 
5747 			/*
5748 			 * See if we can re-use a existing zone.
5749 			 */
5750 			result = dns_viewlist_find(&named_g_server->viewlist,
5751 						   view->name, view->rdclass,
5752 						   &pview);
5753 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
5754 			{
5755 				goto cleanup;
5756 			}
5757 
5758 			if (pview != NULL) {
5759 				(void)dns_view_findzone(pview, name, &zone);
5760 				dns_view_detach(&pview);
5761 			}
5762 
5763 			CHECK(create_empty_zone(zone, name, view, zonelist,
5764 						empty_dbtype, empty_dbtypec,
5765 						statlevel));
5766 			if (zone != NULL) {
5767 				dns_zone_detach(&zone);
5768 			}
5769 		}
5770 	}
5771 
5772 	obj = NULL;
5773 	result = named_config_get(maps, "rate-limit", &obj);
5774 	if (result == ISC_R_SUCCESS) {
5775 		result = configure_rrl(view, config, obj);
5776 		if (result != ISC_R_SUCCESS) {
5777 			goto cleanup;
5778 		}
5779 	}
5780 
5781 	/*
5782 	 * Set the servfail-ttl.
5783 	 */
5784 	obj = NULL;
5785 	result = named_config_get(maps, "servfail-ttl", &obj);
5786 	INSIST(result == ISC_R_SUCCESS);
5787 	fail_ttl = cfg_obj_asduration(obj);
5788 	if (fail_ttl > 30) {
5789 		fail_ttl = 30;
5790 	}
5791 	dns_view_setfailttl(view, fail_ttl);
5792 
5793 	/*
5794 	 * Name space to look up redirect information in.
5795 	 */
5796 	obj = NULL;
5797 	result = named_config_get(maps, "nxdomain-redirect", &obj);
5798 	if (result == ISC_R_SUCCESS) {
5799 		dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
5800 		CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0,
5801 					  NULL));
5802 		view->redirectzone = name;
5803 	} else {
5804 		view->redirectzone = NULL;
5805 	}
5806 
5807 	/*
5808 	 * Exceptions to DNSSEC validation.
5809 	 */
5810 	obj = NULL;
5811 	result = named_config_get(maps, "validate-except", &obj);
5812 	if (result == ISC_R_SUCCESS) {
5813 		result = dns_view_getntatable(view, &ntatable);
5814 	}
5815 	if (result == ISC_R_SUCCESS) {
5816 		for (element = cfg_list_first(obj); element != NULL;
5817 		     element = cfg_list_next(element))
5818 		{
5819 			dns_fixedname_t fntaname;
5820 			dns_name_t *ntaname;
5821 
5822 			ntaname = dns_fixedname_initname(&fntaname);
5823 			obj = cfg_listelt_value(element);
5824 			CHECK(dns_name_fromstring(
5825 				ntaname, cfg_obj_asstring(obj), 0, NULL));
5826 			CHECK(dns_ntatable_add(ntatable, ntaname, true, 0,
5827 					       0xffffffffU));
5828 		}
5829 	}
5830 
5831 #ifdef HAVE_DNSTAP
5832 	/*
5833 	 * Set up the dnstap environment and configure message
5834 	 * types to log.
5835 	 */
5836 	CHECK(configure_dnstap(maps, view));
5837 #endif /* HAVE_DNSTAP */
5838 
5839 	result = ISC_R_SUCCESS;
5840 
5841 cleanup:
5842 	/*
5843 	 * Revert to the old view if there was an error.
5844 	 */
5845 	if (result != ISC_R_SUCCESS) {
5846 		isc_result_t result2;
5847 
5848 		result2 = dns_viewlist_find(&named_g_server->viewlist,
5849 					    view->name, view->rdclass, &pview);
5850 		if (result2 == ISC_R_SUCCESS) {
5851 			dns_view_thaw(pview);
5852 
5853 			obj = NULL;
5854 			if (rpz_configured &&
5855 			    pview->rdclass == dns_rdataclass_in && need_hints &&
5856 			    named_config_get(maps, "response-policy", &obj) ==
5857 				    ISC_R_SUCCESS)
5858 			{
5859 				/*
5860 				 * We are swapping the places of the `view` and
5861 				 * `pview` in the function's parameters list
5862 				 * because we are reverting the same operation
5863 				 * done previously in the "correct" order.
5864 				 */
5865 				result2 = configure_rpz(pview, view, maps, obj,
5866 							&old_rpz_ok);
5867 				if (result2 != ISC_R_SUCCESS) {
5868 					isc_log_write(named_g_lctx,
5869 						      NAMED_LOGCATEGORY_GENERAL,
5870 						      NAMED_LOGMODULE_SERVER,
5871 						      ISC_LOG_ERROR,
5872 						      "rpz configuration "
5873 						      "revert failed for view "
5874 						      "'%s'",
5875 						      pview->name);
5876 				}
5877 			}
5878 
5879 			obj = NULL;
5880 			if (catz_configured &&
5881 			    pview->rdclass == dns_rdataclass_in && need_hints &&
5882 			    named_config_get(maps, "catalog-zones", &obj) ==
5883 				    ISC_R_SUCCESS)
5884 			{
5885 				/*
5886 				 * We are swapping the places of the `view` and
5887 				 * `pview` in the function's parameters list
5888 				 * because we are reverting the same operation
5889 				 * done previously in the "correct" order.
5890 				 */
5891 				result2 = configure_catz(pview, view, config,
5892 							 obj);
5893 				if (result2 != ISC_R_SUCCESS) {
5894 					isc_log_write(named_g_lctx,
5895 						      NAMED_LOGCATEGORY_GENERAL,
5896 						      NAMED_LOGMODULE_SERVER,
5897 						      ISC_LOG_ERROR,
5898 						      "catz configuration "
5899 						      "revert failed for view "
5900 						      "'%s'",
5901 						      pview->name);
5902 				}
5903 			}
5904 
5905 			dns_view_freeze(pview);
5906 		}
5907 
5908 		if (pview != NULL) {
5909 			dns_view_detach(&pview);
5910 		}
5911 
5912 		if (zone_element_latest != NULL) {
5913 			for (element = cfg_list_first(zonelist);
5914 			     element != NULL; element = cfg_list_next(element))
5915 			{
5916 				const cfg_obj_t *zconfig =
5917 					cfg_listelt_value(element);
5918 				configure_zone_setviewcommit(result, zconfig,
5919 							     view);
5920 				if (element == zone_element_latest) {
5921 					/*
5922 					 * This was the latest element that was
5923 					 * successfully configured earlier.
5924 					 */
5925 					break;
5926 				}
5927 			}
5928 		}
5929 	}
5930 
5931 	if (ntatable != NULL) {
5932 		dns_ntatable_detach(&ntatable);
5933 	}
5934 	if (clients != NULL) {
5935 		dns_acl_detach(&clients);
5936 	}
5937 	if (mapped != NULL) {
5938 		dns_acl_detach(&mapped);
5939 	}
5940 	if (excluded != NULL) {
5941 		dns_acl_detach(&excluded);
5942 	}
5943 	if (ring != NULL) {
5944 		dns_tsigkeyring_detach(&ring);
5945 	}
5946 	if (zone != NULL) {
5947 		dns_zone_detach(&zone);
5948 	}
5949 	if (dispatch4 != NULL) {
5950 		dns_dispatch_detach(&dispatch4);
5951 	}
5952 	if (dispatch6 != NULL) {
5953 		dns_dispatch_detach(&dispatch6);
5954 	}
5955 	if (resstats != NULL) {
5956 		isc_stats_detach(&resstats);
5957 	}
5958 	if (resquerystats != NULL) {
5959 		dns_stats_detach(&resquerystats);
5960 	}
5961 	if (order != NULL) {
5962 		dns_order_detach(&order);
5963 	}
5964 	if (cmctx != NULL) {
5965 		isc_mem_detach(&cmctx);
5966 	}
5967 	if (hmctx != NULL) {
5968 		isc_mem_detach(&hmctx);
5969 	}
5970 	if (cache != NULL) {
5971 		dns_cache_detach(&cache);
5972 	}
5973 	if (dctx != NULL) {
5974 		dns_dyndb_destroyctx(&dctx);
5975 	}
5976 
5977 	return (result);
5978 }
5979 
5980 static isc_result_t
configure_hints(dns_view_t * view,const char * filename)5981 configure_hints(dns_view_t *view, const char *filename) {
5982 	isc_result_t result;
5983 	dns_db_t *db;
5984 
5985 	db = NULL;
5986 	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
5987 	if (result == ISC_R_SUCCESS) {
5988 		dns_view_sethints(view, db);
5989 		dns_db_detach(&db);
5990 	}
5991 
5992 	return (result);
5993 }
5994 
5995 static isc_result_t
configure_alternates(const cfg_obj_t * config,dns_view_t * view,const cfg_obj_t * alternates)5996 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
5997 		     const cfg_obj_t *alternates) {
5998 	const cfg_obj_t *portobj;
5999 	const cfg_obj_t *addresses;
6000 	const cfg_listelt_t *element;
6001 	isc_result_t result = ISC_R_SUCCESS;
6002 	in_port_t port;
6003 
6004 	/*
6005 	 * Determine which port to send requests to.
6006 	 */
6007 	CHECKM(named_config_getport(config, &port), "port");
6008 
6009 	if (alternates != NULL) {
6010 		portobj = cfg_tuple_get(alternates, "port");
6011 		if (cfg_obj_isuint32(portobj)) {
6012 			uint32_t val = cfg_obj_asuint32(portobj);
6013 			if (val > UINT16_MAX) {
6014 				cfg_obj_log(portobj, named_g_lctx,
6015 					    ISC_LOG_ERROR,
6016 					    "port '%u' out of range", val);
6017 				return (ISC_R_RANGE);
6018 			}
6019 			port = (in_port_t)val;
6020 		}
6021 	}
6022 
6023 	addresses = NULL;
6024 	if (alternates != NULL) {
6025 		addresses = cfg_tuple_get(alternates, "addresses");
6026 	}
6027 
6028 	for (element = cfg_list_first(addresses); element != NULL;
6029 	     element = cfg_list_next(element))
6030 	{
6031 		const cfg_obj_t *alternate = cfg_listelt_value(element);
6032 		isc_sockaddr_t sa;
6033 
6034 		if (!cfg_obj_issockaddr(alternate)) {
6035 			dns_fixedname_t fixed;
6036 			dns_name_t *name;
6037 			const char *str = cfg_obj_asstring(
6038 				cfg_tuple_get(alternate, "name"));
6039 			isc_buffer_t buffer;
6040 			in_port_t myport = port;
6041 
6042 			isc_buffer_constinit(&buffer, str, strlen(str));
6043 			isc_buffer_add(&buffer, strlen(str));
6044 			name = dns_fixedname_initname(&fixed);
6045 			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
6046 						NULL));
6047 
6048 			portobj = cfg_tuple_get(alternate, "port");
6049 			if (cfg_obj_isuint32(portobj)) {
6050 				uint32_t val = cfg_obj_asuint32(portobj);
6051 				if (val > UINT16_MAX) {
6052 					cfg_obj_log(portobj, named_g_lctx,
6053 						    ISC_LOG_ERROR,
6054 						    "port '%u' out of range",
6055 						    val);
6056 					return (ISC_R_RANGE);
6057 				}
6058 				myport = (in_port_t)val;
6059 			}
6060 			CHECK(dns_resolver_addalternate(view->resolver, NULL,
6061 							name, myport));
6062 			continue;
6063 		}
6064 
6065 		sa = *cfg_obj_assockaddr(alternate);
6066 		if (isc_sockaddr_getport(&sa) == 0) {
6067 			isc_sockaddr_setport(&sa, port);
6068 		}
6069 		CHECK(dns_resolver_addalternate(view->resolver, &sa, NULL, 0));
6070 	}
6071 
6072 cleanup:
6073 	return (result);
6074 }
6075 
6076 static isc_result_t
configure_forward(const cfg_obj_t * config,dns_view_t * view,const dns_name_t * origin,const cfg_obj_t * forwarders,const cfg_obj_t * forwardtype)6077 configure_forward(const cfg_obj_t *config, dns_view_t *view,
6078 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
6079 		  const cfg_obj_t *forwardtype) {
6080 	const cfg_obj_t *portobj, *dscpobj;
6081 	const cfg_obj_t *faddresses;
6082 	const cfg_listelt_t *element;
6083 	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
6084 	dns_forwarderlist_t fwdlist;
6085 	dns_forwarder_t *fwd;
6086 	isc_result_t result;
6087 	in_port_t port;
6088 	isc_dscp_t dscp = -1;
6089 
6090 	ISC_LIST_INIT(fwdlist);
6091 
6092 	/*
6093 	 * Determine which port to send forwarded requests to.
6094 	 */
6095 	CHECKM(named_config_getport(config, &port), "port");
6096 
6097 	if (forwarders != NULL) {
6098 		portobj = cfg_tuple_get(forwarders, "port");
6099 		if (cfg_obj_isuint32(portobj)) {
6100 			uint32_t val = cfg_obj_asuint32(portobj);
6101 			if (val > UINT16_MAX) {
6102 				cfg_obj_log(portobj, named_g_lctx,
6103 					    ISC_LOG_ERROR,
6104 					    "port '%u' out of range", val);
6105 				return (ISC_R_RANGE);
6106 			}
6107 			port = (in_port_t)val;
6108 		}
6109 	}
6110 
6111 	/*
6112 	 * DSCP value for forwarded requests.
6113 	 */
6114 	dscp = named_g_dscp;
6115 	if (forwarders != NULL) {
6116 		dscpobj = cfg_tuple_get(forwarders, "dscp");
6117 		if (cfg_obj_isuint32(dscpobj)) {
6118 			if (cfg_obj_asuint32(dscpobj) > 63) {
6119 				cfg_obj_log(dscpobj, named_g_lctx,
6120 					    ISC_LOG_ERROR,
6121 					    "dscp value '%u' is out of range",
6122 					    cfg_obj_asuint32(dscpobj));
6123 				return (ISC_R_RANGE);
6124 			}
6125 			dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
6126 		}
6127 	}
6128 
6129 	faddresses = NULL;
6130 	if (forwarders != NULL) {
6131 		faddresses = cfg_tuple_get(forwarders, "addresses");
6132 	}
6133 
6134 	for (element = cfg_list_first(faddresses); element != NULL;
6135 	     element = cfg_list_next(element))
6136 	{
6137 		const cfg_obj_t *forwarder = cfg_listelt_value(element);
6138 		fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
6139 		fwd->addr = *cfg_obj_assockaddr(forwarder);
6140 		if (isc_sockaddr_getport(&fwd->addr) == 0) {
6141 			isc_sockaddr_setport(&fwd->addr, port);
6142 		}
6143 		fwd->dscp = cfg_obj_getdscp(forwarder);
6144 		if (fwd->dscp == -1) {
6145 			fwd->dscp = dscp;
6146 		}
6147 		ISC_LINK_INIT(fwd, link);
6148 		ISC_LIST_APPEND(fwdlist, fwd, link);
6149 	}
6150 
6151 	if (ISC_LIST_EMPTY(fwdlist)) {
6152 		if (forwardtype != NULL) {
6153 			cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING,
6154 				    "no forwarders seen; disabling "
6155 				    "forwarding");
6156 		}
6157 		fwdpolicy = dns_fwdpolicy_none;
6158 	} else {
6159 		if (forwardtype == NULL) {
6160 			fwdpolicy = dns_fwdpolicy_first;
6161 		} else {
6162 			const char *forwardstr = cfg_obj_asstring(forwardtype);
6163 			if (strcasecmp(forwardstr, "first") == 0) {
6164 				fwdpolicy = dns_fwdpolicy_first;
6165 			} else if (strcasecmp(forwardstr, "only") == 0) {
6166 				fwdpolicy = dns_fwdpolicy_only;
6167 			} else {
6168 				UNREACHABLE();
6169 			}
6170 		}
6171 	}
6172 
6173 	result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
6174 				     fwdpolicy);
6175 	if (result != ISC_R_SUCCESS) {
6176 		char namebuf[DNS_NAME_FORMATSIZE];
6177 		dns_name_format(origin, namebuf, sizeof(namebuf));
6178 		cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING,
6179 			    "could not set up forwarding for domain '%s': %s",
6180 			    namebuf, isc_result_totext(result));
6181 		goto cleanup;
6182 	}
6183 
6184 	result = ISC_R_SUCCESS;
6185 
6186 cleanup:
6187 
6188 	while (!ISC_LIST_EMPTY(fwdlist)) {
6189 		fwd = ISC_LIST_HEAD(fwdlist);
6190 		ISC_LIST_UNLINK(fwdlist, fwd, link);
6191 		isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
6192 	}
6193 
6194 	return (result);
6195 }
6196 
6197 static isc_result_t
get_viewinfo(const cfg_obj_t * vconfig,const char ** namep,dns_rdataclass_t * classp)6198 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
6199 	     dns_rdataclass_t *classp) {
6200 	isc_result_t result = ISC_R_SUCCESS;
6201 	const char *viewname;
6202 	dns_rdataclass_t viewclass;
6203 
6204 	REQUIRE(namep != NULL && *namep == NULL);
6205 	REQUIRE(classp != NULL);
6206 
6207 	if (vconfig != NULL) {
6208 		const cfg_obj_t *classobj = NULL;
6209 
6210 		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
6211 		classobj = cfg_tuple_get(vconfig, "class");
6212 		CHECK(named_config_getclass(classobj, dns_rdataclass_in,
6213 					    &viewclass));
6214 		if (dns_rdataclass_ismeta(viewclass)) {
6215 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6216 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6217 				      "view '%s': class must not be meta",
6218 				      viewname);
6219 			CHECK(ISC_R_FAILURE);
6220 		}
6221 	} else {
6222 		viewname = "_default";
6223 		viewclass = dns_rdataclass_in;
6224 	}
6225 
6226 	*namep = viewname;
6227 	*classp = viewclass;
6228 
6229 cleanup:
6230 	return (result);
6231 }
6232 
6233 /*
6234  * Find a view based on its configuration info and attach to it.
6235  *
6236  * If 'vconfig' is NULL, attach to the default view.
6237  */
6238 static isc_result_t
find_view(const cfg_obj_t * vconfig,dns_viewlist_t * viewlist,dns_view_t ** viewp)6239 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6240 	  dns_view_t **viewp) {
6241 	isc_result_t result;
6242 	const char *viewname = NULL;
6243 	dns_rdataclass_t viewclass;
6244 	dns_view_t *view = NULL;
6245 
6246 	result = get_viewinfo(vconfig, &viewname, &viewclass);
6247 	if (result != ISC_R_SUCCESS) {
6248 		return (result);
6249 	}
6250 
6251 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6252 	if (result != ISC_R_SUCCESS) {
6253 		return (result);
6254 	}
6255 
6256 	*viewp = view;
6257 	return (ISC_R_SUCCESS);
6258 }
6259 
6260 /*
6261  * Create a new view and add it to the list.
6262  *
6263  * If 'vconfig' is NULL, create the default view.
6264  *
6265  * The view created is attached to '*viewp'.
6266  */
6267 static isc_result_t
create_view(const cfg_obj_t * vconfig,dns_viewlist_t * viewlist,dns_view_t ** viewp)6268 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6269 	    dns_view_t **viewp) {
6270 	isc_result_t result;
6271 	const char *viewname = NULL;
6272 	dns_rdataclass_t viewclass;
6273 	dns_view_t *view = NULL;
6274 
6275 	result = get_viewinfo(vconfig, &viewname, &viewclass);
6276 	if (result != ISC_R_SUCCESS) {
6277 		return (result);
6278 	}
6279 
6280 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6281 	if (result == ISC_R_SUCCESS) {
6282 		return (ISC_R_EXISTS);
6283 	}
6284 	if (result != ISC_R_NOTFOUND) {
6285 		return (result);
6286 	}
6287 	INSIST(view == NULL);
6288 
6289 	result = dns_view_create(named_g_mctx, viewclass, viewname, &view);
6290 	if (result != ISC_R_SUCCESS) {
6291 		return (result);
6292 	}
6293 
6294 	isc_nonce_buf(view->secret, sizeof(view->secret));
6295 
6296 	ISC_LIST_APPEND(*viewlist, view, link);
6297 	dns_view_attach(view, viewp);
6298 	return (ISC_R_SUCCESS);
6299 }
6300 
6301 /*
6302  * Configure or reconfigure a zone.
6303  */
6304 static isc_result_t
configure_zone(const cfg_obj_t * config,const cfg_obj_t * zconfig,const cfg_obj_t * vconfig,isc_mem_t * mctx,dns_view_t * view,dns_viewlist_t * viewlist,dns_kasplist_t * kasplist,cfg_aclconfctx_t * aclconf,bool added,bool old_rpz_ok,bool modify)6305 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
6306 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
6307 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
6308 	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
6309 	       bool modify) {
6310 	dns_view_t *pview = NULL; /* Production view */
6311 	dns_zone_t *zone = NULL;  /* New or reused zone */
6312 	dns_zone_t *raw = NULL;	  /* New or reused raw zone */
6313 	dns_zone_t *dupzone = NULL;
6314 	const cfg_obj_t *options = NULL;
6315 	const cfg_obj_t *zoptions = NULL;
6316 	const cfg_obj_t *typeobj = NULL;
6317 	const cfg_obj_t *forwarders = NULL;
6318 	const cfg_obj_t *forwardtype = NULL;
6319 	const cfg_obj_t *ixfrfromdiffs = NULL;
6320 	const cfg_obj_t *only = NULL;
6321 	const cfg_obj_t *viewobj = NULL;
6322 	isc_result_t result;
6323 	isc_result_t tresult;
6324 	isc_buffer_t buffer;
6325 	dns_fixedname_t fixorigin;
6326 	dns_name_t *origin;
6327 	const char *zname;
6328 	dns_rdataclass_t zclass;
6329 	const char *ztypestr;
6330 	dns_rpz_num_t rpz_num;
6331 	bool zone_is_catz = false;
6332 	bool zone_maybe_inline = false;
6333 	bool inline_signing = false;
6334 	bool fullsign = false;
6335 
6336 	options = NULL;
6337 	(void)cfg_map_get(config, "options", &options);
6338 
6339 	zoptions = cfg_tuple_get(zconfig, "options");
6340 
6341 	/*
6342 	 * Get the zone origin as a dns_name_t.
6343 	 */
6344 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
6345 	isc_buffer_constinit(&buffer, zname, strlen(zname));
6346 	isc_buffer_add(&buffer, strlen(zname));
6347 	dns_fixedname_init(&fixorigin);
6348 	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
6349 				dns_rootname, 0, NULL));
6350 	origin = dns_fixedname_name(&fixorigin);
6351 
6352 	CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"),
6353 				    view->rdclass, &zclass));
6354 	if (zclass != view->rdclass) {
6355 		const char *vname = NULL;
6356 		if (vconfig != NULL) {
6357 			vname = cfg_obj_asstring(
6358 				cfg_tuple_get(vconfig, "name"));
6359 		} else {
6360 			vname = "<default view>";
6361 		}
6362 
6363 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6364 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6365 			      "zone '%s': wrong class for view '%s'", zname,
6366 			      vname);
6367 		result = ISC_R_FAILURE;
6368 		goto cleanup;
6369 	}
6370 
6371 	(void)cfg_map_get(zoptions, "in-view", &viewobj);
6372 	if (viewobj != NULL) {
6373 		const char *inview = cfg_obj_asstring(viewobj);
6374 		dns_view_t *otherview = NULL;
6375 
6376 		if (viewlist == NULL) {
6377 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6378 				    "'in-view' option is not permitted in "
6379 				    "dynamically added zones");
6380 			result = ISC_R_FAILURE;
6381 			goto cleanup;
6382 		}
6383 
6384 		result = dns_viewlist_find(viewlist, inview, view->rdclass,
6385 					   &otherview);
6386 		if (result != ISC_R_SUCCESS) {
6387 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6388 				    "view '%s' is not yet defined.", inview);
6389 			result = ISC_R_FAILURE;
6390 			goto cleanup;
6391 		}
6392 
6393 		result = dns_view_findzone(otherview, origin, &zone);
6394 		dns_view_detach(&otherview);
6395 		if (result != ISC_R_SUCCESS) {
6396 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6397 				    "zone '%s' not defined in view '%s'", zname,
6398 				    inview);
6399 			result = ISC_R_FAILURE;
6400 			goto cleanup;
6401 		}
6402 
6403 		CHECK(dns_view_addzone(view, zone));
6404 		dns_zone_detach(&zone);
6405 
6406 		/*
6407 		 * If the zone contains a 'forwarders' statement, configure
6408 		 * selective forwarding.  Note: this is not inherited from the
6409 		 * other view.
6410 		 */
6411 		forwarders = NULL;
6412 		result = cfg_map_get(zoptions, "forwarders", &forwarders);
6413 		if (result == ISC_R_SUCCESS) {
6414 			forwardtype = NULL;
6415 			(void)cfg_map_get(zoptions, "forward", &forwardtype);
6416 			CHECK(configure_forward(config, view, origin,
6417 						forwarders, forwardtype));
6418 		}
6419 		result = ISC_R_SUCCESS;
6420 		goto cleanup;
6421 	}
6422 
6423 	(void)cfg_map_get(zoptions, "type", &typeobj);
6424 	if (typeobj == NULL) {
6425 		cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6426 			    "zone '%s' 'type' not specified", zname);
6427 		result = ISC_R_FAILURE;
6428 		goto cleanup;
6429 	}
6430 	ztypestr = cfg_obj_asstring(typeobj);
6431 
6432 	/*
6433 	 * "hints zones" aren't zones.	If we've got one,
6434 	 * configure it and return.
6435 	 */
6436 	if (strcasecmp(ztypestr, "hint") == 0) {
6437 		const cfg_obj_t *fileobj = NULL;
6438 		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
6439 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6440 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6441 				      "zone '%s': 'file' not specified", zname);
6442 			result = ISC_R_FAILURE;
6443 			goto cleanup;
6444 		}
6445 		if (dns_name_equal(origin, dns_rootname)) {
6446 			const char *hintsfile = cfg_obj_asstring(fileobj);
6447 
6448 			CHECK(configure_hints(view, hintsfile));
6449 
6450 			/*
6451 			 * Hint zones may also refer to delegation only points.
6452 			 */
6453 			only = NULL;
6454 			tresult = cfg_map_get(zoptions, "delegation-only",
6455 					      &only);
6456 			if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
6457 			{
6458 				CHECK(dns_view_adddelegationonly(view, origin));
6459 			}
6460 		} else {
6461 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6462 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
6463 				      "ignoring non-root hint zone '%s'",
6464 				      zname);
6465 			result = ISC_R_SUCCESS;
6466 		}
6467 		/* Skip ordinary zone processing. */
6468 		goto cleanup;
6469 	}
6470 
6471 	/*
6472 	 * "forward zones" aren't zones either.  Translate this syntax into
6473 	 * the appropriate selective forwarding configuration and return.
6474 	 */
6475 	if (strcasecmp(ztypestr, "forward") == 0) {
6476 		forwardtype = NULL;
6477 		forwarders = NULL;
6478 
6479 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6480 		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
6481 		CHECK(configure_forward(config, view, origin, forwarders,
6482 					forwardtype));
6483 
6484 		/*
6485 		 * Forward zones may also set delegation only.
6486 		 */
6487 		only = NULL;
6488 		tresult = cfg_map_get(zoptions, "delegation-only", &only);
6489 		if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) {
6490 			CHECK(dns_view_adddelegationonly(view, origin));
6491 		}
6492 		goto cleanup;
6493 	}
6494 
6495 	/*
6496 	 * "delegation-only zones" aren't zones either.
6497 	 */
6498 	if (strcasecmp(ztypestr, "delegation-only") == 0) {
6499 		result = dns_view_adddelegationonly(view, origin);
6500 		goto cleanup;
6501 	}
6502 
6503 	/*
6504 	 * Redirect zones only require minimal configuration.
6505 	 */
6506 	if (strcasecmp(ztypestr, "redirect") == 0) {
6507 		if (view->redirect != NULL) {
6508 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6509 				    "redirect zone already exists");
6510 			result = ISC_R_EXISTS;
6511 			goto cleanup;
6512 		}
6513 		result = dns_viewlist_find(viewlist, view->name, view->rdclass,
6514 					   &pview);
6515 		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6516 			goto cleanup;
6517 		}
6518 		if (pview != NULL && pview->redirect != NULL) {
6519 			dns_zone_attach(pview->redirect, &zone);
6520 			dns_zone_setview(zone, view);
6521 		} else {
6522 			CHECK(dns_zonemgr_createzone(named_g_server->zonemgr,
6523 						     &zone));
6524 			CHECK(dns_zone_setorigin(zone, origin));
6525 			dns_zone_setview(zone, view);
6526 			CHECK(dns_zonemgr_managezone(named_g_server->zonemgr,
6527 						     zone));
6528 			dns_zone_setstats(zone, named_g_server->zonestats);
6529 		}
6530 		CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
6531 					   kasplist, zone, NULL));
6532 		dns_zone_attach(zone, &view->redirect);
6533 		goto cleanup;
6534 	}
6535 
6536 	if (!modify) {
6537 		/*
6538 		 * Check for duplicates in the new zone table.
6539 		 */
6540 		result = dns_view_findzone(view, origin, &dupzone);
6541 		if (result == ISC_R_SUCCESS) {
6542 			/*
6543 			 * We already have this zone!
6544 			 */
6545 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6546 				    "zone '%s' already exists", zname);
6547 			dns_zone_detach(&dupzone);
6548 			result = ISC_R_EXISTS;
6549 			goto cleanup;
6550 		}
6551 		INSIST(dupzone == NULL);
6552 	}
6553 
6554 	/*
6555 	 * Note whether this is a response policy zone and which one if so,
6556 	 * unless we are using RPZ service interface.  In that case, the
6557 	 * BIND zone database has nothing to do with rpz and so we don't care.
6558 	 */
6559 	for (rpz_num = 0;; ++rpz_num) {
6560 		if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
6561 		    view->rpzs->p.dnsrps_enabled)
6562 		{
6563 			rpz_num = DNS_RPZ_INVALID_NUM;
6564 			break;
6565 		}
6566 		if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
6567 		{
6568 			break;
6569 		}
6570 	}
6571 
6572 	if (view->catzs != NULL &&
6573 	    dns_catz_get_zone(view->catzs, origin) != NULL)
6574 	{
6575 		zone_is_catz = true;
6576 	}
6577 
6578 	/*
6579 	 * See if we can reuse an existing zone.  This is
6580 	 * only possible if all of these are true:
6581 	 *   - The zone's view exists
6582 	 *   - A zone with the right name exists in the view
6583 	 *   - The zone is compatible with the config
6584 	 *     options (e.g., an existing master zone cannot
6585 	 *     be reused if the options specify a slave zone)
6586 	 *   - The zone was not and is still not a response policy zone
6587 	 *     or the zone is a policy zone with an unchanged number
6588 	 *     and we are using the old policy zone summary data.
6589 	 */
6590 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6591 				   view->rdclass, &pview);
6592 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6593 		goto cleanup;
6594 	}
6595 	if (pview != NULL) {
6596 		result = dns_view_findzone(pview, origin, &zone);
6597 	}
6598 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6599 		goto cleanup;
6600 	}
6601 
6602 	if (zone != NULL && !named_zone_reusable(zone, zconfig)) {
6603 		dns_zone_detach(&zone);
6604 		fullsign = true;
6605 	}
6606 
6607 	if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
6608 			     (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
6609 	{
6610 		dns_zone_detach(&zone);
6611 	}
6612 
6613 	if (zone != NULL) {
6614 		/*
6615 		 * We found a reusable zone.  Make it use the
6616 		 * new view.
6617 		 */
6618 		dns_zone_setview(zone, view);
6619 	} else {
6620 		/*
6621 		 * We cannot reuse an existing zone, we have
6622 		 * to create a new one.
6623 		 */
6624 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6625 		CHECK(dns_zone_setorigin(zone, origin));
6626 		dns_zone_setview(zone, view);
6627 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6628 		dns_zone_setstats(zone, named_g_server->zonestats);
6629 	}
6630 	if (rpz_num != DNS_RPZ_INVALID_NUM) {
6631 		result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
6632 		if (result != ISC_R_SUCCESS) {
6633 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6634 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6635 				      "zone '%s': incompatible"
6636 				      " masterfile-format or database"
6637 				      " for a response policy zone",
6638 				      zname);
6639 			goto cleanup;
6640 		}
6641 	}
6642 
6643 	if (zone_is_catz) {
6644 		dns_zone_catz_enable(zone, view->catzs);
6645 	} else if (dns_zone_catz_is_enabled(zone)) {
6646 		dns_zone_catz_disable(zone);
6647 	}
6648 
6649 	/*
6650 	 * If the zone contains a 'forwarders' statement, configure
6651 	 * selective forwarding.
6652 	 */
6653 	forwarders = NULL;
6654 	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) {
6655 		forwardtype = NULL;
6656 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6657 		CHECK(configure_forward(config, view, origin, forwarders,
6658 					forwardtype));
6659 	}
6660 
6661 	/*
6662 	 * Stub and forward zones may also refer to delegation only points.
6663 	 */
6664 	only = NULL;
6665 	if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) {
6666 		if (cfg_obj_asboolean(only)) {
6667 			CHECK(dns_view_adddelegationonly(view, origin));
6668 		}
6669 	}
6670 
6671 	/*
6672 	 * Mark whether the zone was originally added at runtime or not
6673 	 */
6674 	dns_zone_setadded(zone, added);
6675 
6676 	/*
6677 	 * Determine if we need to set up inline signing.
6678 	 */
6679 	zone_maybe_inline = ((strcasecmp(ztypestr, "primary") == 0 ||
6680 			      strcasecmp(ztypestr, "master") == 0 ||
6681 			      strcasecmp(ztypestr, "secondary") == 0 ||
6682 			      strcasecmp(ztypestr, "slave") == 0));
6683 
6684 	if (zone_maybe_inline) {
6685 		inline_signing = named_zone_inlinesigning(zconfig);
6686 	}
6687 	if (inline_signing) {
6688 		dns_zone_getraw(zone, &raw);
6689 		if (raw == NULL) {
6690 			CHECK(dns_zone_create(&raw, mctx));
6691 			CHECK(dns_zone_setorigin(raw, origin));
6692 			dns_zone_setview(raw, view);
6693 			dns_zone_setstats(raw, named_g_server->zonestats);
6694 			CHECK(dns_zone_link(zone, raw));
6695 		}
6696 		if (cfg_map_get(zoptions, "ixfr-from-differences",
6697 				&ixfrfromdiffs) == ISC_R_SUCCESS)
6698 		{
6699 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6700 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6701 				      "zone '%s': 'ixfr-from-differences' is "
6702 				      "ignored for inline-signed zones",
6703 				      zname);
6704 		}
6705 	}
6706 
6707 	/*
6708 	 * Configure the zone.
6709 	 */
6710 	CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
6711 				   zone, raw));
6712 
6713 	/*
6714 	 * Add the zone to its view in the new view list.
6715 	 */
6716 	if (!modify) {
6717 		CHECK(dns_view_addzone(view, zone));
6718 	}
6719 
6720 	if (zone_is_catz) {
6721 		/*
6722 		 * force catz reload if the zone is loaded;
6723 		 * if it's not it'll get reloaded on zone load
6724 		 */
6725 		dns_db_t *db = NULL;
6726 
6727 		tresult = dns_zone_getdb(zone, &db);
6728 		if (tresult == ISC_R_SUCCESS) {
6729 			dns_catz_dbupdate_callback(db, view->catzs);
6730 			dns_db_detach(&db);
6731 		}
6732 	}
6733 
6734 	/*
6735 	 * Ensure that zone keys are reloaded on reconfig
6736 	 */
6737 	if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) {
6738 		dns_zone_rekey(zone, fullsign);
6739 	}
6740 
6741 cleanup:
6742 	if (zone != NULL) {
6743 		dns_zone_detach(&zone);
6744 	}
6745 	if (raw != NULL) {
6746 		dns_zone_detach(&raw);
6747 	}
6748 	if (pview != NULL) {
6749 		dns_view_detach(&pview);
6750 	}
6751 
6752 	return (result);
6753 }
6754 
6755 /*
6756  * Configure built-in zone for storing managed-key data.
6757  */
6758 static isc_result_t
add_keydata_zone(dns_view_t * view,const char * directory,isc_mem_t * mctx)6759 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
6760 	isc_result_t result;
6761 	dns_view_t *pview = NULL;
6762 	dns_zone_t *zone = NULL;
6763 	dns_acl_t *none = NULL;
6764 	char filename[PATH_MAX];
6765 	bool defaultview;
6766 
6767 	REQUIRE(view != NULL);
6768 
6769 	/* See if we can re-use an existing keydata zone. */
6770 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6771 				   view->rdclass, &pview);
6772 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6773 		return (result);
6774 	}
6775 
6776 	if (pview != NULL) {
6777 		if (pview->managed_keys != NULL) {
6778 			dns_zone_attach(pview->managed_keys,
6779 					&view->managed_keys);
6780 			dns_zone_setview(pview->managed_keys, view);
6781 			dns_zone_setviewcommit(pview->managed_keys);
6782 			dns_view_detach(&pview);
6783 			dns_zone_synckeyzone(view->managed_keys);
6784 			return (ISC_R_SUCCESS);
6785 		}
6786 
6787 		dns_view_detach(&pview);
6788 	}
6789 
6790 	/* No existing keydata zone was found; create one */
6791 	CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6792 	CHECK(dns_zone_setorigin(zone, dns_rootname));
6793 
6794 	defaultview = (strcmp(view->name, "_default") == 0);
6795 	CHECK(isc_file_sanitize(
6796 		directory, defaultview ? "managed-keys" : view->name,
6797 		defaultview ? "bind" : "mkeys", filename, sizeof(filename)));
6798 	CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text,
6799 			       &dns_master_style_default));
6800 
6801 	dns_zone_setview(zone, view);
6802 	dns_zone_settype(zone, dns_zone_key);
6803 	dns_zone_setclass(zone, view->rdclass);
6804 
6805 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6806 
6807 	CHECK(dns_acl_none(mctx, &none));
6808 	dns_zone_setqueryacl(zone, none);
6809 	dns_zone_setqueryonacl(zone, none);
6810 	dns_acl_detach(&none);
6811 
6812 	dns_zone_setdialup(zone, dns_dialuptype_no);
6813 	dns_zone_setnotifytype(zone, dns_notifytype_no);
6814 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
6815 	dns_zone_setjournalsize(zone, 0);
6816 
6817 	dns_zone_setstats(zone, named_g_server->zonestats);
6818 	CHECK(setquerystats(zone, mctx, dns_zonestat_none));
6819 
6820 	if (view->managed_keys != NULL) {
6821 		dns_zone_detach(&view->managed_keys);
6822 	}
6823 	dns_zone_attach(zone, &view->managed_keys);
6824 
6825 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6826 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6827 		      "set up managed keys zone for view %s, file '%s'",
6828 		      view->name, filename);
6829 
6830 cleanup:
6831 	if (zone != NULL) {
6832 		dns_zone_detach(&zone);
6833 	}
6834 	if (none != NULL) {
6835 		dns_acl_detach(&none);
6836 	}
6837 
6838 	return (result);
6839 }
6840 
6841 /*
6842  * Configure a single server quota.
6843  */
6844 static void
configure_server_quota(const cfg_obj_t ** maps,const char * name,isc_quota_t * quota)6845 configure_server_quota(const cfg_obj_t **maps, const char *name,
6846 		       isc_quota_t *quota) {
6847 	const cfg_obj_t *obj = NULL;
6848 	isc_result_t result;
6849 
6850 	result = named_config_get(maps, name, &obj);
6851 	INSIST(result == ISC_R_SUCCESS);
6852 	isc_quota_max(quota, cfg_obj_asuint32(obj));
6853 }
6854 
6855 /*
6856  * This function is called as soon as the 'directory' statement has been
6857  * parsed.  This can be extended to support other options if necessary.
6858  */
6859 static isc_result_t
directory_callback(const char * clausename,const cfg_obj_t * obj,void * arg)6860 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
6861 	isc_result_t result;
6862 	const char *directory;
6863 
6864 	REQUIRE(strcasecmp("directory", clausename) == 0);
6865 
6866 	UNUSED(arg);
6867 	UNUSED(clausename);
6868 
6869 	/*
6870 	 * Change directory.
6871 	 */
6872 	directory = cfg_obj_asstring(obj);
6873 
6874 	if (!isc_file_ischdiridempotent(directory)) {
6875 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
6876 			    "option 'directory' contains relative path '%s'",
6877 			    directory);
6878 	}
6879 
6880 #if 0
6881 	if (!isc_file_isdirwritable(directory)) {
6882 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6883 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6884 			      "directory '%s' is not writable", directory);
6885 		return (ISC_R_NOPERM);
6886 	}
6887 #endif
6888 
6889 	result = isc_dir_chdir(directory);
6890 	if (result != ISC_R_SUCCESS) {
6891 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
6892 			    "change directory to '%s' failed: %s", directory,
6893 			    isc_result_totext(result));
6894 		return (result);
6895 	}
6896 
6897 	return (ISC_R_SUCCESS);
6898 }
6899 
6900 /*
6901  * This event callback is invoked to do periodic network interface
6902  * scanning.
6903  */
6904 
6905 static void
interface_timer_tick(isc_task_t * task,isc_event_t * event)6906 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
6907 	named_server_t *server = (named_server_t *)event->ev_arg;
6908 	INSIST(task == server->task);
6909 	UNUSED(task);
6910 
6911 	isc_event_free(&event);
6912 	ns_interfacemgr_scan(server->interfacemgr, false);
6913 }
6914 
6915 static void
heartbeat_timer_tick(isc_task_t * task,isc_event_t * event)6916 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
6917 	named_server_t *server = (named_server_t *)event->ev_arg;
6918 	dns_view_t *view;
6919 
6920 	UNUSED(task);
6921 	isc_event_free(&event);
6922 	view = ISC_LIST_HEAD(server->viewlist);
6923 	while (view != NULL) {
6924 		dns_view_dialup(view);
6925 		view = ISC_LIST_NEXT(view, link);
6926 	}
6927 }
6928 
6929 typedef struct {
6930 	isc_mem_t *mctx;
6931 	isc_task_t *task;
6932 	dns_fetch_t *fetch;
6933 	dns_view_t *view;
6934 	dns_fixedname_t tatname;
6935 	dns_fixedname_t keyname;
6936 	dns_rdataset_t rdataset;
6937 	dns_rdataset_t sigrdataset;
6938 } ns_tat_t;
6939 
6940 static int
cid(const void * a,const void * b)6941 cid(const void *a, const void *b) {
6942 	const uint16_t ida = *(const uint16_t *)a;
6943 	const uint16_t idb = *(const uint16_t *)b;
6944 	if (ida < idb) {
6945 		return (-1);
6946 	} else if (ida > idb) {
6947 		return (1);
6948 	} else {
6949 		return (0);
6950 	}
6951 }
6952 
6953 static void
tat_done(isc_task_t * task,isc_event_t * event)6954 tat_done(isc_task_t *task, isc_event_t *event) {
6955 	dns_fetchevent_t *devent;
6956 	ns_tat_t *tat;
6957 
6958 	INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE);
6959 	INSIST(event->ev_arg != NULL);
6960 
6961 	UNUSED(task);
6962 
6963 	tat = event->ev_arg;
6964 	devent = (dns_fetchevent_t *)event;
6965 
6966 	/* Free resources which are not of interest */
6967 	if (devent->node != NULL) {
6968 		dns_db_detachnode(devent->db, &devent->node);
6969 	}
6970 	if (devent->db != NULL) {
6971 		dns_db_detach(&devent->db);
6972 	}
6973 	isc_event_free(&event);
6974 	dns_resolver_destroyfetch(&tat->fetch);
6975 	if (dns_rdataset_isassociated(&tat->rdataset)) {
6976 		dns_rdataset_disassociate(&tat->rdataset);
6977 	}
6978 	if (dns_rdataset_isassociated(&tat->sigrdataset)) {
6979 		dns_rdataset_disassociate(&tat->sigrdataset);
6980 	}
6981 	dns_view_detach(&tat->view);
6982 	isc_task_detach(&tat->task);
6983 	isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
6984 }
6985 
6986 struct dotat_arg {
6987 	dns_view_t *view;
6988 	isc_task_t *task;
6989 };
6990 
6991 /*%
6992  * Prepare the QNAME for the TAT query to be sent by processing the trust
6993  * anchors present at 'keynode' of 'keytable'.  Store the result in 'dst' and
6994  * the domain name which 'keynode' is associated with in 'origin'.
6995  *
6996  * A maximum of 12 key IDs can be reported in a single TAT query due to the
6997  * 63-octet length limit for any single label in a domain name.  If there are
6998  * more than 12 keys configured at 'keynode', only the first 12 will be
6999  * reported in the TAT query.
7000  */
7001 static isc_result_t
get_tat_qname(dns_name_t * target,dns_name_t * keyname,dns_keynode_t * keynode)7002 get_tat_qname(dns_name_t *target, dns_name_t *keyname, dns_keynode_t *keynode) {
7003 	dns_rdataset_t dsset;
7004 	unsigned int i, n = 0;
7005 	uint16_t ids[12];
7006 	isc_textregion_t r;
7007 	char label[64];
7008 	int m;
7009 
7010 	dns_rdataset_init(&dsset);
7011 	if (dns_keynode_dsset(keynode, &dsset)) {
7012 		isc_result_t result;
7013 
7014 		for (result = dns_rdataset_first(&dsset);
7015 		     result == ISC_R_SUCCESS;
7016 		     result = dns_rdataset_next(&dsset))
7017 		{
7018 			dns_rdata_t rdata = DNS_RDATA_INIT;
7019 			dns_rdata_ds_t ds;
7020 
7021 			dns_rdata_reset(&rdata);
7022 			dns_rdataset_current(&dsset, &rdata);
7023 			result = dns_rdata_tostruct(&rdata, &ds, NULL);
7024 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
7025 			if (n < (sizeof(ids) / sizeof(ids[0]))) {
7026 				ids[n] = ds.key_tag;
7027 				n++;
7028 			}
7029 		}
7030 		dns_rdataset_disassociate(&dsset);
7031 	}
7032 
7033 	if (n == 0) {
7034 		return (DNS_R_EMPTYNAME);
7035 	}
7036 
7037 	if (n > 1) {
7038 		qsort(ids, n, sizeof(ids[0]), cid);
7039 	}
7040 
7041 	/*
7042 	 * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
7043 	 * of the keyid.
7044 	 */
7045 	label[0] = 0;
7046 	r.base = label;
7047 	r.length = sizeof(label);
7048 	m = snprintf(r.base, r.length, "_ta");
7049 	if (m < 0 || (unsigned)m > r.length) {
7050 		return (ISC_R_FAILURE);
7051 	}
7052 	isc_textregion_consume(&r, m);
7053 	for (i = 0; i < n; i++) {
7054 		m = snprintf(r.base, r.length, "-%04x", ids[i]);
7055 		if (m < 0 || (unsigned)m > r.length) {
7056 			return (ISC_R_FAILURE);
7057 		}
7058 		isc_textregion_consume(&r, m);
7059 	}
7060 
7061 	return (dns_name_fromstring2(target, label, keyname, 0, NULL));
7062 }
7063 
7064 static void
tat_send(isc_task_t * task,isc_event_t * event)7065 tat_send(isc_task_t *task, isc_event_t *event) {
7066 	ns_tat_t *tat;
7067 	char namebuf[DNS_NAME_FORMATSIZE];
7068 	dns_fixedname_t fdomain;
7069 	dns_name_t *domain;
7070 	dns_rdataset_t nameservers;
7071 	isc_result_t result;
7072 	dns_name_t *keyname;
7073 	dns_name_t *tatname;
7074 
7075 	INSIST(event != NULL && event->ev_type == NAMED_EVENT_TATSEND);
7076 	INSIST(event->ev_arg != NULL);
7077 
7078 	UNUSED(task);
7079 
7080 	tat = event->ev_arg;
7081 
7082 	keyname = dns_fixedname_name(&tat->keyname);
7083 	tatname = dns_fixedname_name(&tat->tatname);
7084 
7085 	dns_name_format(tatname, namebuf, sizeof(namebuf));
7086 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7087 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7088 		      "%s: sending trust-anchor-telemetry query '%s/NULL'",
7089 		      tat->view->name, namebuf);
7090 
7091 	/*
7092 	 * TAT queries should be sent to the authoritative servers for a given
7093 	 * zone.  If this function is called for a keytable node corresponding
7094 	 * to a locally served zone, calling dns_resolver_createfetch() with
7095 	 * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be
7096 	 * resolved locally, without sending any TAT queries upstream.
7097 	 *
7098 	 * Work around this issue by calling dns_view_findzonecut() first.  If
7099 	 * the zone is served locally, the NS RRset for the given domain name
7100 	 * will be retrieved from local data; if it is not, the deepest zone
7101 	 * cut we have for it will be retrieved from cache.  In either case,
7102 	 * passing the results to dns_resolver_createfetch() will prevent it
7103 	 * from returning NXDOMAIN for 'tatname' while still allowing it to
7104 	 * chase down any potential delegations returned by upstream servers in
7105 	 * order to eventually find the destination host to send the TAT query
7106 	 * to.
7107 	 *
7108 	 * After the dns_view_findzonecut() call, 'domain' will hold the
7109 	 * deepest zone cut we can find for 'keyname' while 'nameservers' will
7110 	 * hold the NS RRset at that zone cut.
7111 	 */
7112 	domain = dns_fixedname_initname(&fdomain);
7113 	dns_rdataset_init(&nameservers);
7114 	result = dns_view_findzonecut(tat->view, keyname, domain, NULL, 0, 0,
7115 				      true, true, &nameservers, NULL);
7116 	if (result == ISC_R_SUCCESS) {
7117 		result = dns_resolver_createfetch(
7118 			tat->view->resolver, tatname, dns_rdatatype_null,
7119 			domain, &nameservers, NULL, NULL, 0, 0, 0, NULL,
7120 			tat->task, tat_done, tat, &tat->rdataset,
7121 			&tat->sigrdataset, &tat->fetch);
7122 	}
7123 
7124 	/*
7125 	 * 'domain' holds the dns_name_t pointer inside a dst_key_t structure.
7126 	 * dns_resolver_createfetch() creates its own copy of 'domain' if it
7127 	 * succeeds.  Thus, 'domain' is not freed here.
7128 	 *
7129 	 * Even if dns_view_findzonecut() returned something else than
7130 	 * ISC_R_SUCCESS, it still could have associated 'nameservers'.
7131 	 * dns_resolver_createfetch() creates its own copy of 'nameservers' if
7132 	 * it succeeds.  Thus, we need to check whether 'nameservers' is
7133 	 * associated and release it if it is.
7134 	 */
7135 	if (dns_rdataset_isassociated(&nameservers)) {
7136 		dns_rdataset_disassociate(&nameservers);
7137 	}
7138 
7139 	if (result != ISC_R_SUCCESS) {
7140 		dns_view_detach(&tat->view);
7141 		isc_task_detach(&tat->task);
7142 		isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
7143 	}
7144 	isc_event_free(&event);
7145 }
7146 
7147 static void
dotat(dns_keytable_t * keytable,dns_keynode_t * keynode,dns_name_t * keyname,void * arg)7148 dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, dns_name_t *keyname,
7149       void *arg) {
7150 	struct dotat_arg *dotat_arg = arg;
7151 	isc_result_t result;
7152 	dns_view_t *view;
7153 	isc_task_t *task;
7154 	ns_tat_t *tat;
7155 	isc_event_t *event;
7156 
7157 	REQUIRE(keytable != NULL);
7158 	REQUIRE(keynode != NULL);
7159 	REQUIRE(dotat_arg != NULL);
7160 
7161 	view = dotat_arg->view;
7162 	task = dotat_arg->task;
7163 
7164 	tat = isc_mem_get(dotat_arg->view->mctx, sizeof(*tat));
7165 
7166 	tat->fetch = NULL;
7167 	tat->mctx = NULL;
7168 	tat->task = NULL;
7169 	tat->view = NULL;
7170 	dns_rdataset_init(&tat->rdataset);
7171 	dns_rdataset_init(&tat->sigrdataset);
7172 	dns_name_copynf(keyname, dns_fixedname_initname(&tat->keyname));
7173 	result = get_tat_qname(dns_fixedname_initname(&tat->tatname), keyname,
7174 			       keynode);
7175 	if (result != ISC_R_SUCCESS) {
7176 		isc_mem_put(dotat_arg->view->mctx, tat, sizeof(*tat));
7177 		return;
7178 	}
7179 	isc_mem_attach(dotat_arg->view->mctx, &tat->mctx);
7180 	isc_task_attach(task, &tat->task);
7181 	dns_view_attach(view, &tat->view);
7182 
7183 	/*
7184 	 * We don't want to be holding the keytable lock when calling
7185 	 * dns_view_findzonecut() as it creates a lock order loop so
7186 	 * call dns_view_findzonecut() in a event handler.
7187 	 *
7188 	 * zone->lock (dns_zone_setviewcommit) while holding view->lock
7189 	 * (dns_view_setviewcommit)
7190 	 *
7191 	 * keytable->lock (dns_keytable_find) while holding zone->lock
7192 	 * (zone_asyncload)
7193 	 *
7194 	 * view->lock (dns_view_findzonecut) while holding keytable->lock
7195 	 * (dns_keytable_forall)
7196 	 */
7197 	event = isc_event_allocate(tat->mctx, keytable, NAMED_EVENT_TATSEND,
7198 				   tat_send, tat, sizeof(isc_event_t));
7199 	isc_task_send(task, &event);
7200 }
7201 
7202 static void
tat_timer_tick(isc_task_t * task,isc_event_t * event)7203 tat_timer_tick(isc_task_t *task, isc_event_t *event) {
7204 	isc_result_t result;
7205 	named_server_t *server = (named_server_t *)event->ev_arg;
7206 	struct dotat_arg arg;
7207 	dns_view_t *view;
7208 	dns_keytable_t *secroots = NULL;
7209 
7210 	isc_event_free(&event);
7211 
7212 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
7213 	     view = ISC_LIST_NEXT(view, link))
7214 	{
7215 		if (!view->trust_anchor_telemetry || !view->enablevalidation) {
7216 			continue;
7217 		}
7218 
7219 		result = dns_view_getsecroots(view, &secroots);
7220 		if (result != ISC_R_SUCCESS) {
7221 			continue;
7222 		}
7223 
7224 		arg.view = view;
7225 		arg.task = task;
7226 		(void)dns_keytable_forall(secroots, dotat, &arg);
7227 		dns_keytable_detach(&secroots);
7228 	}
7229 }
7230 
7231 static void
pps_timer_tick(isc_task_t * task,isc_event_t * event)7232 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
7233 	static unsigned int oldrequests = 0;
7234 	unsigned int requests = atomic_load_relaxed(&ns_client_requests);
7235 
7236 	UNUSED(task);
7237 	isc_event_free(&event);
7238 
7239 	/*
7240 	 * Don't worry about wrapping as the overflow result will be right.
7241 	 */
7242 	dns_pps = (requests - oldrequests) / 1200;
7243 	oldrequests = requests;
7244 }
7245 
7246 /*
7247  * Replace the current value of '*field', a dynamically allocated
7248  * string or NULL, with a dynamically allocated copy of the
7249  * null-terminated string pointed to by 'value', or NULL.
7250  */
7251 static isc_result_t
setstring(named_server_t * server,char ** field,const char * value)7252 setstring(named_server_t *server, char **field, const char *value) {
7253 	char *copy;
7254 
7255 	if (value != NULL) {
7256 		copy = isc_mem_strdup(server->mctx, value);
7257 	} else {
7258 		copy = NULL;
7259 	}
7260 
7261 	if (*field != NULL) {
7262 		isc_mem_free(server->mctx, *field);
7263 	}
7264 
7265 	*field = copy;
7266 	return (ISC_R_SUCCESS);
7267 }
7268 
7269 /*
7270  * Replace the current value of '*field', a dynamically allocated
7271  * string or NULL, with another dynamically allocated string
7272  * or NULL if whether 'obj' is a string or void value, respectively.
7273  */
7274 static isc_result_t
setoptstring(named_server_t * server,char ** field,const cfg_obj_t * obj)7275 setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) {
7276 	if (cfg_obj_isvoid(obj)) {
7277 		return (setstring(server, field, NULL));
7278 	} else {
7279 		return (setstring(server, field, cfg_obj_asstring(obj)));
7280 	}
7281 }
7282 
7283 static void
set_limit(const cfg_obj_t ** maps,const char * configname,const char * description,isc_resource_t resourceid,isc_resourcevalue_t defaultvalue)7284 set_limit(const cfg_obj_t **maps, const char *configname,
7285 	  const char *description, isc_resource_t resourceid,
7286 	  isc_resourcevalue_t defaultvalue) {
7287 	const cfg_obj_t *obj = NULL;
7288 	const char *resource;
7289 	isc_resourcevalue_t value;
7290 	isc_result_t result;
7291 
7292 	if (named_config_get(maps, configname, &obj) != ISC_R_SUCCESS) {
7293 		return;
7294 	}
7295 
7296 	if (cfg_obj_isstring(obj)) {
7297 		resource = cfg_obj_asstring(obj);
7298 		if (strcasecmp(resource, "unlimited") == 0) {
7299 			value = ISC_RESOURCE_UNLIMITED;
7300 		} else {
7301 			INSIST(strcasecmp(resource, "default") == 0);
7302 			value = defaultvalue;
7303 		}
7304 	} else {
7305 		value = cfg_obj_asuint64(obj);
7306 	}
7307 
7308 	result = isc_resource_setlimit(resourceid, value);
7309 	isc_log_write(
7310 		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7311 		result == ISC_R_SUCCESS ? ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
7312 		"set maximum %s to %" PRIu64 ": %s", description, value,
7313 		isc_result_totext(result));
7314 }
7315 
7316 #define SETLIMIT(cfgvar, resource, description)                       \
7317 	set_limit(maps, cfgvar, description, isc_resource_##resource, \
7318 		  named_g_init##resource)
7319 
7320 static void
set_limits(const cfg_obj_t ** maps)7321 set_limits(const cfg_obj_t **maps) {
7322 	SETLIMIT("stacksize", stacksize, "stack size");
7323 	SETLIMIT("datasize", datasize, "data size");
7324 	SETLIMIT("coresize", coresize, "core size");
7325 	SETLIMIT("files", openfiles, "open files");
7326 }
7327 
7328 static void
portset_fromconf(isc_portset_t * portset,const cfg_obj_t * ports,bool positive)7329 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
7330 		 bool positive) {
7331 	const cfg_listelt_t *element;
7332 
7333 	for (element = cfg_list_first(ports); element != NULL;
7334 	     element = cfg_list_next(element))
7335 	{
7336 		const cfg_obj_t *obj = cfg_listelt_value(element);
7337 
7338 		if (cfg_obj_isuint32(obj)) {
7339 			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
7340 
7341 			if (positive) {
7342 				isc_portset_add(portset, port);
7343 			} else {
7344 				isc_portset_remove(portset, port);
7345 			}
7346 		} else {
7347 			const cfg_obj_t *obj_loport, *obj_hiport;
7348 			in_port_t loport, hiport;
7349 
7350 			obj_loport = cfg_tuple_get(obj, "loport");
7351 			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
7352 			obj_hiport = cfg_tuple_get(obj, "hiport");
7353 			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
7354 
7355 			if (positive) {
7356 				isc_portset_addrange(portset, loport, hiport);
7357 			} else {
7358 				isc_portset_removerange(portset, loport,
7359 							hiport);
7360 			}
7361 		}
7362 	}
7363 }
7364 
7365 static isc_result_t
removed(dns_zone_t * zone,void * uap)7366 removed(dns_zone_t *zone, void *uap) {
7367 	if (dns_zone_getview(zone) != uap) {
7368 		return (ISC_R_SUCCESS);
7369 	}
7370 
7371 	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed",
7372 		     dns_zonetype_name(dns_zone_gettype(zone)));
7373 	return (ISC_R_SUCCESS);
7374 }
7375 
7376 static void
cleanup_session_key(named_server_t * server,isc_mem_t * mctx)7377 cleanup_session_key(named_server_t *server, isc_mem_t *mctx) {
7378 	if (server->session_keyfile != NULL) {
7379 		isc_file_remove(server->session_keyfile);
7380 		isc_mem_free(mctx, server->session_keyfile);
7381 		server->session_keyfile = NULL;
7382 	}
7383 
7384 	if (server->session_keyname != NULL) {
7385 		if (dns_name_dynamic(server->session_keyname)) {
7386 			dns_name_free(server->session_keyname, mctx);
7387 		}
7388 		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
7389 		server->session_keyname = NULL;
7390 	}
7391 
7392 	if (server->sessionkey != NULL) {
7393 		dns_tsigkey_detach(&server->sessionkey);
7394 	}
7395 
7396 	server->session_keyalg = DST_ALG_UNKNOWN;
7397 	server->session_keybits = 0;
7398 }
7399 
7400 static isc_result_t
generate_session_key(const char * filename,const char * keynamestr,const dns_name_t * keyname,const char * algstr,const dns_name_t * algname,unsigned int algtype,uint16_t bits,isc_mem_t * mctx,bool first_time,dns_tsigkey_t ** tsigkeyp)7401 generate_session_key(const char *filename, const char *keynamestr,
7402 		     const dns_name_t *keyname, const char *algstr,
7403 		     const dns_name_t *algname, unsigned int algtype,
7404 		     uint16_t bits, isc_mem_t *mctx, bool first_time,
7405 		     dns_tsigkey_t **tsigkeyp) {
7406 	isc_result_t result = ISC_R_SUCCESS;
7407 	dst_key_t *key = NULL;
7408 	isc_buffer_t key_txtbuffer;
7409 	isc_buffer_t key_rawbuffer;
7410 	char key_txtsecret[256];
7411 	char key_rawsecret[64];
7412 	isc_region_t key_rawregion;
7413 	isc_stdtime_t now;
7414 	dns_tsigkey_t *tsigkey = NULL;
7415 	FILE *fp = NULL;
7416 
7417 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7418 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7419 		      "generating session key for dynamic DNS");
7420 
7421 	/* generate key */
7422 	result = dst_key_generate(keyname, algtype, bits, 1, 0,
7423 				  DNS_KEYPROTO_ANY, dns_rdataclass_in, mctx,
7424 				  &key, NULL);
7425 	if (result != ISC_R_SUCCESS) {
7426 		return (result);
7427 	}
7428 
7429 	/*
7430 	 * Dump the key to the buffer for later use.  Should be done before
7431 	 * we transfer the ownership of key to tsigkey.
7432 	 */
7433 	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
7434 	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
7435 
7436 	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
7437 	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
7438 	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
7439 
7440 	/* Store the key in tsigkey. */
7441 	isc_stdtime_get(&now);
7442 	CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key, false,
7443 					NULL, now, now, mctx, NULL, &tsigkey));
7444 
7445 	/* Dump the key to the key file. */
7446 	fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time);
7447 	if (fp == NULL) {
7448 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7449 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7450 			      "could not create %s", filename);
7451 		result = ISC_R_NOPERM;
7452 		goto cleanup;
7453 	}
7454 
7455 	fprintf(fp,
7456 		"key \"%s\" {\n"
7457 		"\talgorithm %s;\n"
7458 		"\tsecret \"%.*s\";\n};\n",
7459 		keynamestr, algstr, (int)isc_buffer_usedlength(&key_txtbuffer),
7460 		(char *)isc_buffer_base(&key_txtbuffer));
7461 
7462 	CHECK(isc_stdio_flush(fp));
7463 	result = isc_stdio_close(fp);
7464 	fp = NULL;
7465 	if (result != ISC_R_SUCCESS) {
7466 		goto cleanup;
7467 	}
7468 
7469 	dst_key_free(&key);
7470 
7471 	*tsigkeyp = tsigkey;
7472 
7473 	return (ISC_R_SUCCESS);
7474 
7475 cleanup:
7476 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7477 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7478 		      "failed to generate session key "
7479 		      "for dynamic DNS: %s",
7480 		      isc_result_totext(result));
7481 	if (fp != NULL) {
7482 		(void)isc_stdio_close(fp);
7483 		(void)isc_file_remove(filename);
7484 	}
7485 	if (tsigkey != NULL) {
7486 		dns_tsigkey_detach(&tsigkey);
7487 	}
7488 	if (key != NULL) {
7489 		dst_key_free(&key);
7490 	}
7491 
7492 	return (result);
7493 }
7494 
7495 static isc_result_t
configure_session_key(const cfg_obj_t ** maps,named_server_t * server,isc_mem_t * mctx,bool first_time)7496 configure_session_key(const cfg_obj_t **maps, named_server_t *server,
7497 		      isc_mem_t *mctx, bool first_time) {
7498 	const char *keyfile, *keynamestr, *algstr;
7499 	unsigned int algtype;
7500 	dns_fixedname_t fname;
7501 	dns_name_t *keyname;
7502 	const dns_name_t *algname;
7503 	isc_buffer_t buffer;
7504 	uint16_t bits;
7505 	const cfg_obj_t *obj;
7506 	bool need_deleteold = false;
7507 	bool need_createnew = false;
7508 	isc_result_t result;
7509 
7510 	obj = NULL;
7511 	result = named_config_get(maps, "session-keyfile", &obj);
7512 	if (result == ISC_R_SUCCESS) {
7513 		if (cfg_obj_isvoid(obj)) {
7514 			keyfile = NULL; /* disable it */
7515 		} else {
7516 			keyfile = cfg_obj_asstring(obj);
7517 		}
7518 	} else {
7519 		keyfile = named_g_defaultsessionkeyfile;
7520 	}
7521 
7522 	obj = NULL;
7523 	result = named_config_get(maps, "session-keyname", &obj);
7524 	INSIST(result == ISC_R_SUCCESS);
7525 	keynamestr = cfg_obj_asstring(obj);
7526 	isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
7527 	isc_buffer_add(&buffer, strlen(keynamestr));
7528 	keyname = dns_fixedname_initname(&fname);
7529 	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
7530 	if (result != ISC_R_SUCCESS) {
7531 		return (result);
7532 	}
7533 
7534 	obj = NULL;
7535 	result = named_config_get(maps, "session-keyalg", &obj);
7536 	INSIST(result == ISC_R_SUCCESS);
7537 	algstr = cfg_obj_asstring(obj);
7538 	algname = NULL;
7539 	result = named_config_getkeyalgorithm2(algstr, &algname, &algtype,
7540 					       &bits);
7541 	if (result != ISC_R_SUCCESS) {
7542 		const char *s = " (keeping current key)";
7543 
7544 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7545 			    "session-keyalg: "
7546 			    "unsupported or unknown algorithm '%s'%s",
7547 			    algstr, server->session_keyfile != NULL ? s : "");
7548 		return (result);
7549 	}
7550 
7551 	/* See if we need to (re)generate a new key. */
7552 	if (keyfile == NULL) {
7553 		if (server->session_keyfile != NULL) {
7554 			need_deleteold = true;
7555 		}
7556 	} else if (server->session_keyfile == NULL) {
7557 		need_createnew = true;
7558 	} else if (strcmp(keyfile, server->session_keyfile) != 0 ||
7559 		   !dns_name_equal(server->session_keyname, keyname) ||
7560 		   server->session_keyalg != algtype ||
7561 		   server->session_keybits != bits)
7562 	{
7563 		need_deleteold = true;
7564 		need_createnew = true;
7565 	}
7566 
7567 	if (need_deleteold) {
7568 		INSIST(server->session_keyfile != NULL);
7569 		INSIST(server->session_keyname != NULL);
7570 		INSIST(server->sessionkey != NULL);
7571 
7572 		cleanup_session_key(server, mctx);
7573 	}
7574 
7575 	if (need_createnew) {
7576 		INSIST(server->sessionkey == NULL);
7577 		INSIST(server->session_keyfile == NULL);
7578 		INSIST(server->session_keyname == NULL);
7579 		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
7580 		INSIST(server->session_keybits == 0);
7581 
7582 		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
7583 		dns_name_init(server->session_keyname, NULL);
7584 		dns_name_dup(keyname, mctx, server->session_keyname);
7585 
7586 		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
7587 
7588 		server->session_keyalg = algtype;
7589 		server->session_keybits = bits;
7590 
7591 		CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
7592 					   algname, algtype, bits, mctx,
7593 					   first_time, &server->sessionkey));
7594 	}
7595 
7596 	return (result);
7597 
7598 cleanup:
7599 	cleanup_session_key(server, mctx);
7600 	return (result);
7601 }
7602 
7603 #ifndef HAVE_LMDB
7604 static isc_result_t
count_newzones(dns_view_t * view,ns_cfgctx_t * nzcfg,int * num_zonesp)7605 count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7606 	isc_result_t result;
7607 
7608 	/* The new zone file may not exist. That is OK. */
7609 	if (!isc_file_exists(view->new_zone_file)) {
7610 		*num_zonesp = 0;
7611 		return (ISC_R_SUCCESS);
7612 	}
7613 
7614 	/*
7615 	 * In the case of NZF files, we also parse the configuration in
7616 	 * the file at this stage.
7617 	 *
7618 	 * This may be called in multiple views, so we reset
7619 	 * the parser each time.
7620 	 */
7621 	cfg_parser_reset(named_g_addparser);
7622 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
7623 				&cfg_type_addzoneconf, &nzcfg->nzf_config);
7624 	if (result == ISC_R_SUCCESS) {
7625 		int num_zones;
7626 
7627 		num_zones = count_zones(nzcfg->nzf_config);
7628 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7629 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7630 			      "NZF file '%s' contains %d zones",
7631 			      view->new_zone_file, num_zones);
7632 		if (num_zonesp != NULL) {
7633 			*num_zonesp = num_zones;
7634 		}
7635 	} else {
7636 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7637 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7638 			      "Error parsing NZF file '%s': %s",
7639 			      view->new_zone_file, isc_result_totext(result));
7640 	}
7641 
7642 	return (result);
7643 }
7644 
7645 #else /* HAVE_LMDB */
7646 
7647 static isc_result_t
count_newzones(dns_view_t * view,ns_cfgctx_t * nzcfg,int * num_zonesp)7648 count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7649 	isc_result_t result;
7650 	int n;
7651 
7652 	UNUSED(nzcfg);
7653 
7654 	REQUIRE(num_zonesp != NULL);
7655 
7656 	LOCK(&view->new_zone_lock);
7657 
7658 	CHECK(migrate_nzf(view));
7659 
7660 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7661 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7662 		      "loading NZD zone count from '%s' "
7663 		      "for view '%s'",
7664 		      view->new_zone_db, view->name);
7665 
7666 	CHECK(nzd_count(view, &n));
7667 
7668 	*num_zonesp = n;
7669 
7670 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7671 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7672 		      "NZD database '%s' contains %d zones", view->new_zone_db,
7673 		      n);
7674 
7675 cleanup:
7676 	if (result != ISC_R_SUCCESS) {
7677 		*num_zonesp = 0;
7678 	}
7679 
7680 	UNLOCK(&view->new_zone_lock);
7681 
7682 	return (ISC_R_SUCCESS);
7683 }
7684 
7685 #endif /* HAVE_LMDB */
7686 
7687 static isc_result_t
setup_newzones(dns_view_t * view,cfg_obj_t * config,cfg_obj_t * vconfig,cfg_parser_t * conf_parser,cfg_aclconfctx_t * actx,int * num_zones)7688 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7689 	       cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx,
7690 	       int *num_zones) {
7691 	isc_result_t result = ISC_R_SUCCESS;
7692 	bool allow = false;
7693 	ns_cfgctx_t *nzcfg = NULL;
7694 	const cfg_obj_t *maps[4];
7695 	const cfg_obj_t *options = NULL, *voptions = NULL;
7696 	const cfg_obj_t *nz = NULL;
7697 	const cfg_obj_t *nzdir = NULL;
7698 	const char *dir = NULL;
7699 	const cfg_obj_t *obj = NULL;
7700 	int i = 0;
7701 	uint64_t mapsize = 0ULL;
7702 
7703 	REQUIRE(config != NULL);
7704 
7705 	if (vconfig != NULL) {
7706 		voptions = cfg_tuple_get(vconfig, "options");
7707 	}
7708 	if (voptions != NULL) {
7709 		maps[i++] = voptions;
7710 	}
7711 	result = cfg_map_get(config, "options", &options);
7712 	if (result == ISC_R_SUCCESS) {
7713 		maps[i++] = options;
7714 	}
7715 	maps[i++] = named_g_defaults;
7716 	maps[i] = NULL;
7717 
7718 	result = named_config_get(maps, "allow-new-zones", &nz);
7719 	if (result == ISC_R_SUCCESS) {
7720 		allow = cfg_obj_asboolean(nz);
7721 	}
7722 	result = named_config_get(maps, "new-zones-directory", &nzdir);
7723 	if (result == ISC_R_SUCCESS) {
7724 		dir = cfg_obj_asstring(nzdir);
7725 		result = isc_file_isdirectory(dir);
7726 		if (result != ISC_R_SUCCESS) {
7727 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
7728 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7729 				      "invalid new-zones-directory %s: %s", dir,
7730 				      isc_result_totext(result));
7731 			return (result);
7732 		}
7733 		if (!isc_file_isdirwritable(dir)) {
7734 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7735 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7736 				      "new-zones-directory '%s' "
7737 				      "is not writable",
7738 				      dir);
7739 			return (ISC_R_NOPERM);
7740 		}
7741 
7742 		dns_view_setnewzonedir(view, dir);
7743 	}
7744 
7745 #ifdef HAVE_LMDB
7746 	result = named_config_get(maps, "lmdb-mapsize", &obj);
7747 	if (result == ISC_R_SUCCESS && obj != NULL) {
7748 		mapsize = cfg_obj_asuint64(obj);
7749 		if (mapsize < (1ULL << 20)) { /* 1 megabyte */
7750 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7751 				    "'lmdb-mapsize "
7752 				    "%" PRId64 "' "
7753 				    "is too small",
7754 				    mapsize);
7755 			return (ISC_R_FAILURE);
7756 		} else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
7757 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7758 				    "'lmdb-mapsize "
7759 				    "%" PRId64 "' "
7760 				    "is too large",
7761 				    mapsize);
7762 			return (ISC_R_FAILURE);
7763 		}
7764 	}
7765 #else  /* ifdef HAVE_LMDB */
7766 	UNUSED(obj);
7767 #endif /* HAVE_LMDB */
7768 
7769 	/*
7770 	 * A non-empty catalog-zones statement implies allow-new-zones
7771 	 */
7772 	if (!allow) {
7773 		const cfg_obj_t *cz = NULL;
7774 		result = named_config_get(maps, "catalog-zones", &cz);
7775 		if (result == ISC_R_SUCCESS) {
7776 			const cfg_listelt_t *e =
7777 				cfg_list_first(cfg_tuple_get(cz, "zone list"));
7778 			if (e != NULL) {
7779 				allow = true;
7780 			}
7781 		}
7782 	}
7783 
7784 	if (!allow) {
7785 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7786 		if (num_zones != NULL) {
7787 			*num_zones = 0;
7788 		}
7789 		return (ISC_R_SUCCESS);
7790 	}
7791 
7792 	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
7793 
7794 	/*
7795 	 * We attach the parser that was used for config as well
7796 	 * as the one that will be used for added zones, to avoid
7797 	 * a shutdown race later.
7798 	 */
7799 	memset(nzcfg, 0, sizeof(*nzcfg));
7800 	cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
7801 	cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
7802 	isc_mem_attach(view->mctx, &nzcfg->mctx);
7803 	cfg_aclconfctx_attach(actx, &nzcfg->actx);
7804 
7805 	result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy,
7806 				      mapsize);
7807 	if (result != ISC_R_SUCCESS) {
7808 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7809 		return (result);
7810 	}
7811 
7812 	cfg_obj_attach(config, &nzcfg->config);
7813 	if (vconfig != NULL) {
7814 		cfg_obj_attach(vconfig, &nzcfg->vconfig);
7815 	}
7816 
7817 	result = count_newzones(view, nzcfg, num_zones);
7818 	return (result);
7819 }
7820 
7821 static void
configure_zone_setviewcommit(isc_result_t result,const cfg_obj_t * zconfig,dns_view_t * view)7822 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
7823 			     dns_view_t *view) {
7824 	const char *zname;
7825 	dns_fixedname_t fixorigin;
7826 	dns_name_t *origin;
7827 	isc_result_t result2;
7828 	dns_view_t *pview = NULL;
7829 	dns_zone_t *zone = NULL;
7830 
7831 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
7832 	origin = dns_fixedname_initname(&fixorigin);
7833 
7834 	result2 = dns_name_fromstring(origin, zname, 0, NULL);
7835 	if (result2 != ISC_R_SUCCESS) {
7836 		return;
7837 	}
7838 
7839 	result2 = dns_viewlist_find(&named_g_server->viewlist, view->name,
7840 				    view->rdclass, &pview);
7841 	if (result2 != ISC_R_SUCCESS) {
7842 		return;
7843 	}
7844 
7845 	result2 = dns_view_findzone(pview, origin, &zone);
7846 	if (result2 != ISC_R_SUCCESS) {
7847 		dns_view_detach(&pview);
7848 		return;
7849 	}
7850 
7851 	if (result == ISC_R_SUCCESS) {
7852 		dns_zone_setviewcommit(zone);
7853 	} else {
7854 		dns_zone_setviewrevert(zone);
7855 	}
7856 
7857 	dns_zone_detach(&zone);
7858 	dns_view_detach(&pview);
7859 }
7860 
7861 #ifndef HAVE_LMDB
7862 
7863 static isc_result_t
configure_newzones(dns_view_t * view,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,cfg_aclconfctx_t * actx)7864 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7865 		   isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
7866 	isc_result_t result;
7867 	ns_cfgctx_t *nzctx;
7868 	const cfg_obj_t *zonelist;
7869 	const cfg_listelt_t *element;
7870 
7871 	nzctx = view->new_zone_config;
7872 	if (nzctx == NULL || nzctx->nzf_config == NULL) {
7873 		return (ISC_R_SUCCESS);
7874 	}
7875 
7876 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7877 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7878 		      "loading additional zones for view '%s'", view->name);
7879 
7880 	zonelist = NULL;
7881 	cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
7882 
7883 	for (element = cfg_list_first(zonelist); element != NULL;
7884 	     element = cfg_list_next(element))
7885 	{
7886 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
7887 		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
7888 				     &named_g_server->viewlist,
7889 				     &named_g_server->kasplist, actx, true,
7890 				     false, false));
7891 	}
7892 
7893 	result = ISC_R_SUCCESS;
7894 
7895 cleanup:
7896 	for (element = cfg_list_first(zonelist); element != NULL;
7897 	     element = cfg_list_next(element))
7898 	{
7899 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
7900 		configure_zone_setviewcommit(result, zconfig, view);
7901 	}
7902 
7903 	return (result);
7904 }
7905 
7906 #else /* HAVE_LMDB */
7907 
7908 static isc_result_t
data_to_cfg(dns_view_t * view,MDB_val * key,MDB_val * data,isc_buffer_t ** text,cfg_obj_t ** zoneconfig)7909 data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text,
7910 	    cfg_obj_t **zoneconfig) {
7911 	isc_result_t result;
7912 	const char *zone_name;
7913 	size_t zone_name_len;
7914 	const char *zone_config;
7915 	size_t zone_config_len;
7916 	cfg_obj_t *zoneconf = NULL;
7917 	char bufname[DNS_NAME_FORMATSIZE];
7918 
7919 	REQUIRE(view != NULL);
7920 	REQUIRE(key != NULL);
7921 	REQUIRE(data != NULL);
7922 	REQUIRE(text != NULL);
7923 	REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
7924 
7925 	if (*text == NULL) {
7926 		isc_buffer_allocate(view->mctx, text, 256);
7927 	} else {
7928 		isc_buffer_clear(*text);
7929 	}
7930 
7931 	zone_name = (const char *)key->mv_data;
7932 	zone_name_len = key->mv_size;
7933 	INSIST(zone_name != NULL && zone_name_len > 0);
7934 
7935 	zone_config = (const char *)data->mv_data;
7936 	zone_config_len = data->mv_size;
7937 	INSIST(zone_config != NULL && zone_config_len > 0);
7938 
7939 	/* zone zonename { config; }; */
7940 	result = isc_buffer_reserve(text, 6 + zone_name_len + 2 +
7941 						  zone_config_len + 2);
7942 	if (result != ISC_R_SUCCESS) {
7943 		goto cleanup;
7944 	}
7945 
7946 	CHECK(putstr(text, "zone \""));
7947 	CHECK(putmem(text, (const void *)zone_name, zone_name_len));
7948 	CHECK(putstr(text, "\" "));
7949 	CHECK(putmem(text, (const void *)zone_config, zone_config_len));
7950 	CHECK(putstr(text, ";\n"));
7951 
7952 	snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len,
7953 		 zone_name);
7954 
7955 	cfg_parser_reset(named_g_addparser);
7956 	result = cfg_parse_buffer(named_g_addparser, *text, bufname, 0,
7957 				  &cfg_type_addzoneconf, 0, &zoneconf);
7958 	if (result != ISC_R_SUCCESS) {
7959 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7960 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7961 			      "parsing config for zone '%.*s' in "
7962 			      "NZD database '%s' failed",
7963 			      (int)zone_name_len, zone_name, view->new_zone_db);
7964 		goto cleanup;
7965 	}
7966 
7967 	*zoneconfig = zoneconf;
7968 	zoneconf = NULL;
7969 	result = ISC_R_SUCCESS;
7970 
7971 cleanup:
7972 	if (zoneconf != NULL) {
7973 		cfg_obj_destroy(named_g_addparser, &zoneconf);
7974 	}
7975 
7976 	return (result);
7977 }
7978 
7979 /*%
7980  * Prototype for a callback which can be used with for_all_newzone_cfgs().
7981  */
7982 typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
7983 					 cfg_obj_t *config, cfg_obj_t *vconfig,
7984 					 isc_mem_t *mctx, dns_view_t *view,
7985 					 cfg_aclconfctx_t *actx);
7986 
7987 /*%
7988  * For each zone found in a NZD opened by the caller, create an object
7989  * representing its configuration and invoke "callback" with the created
7990  * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all
7991  * these are non-global variables required to invoke configure_zone()).
7992  * Immediately interrupt processing if an error is encountered while
7993  * transforming NZD data into a zone configuration object or if "callback"
7994  * returns an error.
7995  *
7996  * Caller must hold 'view->new_zone_lock'.
7997  */
7998 static isc_result_t
for_all_newzone_cfgs(newzone_cfg_cb_t callback,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,dns_view_t * view,cfg_aclconfctx_t * actx,MDB_txn * txn,MDB_dbi dbi)7999 for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
8000 		     cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8001 		     cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi) {
8002 	const cfg_obj_t *zconfig, *zlist;
8003 	isc_result_t result = ISC_R_SUCCESS;
8004 	cfg_obj_t *zconfigobj = NULL;
8005 	isc_buffer_t *text = NULL;
8006 	MDB_cursor *cursor = NULL;
8007 	MDB_val data, key;
8008 	int status;
8009 
8010 	status = mdb_cursor_open(txn, dbi, &cursor);
8011 	if (status != MDB_SUCCESS) {
8012 		return (ISC_R_FAILURE);
8013 	}
8014 
8015 	for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
8016 	     status == MDB_SUCCESS;
8017 	     status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
8018 	{
8019 		/*
8020 		 * Create a configuration object from data fetched from NZD.
8021 		 */
8022 		result = data_to_cfg(view, &key, &data, &text, &zconfigobj);
8023 		if (result != ISC_R_SUCCESS) {
8024 			break;
8025 		}
8026 
8027 		/*
8028 		 * Extract zone configuration from configuration object.
8029 		 */
8030 		zlist = NULL;
8031 		result = cfg_map_get(zconfigobj, "zone", &zlist);
8032 		if (result != ISC_R_SUCCESS) {
8033 			break;
8034 		} else if (!cfg_obj_islist(zlist)) {
8035 			result = ISC_R_FAILURE;
8036 			break;
8037 		}
8038 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
8039 
8040 		/*
8041 		 * Invoke callback.
8042 		 */
8043 		result = callback(zconfig, config, vconfig, mctx, view, actx);
8044 		if (result != ISC_R_SUCCESS) {
8045 			break;
8046 		}
8047 
8048 		/*
8049 		 * Destroy the configuration object created in this iteration.
8050 		 */
8051 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8052 	}
8053 
8054 	if (text != NULL) {
8055 		isc_buffer_free(&text);
8056 	}
8057 	if (zconfigobj != NULL) {
8058 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8059 	}
8060 	mdb_cursor_close(cursor);
8061 
8062 	return (result);
8063 }
8064 
8065 /*%
8066  * Attempt to configure a zone found in NZD and return the result.
8067  */
8068 static isc_result_t
configure_newzone(const cfg_obj_t * zconfig,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,dns_view_t * view,cfg_aclconfctx_t * actx)8069 configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
8070 		  cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8071 		  cfg_aclconfctx_t *actx) {
8072 	return (configure_zone(
8073 		config, zconfig, vconfig, mctx, view, &named_g_server->viewlist,
8074 		&named_g_server->kasplist, actx, true, false, false));
8075 }
8076 
8077 /*%
8078  * Revert new view assignment for a zone found in NZD.
8079  */
8080 static isc_result_t
configure_newzone_revert(const cfg_obj_t * zconfig,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,dns_view_t * view,cfg_aclconfctx_t * actx)8081 configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config,
8082 			 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8083 			 cfg_aclconfctx_t *actx) {
8084 	UNUSED(config);
8085 	UNUSED(vconfig);
8086 	UNUSED(mctx);
8087 	UNUSED(actx);
8088 
8089 	configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view);
8090 
8091 	return (ISC_R_SUCCESS);
8092 }
8093 
8094 static isc_result_t
configure_newzones(dns_view_t * view,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,cfg_aclconfctx_t * actx)8095 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
8096 		   isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
8097 	isc_result_t result;
8098 	MDB_txn *txn = NULL;
8099 	MDB_dbi dbi;
8100 
8101 	if (view->new_zone_config == NULL) {
8102 		return (ISC_R_SUCCESS);
8103 	}
8104 
8105 	LOCK(&view->new_zone_lock);
8106 
8107 	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
8108 	if (result != ISC_R_SUCCESS) {
8109 		UNLOCK(&view->new_zone_lock);
8110 		return (ISC_R_SUCCESS);
8111 	}
8112 
8113 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8114 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8115 		      "loading NZD configs from '%s' "
8116 		      "for view '%s'",
8117 		      view->new_zone_db, view->name);
8118 
8119 	result = for_all_newzone_cfgs(configure_newzone, config, vconfig, mctx,
8120 				      view, actx, txn, dbi);
8121 	if (result != ISC_R_SUCCESS) {
8122 		/*
8123 		 * An error was encountered while attempting to configure zones
8124 		 * found in NZD.  As this error may have been caused by a
8125 		 * configure_zone() failure, try restoring a sane configuration
8126 		 * by reattaching all zones found in NZD to the old view.  If
8127 		 * this also fails, too bad, there is nothing more we can do in
8128 		 * terms of trying to make things right.
8129 		 */
8130 		(void)for_all_newzone_cfgs(configure_newzone_revert, config,
8131 					   vconfig, mctx, view, actx, txn, dbi);
8132 	}
8133 
8134 	(void)nzd_close(&txn, false);
8135 
8136 	UNLOCK(&view->new_zone_lock);
8137 
8138 	return (result);
8139 }
8140 
8141 static isc_result_t
get_newzone_config(dns_view_t * view,const char * zonename,cfg_obj_t ** zoneconfig)8142 get_newzone_config(dns_view_t *view, const char *zonename,
8143 		   cfg_obj_t **zoneconfig) {
8144 	isc_result_t result;
8145 	int status;
8146 	cfg_obj_t *zoneconf = NULL;
8147 	isc_buffer_t *text = NULL;
8148 	MDB_txn *txn = NULL;
8149 	MDB_dbi dbi;
8150 	MDB_val key, data;
8151 	char zname[DNS_NAME_FORMATSIZE];
8152 	dns_fixedname_t fname;
8153 	dns_name_t *name;
8154 	isc_buffer_t b;
8155 
8156 	INSIST(zoneconfig != NULL && *zoneconfig == NULL);
8157 
8158 	LOCK(&view->new_zone_lock);
8159 
8160 	CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
8161 
8162 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8163 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8164 		      "loading NZD config from '%s' "
8165 		      "for zone '%s'",
8166 		      view->new_zone_db, zonename);
8167 
8168 	/* Normalize zone name */
8169 	isc_buffer_constinit(&b, zonename, strlen(zonename));
8170 	isc_buffer_add(&b, strlen(zonename));
8171 	name = dns_fixedname_initname(&fname);
8172 	CHECK(dns_name_fromtext(name, &b, dns_rootname, DNS_NAME_DOWNCASE,
8173 				NULL));
8174 	dns_name_format(name, zname, sizeof(zname));
8175 
8176 	key.mv_data = zname;
8177 	key.mv_size = strlen(zname);
8178 
8179 	status = mdb_get(txn, dbi, &key, &data);
8180 	if (status != MDB_SUCCESS) {
8181 		CHECK(ISC_R_FAILURE);
8182 	}
8183 
8184 	CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
8185 
8186 	*zoneconfig = zoneconf;
8187 	zoneconf = NULL;
8188 	result = ISC_R_SUCCESS;
8189 
8190 cleanup:
8191 	(void)nzd_close(&txn, false);
8192 
8193 	UNLOCK(&view->new_zone_lock);
8194 
8195 	if (zoneconf != NULL) {
8196 		cfg_obj_destroy(named_g_addparser, &zoneconf);
8197 	}
8198 	if (text != NULL) {
8199 		isc_buffer_free(&text);
8200 	}
8201 
8202 	return (result);
8203 }
8204 
8205 #endif /* HAVE_LMDB */
8206 
8207 static int
count_zones(const cfg_obj_t * conf)8208 count_zones(const cfg_obj_t *conf) {
8209 	const cfg_obj_t *zonelist = NULL;
8210 	const cfg_listelt_t *element;
8211 	int n = 0;
8212 
8213 	REQUIRE(conf != NULL);
8214 
8215 	cfg_map_get(conf, "zone", &zonelist);
8216 	for (element = cfg_list_first(zonelist); element != NULL;
8217 	     element = cfg_list_next(element))
8218 	{
8219 		n++;
8220 	}
8221 
8222 	return (n);
8223 }
8224 
8225 static isc_result_t
check_lockfile(named_server_t * server,const cfg_obj_t * config,bool first_time)8226 check_lockfile(named_server_t *server, const cfg_obj_t *config,
8227 	       bool first_time) {
8228 	isc_result_t result;
8229 	const char *filename = NULL;
8230 	const cfg_obj_t *maps[3];
8231 	const cfg_obj_t *options;
8232 	const cfg_obj_t *obj;
8233 	int i;
8234 
8235 	i = 0;
8236 	options = NULL;
8237 	result = cfg_map_get(config, "options", &options);
8238 	if (result == ISC_R_SUCCESS) {
8239 		maps[i++] = options;
8240 	}
8241 	maps[i++] = named_g_defaults;
8242 	maps[i] = NULL;
8243 
8244 	obj = NULL;
8245 	(void)named_config_get(maps, "lock-file", &obj);
8246 
8247 	if (!first_time) {
8248 		if (obj != NULL && !cfg_obj_isstring(obj) &&
8249 		    server->lockfile != NULL &&
8250 		    strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
8251 		{
8252 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8253 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8254 				      "changing 'lock-file' "
8255 				      "has no effect until the "
8256 				      "server is restarted");
8257 		}
8258 
8259 		return (ISC_R_SUCCESS);
8260 	}
8261 
8262 	if (obj != NULL) {
8263 		if (cfg_obj_isvoid(obj)) {
8264 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8265 				      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
8266 				      "skipping lock-file check ");
8267 			return (ISC_R_SUCCESS);
8268 		} else if (named_g_forcelock) {
8269 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8270 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8271 				      "'lock-file' has no effect "
8272 				      "because the server was run with -X");
8273 			server->lockfile = isc_mem_strdup(
8274 				server->mctx, named_g_defaultlockfile);
8275 		} else {
8276 			filename = cfg_obj_asstring(obj);
8277 			server->lockfile = isc_mem_strdup(server->mctx,
8278 							  filename);
8279 		}
8280 
8281 		if (server->lockfile == NULL) {
8282 			return (ISC_R_NOMEMORY);
8283 		}
8284 	}
8285 
8286 	if (named_g_forcelock && named_g_defaultlockfile != NULL) {
8287 		INSIST(server->lockfile == NULL);
8288 		server->lockfile = isc_mem_strdup(server->mctx,
8289 						  named_g_defaultlockfile);
8290 	}
8291 
8292 	if (server->lockfile == NULL) {
8293 		return (ISC_R_SUCCESS);
8294 	}
8295 
8296 	if (named_os_issingleton(server->lockfile)) {
8297 		return (ISC_R_SUCCESS);
8298 	}
8299 
8300 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8301 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8302 		      "could not lock %s; another named "
8303 		      "process may be running",
8304 		      server->lockfile);
8305 	return (ISC_R_FAILURE);
8306 }
8307 
8308 static isc_result_t
load_configuration(const char * filename,named_server_t * server,bool first_time)8309 load_configuration(const char *filename, named_server_t *server,
8310 		   bool first_time) {
8311 	cfg_obj_t *config = NULL, *bindkeys = NULL;
8312 	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
8313 	const cfg_listelt_t *element;
8314 	const cfg_obj_t *builtin_views;
8315 	const cfg_obj_t *maps[3];
8316 	const cfg_obj_t *obj;
8317 	const cfg_obj_t *options;
8318 	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
8319 	const cfg_obj_t *kasps;
8320 	dns_kasp_t *kasp = NULL;
8321 	dns_kasp_t *kasp_next = NULL;
8322 	dns_kasplist_t tmpkasplist, kasplist;
8323 	const cfg_obj_t *views;
8324 	dns_view_t *view = NULL;
8325 	dns_view_t *view_next = NULL;
8326 	dns_viewlist_t tmpviewlist;
8327 	dns_viewlist_t viewlist, builtin_viewlist;
8328 	in_port_t listen_port, udpport_low, udpport_high;
8329 	int i, backlog;
8330 	int num_zones = 0;
8331 	bool exclusive = false;
8332 	isc_interval_t interval;
8333 	isc_logconfig_t *logc = NULL;
8334 	isc_portset_t *v4portset = NULL;
8335 	isc_portset_t *v6portset = NULL;
8336 	isc_resourcevalue_t nfiles;
8337 	isc_result_t result, tresult;
8338 	uint32_t heartbeat_interval;
8339 	uint32_t interface_interval;
8340 	uint32_t reserved;
8341 	uint32_t udpsize;
8342 	uint32_t transfer_message_size;
8343 	named_cache_t *nsc;
8344 	named_cachelist_t cachelist, tmpcachelist;
8345 	ns_altsecret_t *altsecret;
8346 	ns_altsecretlist_t altsecrets, tmpaltsecrets;
8347 	unsigned int maxsocks;
8348 	uint32_t softquota = 0;
8349 	uint32_t max;
8350 	uint64_t initial, idle, keepalive, advertised;
8351 	bool loadbalancesockets;
8352 	dns_aclenv_t *env =
8353 		ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
8354 
8355 	ISC_LIST_INIT(kasplist);
8356 	ISC_LIST_INIT(viewlist);
8357 	ISC_LIST_INIT(builtin_viewlist);
8358 	ISC_LIST_INIT(cachelist);
8359 	ISC_LIST_INIT(altsecrets);
8360 
8361 	/* Create the ACL configuration context */
8362 	if (named_g_aclconfctx != NULL) {
8363 		cfg_aclconfctx_detach(&named_g_aclconfctx);
8364 	}
8365 	CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx));
8366 
8367 	/*
8368 	 * Shut down all dyndb instances.
8369 	 */
8370 	dns_dyndb_cleanup(false);
8371 
8372 	/*
8373 	 * Parse the global default pseudo-config file.
8374 	 */
8375 	if (first_time) {
8376 		result = named_config_parsedefaults(named_g_parser,
8377 						    &named_g_config);
8378 		if (result != ISC_R_SUCCESS) {
8379 			named_main_earlyfatal("unable to load "
8380 					      "internal defaults: %s",
8381 					      isc_result_totext(result));
8382 		}
8383 		RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
8384 					  &named_g_defaults) == ISC_R_SUCCESS);
8385 	}
8386 
8387 	/*
8388 	 * Parse the configuration file using the new config code.
8389 	 */
8390 	config = NULL;
8391 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8392 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8393 		      "loading configuration from '%s'", filename);
8394 	CHECK(cfg_parser_create(named_g_mctx, named_g_lctx, &conf_parser));
8395 	cfg_parser_setcallback(conf_parser, directory_callback, NULL);
8396 	result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf,
8397 				&config);
8398 
8399 	CHECK(result);
8400 
8401 	/*
8402 	 * Check the validity of the configuration.
8403 	 *
8404 	 * (Ignore plugin parameters for now; they will be
8405 	 * checked later when the modules are actually loaded and
8406 	 * registered.)
8407 	 */
8408 	CHECK(bind9_check_namedconf(config, false, named_g_lctx, named_g_mctx));
8409 
8410 	/*
8411 	 * Fill in the maps array, used for resolving defaults.
8412 	 */
8413 	i = 0;
8414 	options = NULL;
8415 	result = cfg_map_get(config, "options", &options);
8416 	if (result == ISC_R_SUCCESS) {
8417 		maps[i++] = options;
8418 	}
8419 	maps[i++] = named_g_defaults;
8420 	maps[i] = NULL;
8421 
8422 	/*
8423 	 * If bind.keys exists, load it.  If "dnssec-validation auto"
8424 	 * is turned on, the root key found there will be used as a
8425 	 * default trust anchor.
8426 	 */
8427 	obj = NULL;
8428 	result = named_config_get(maps, "bindkeys-file", &obj);
8429 	INSIST(result == ISC_R_SUCCESS);
8430 	CHECKM(setstring(server, &server->bindkeysfile, cfg_obj_asstring(obj)),
8431 	       "strdup");
8432 	INSIST(server->bindkeysfile != NULL);
8433 
8434 	if (access(server->bindkeysfile, R_OK) == 0) {
8435 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8436 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8437 			      "reading built-in trust anchors "
8438 			      "from file '%s'",
8439 			      server->bindkeysfile);
8440 
8441 		CHECK(cfg_parser_create(named_g_mctx, named_g_lctx,
8442 					&bindkeys_parser));
8443 
8444 		result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
8445 					&cfg_type_bindkeys, &bindkeys);
8446 		if (result != ISC_R_SUCCESS) {
8447 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8448 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8449 				      "unable to parse '%s' error '%s'; using "
8450 				      "built-in keys instead",
8451 				      server->bindkeysfile,
8452 				      isc_result_totext(result));
8453 		}
8454 	} else {
8455 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8456 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8457 			      "unable to open '%s'; using built-in keys "
8458 			      "instead",
8459 			      server->bindkeysfile);
8460 	}
8461 
8462 	/* Ensure exclusive access to configuration data. */
8463 	if (!exclusive) {
8464 		result = isc_task_beginexclusive(server->task);
8465 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
8466 		exclusive = true;
8467 	}
8468 
8469 	/*
8470 	 * Set process limits, which (usually) needs to be done as root.
8471 	 */
8472 	set_limits(maps);
8473 
8474 	/*
8475 	 * Check the process lockfile.
8476 	 */
8477 	CHECK(check_lockfile(server, config, first_time));
8478 
8479 	/*
8480 	 * Check if max number of open sockets that the system allows is
8481 	 * sufficiently large.	Failing this condition is not necessarily fatal,
8482 	 * but may cause subsequent runtime failures for a busy recursive
8483 	 * server.
8484 	 */
8485 	result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &maxsocks);
8486 	if (result != ISC_R_SUCCESS) {
8487 		maxsocks = 0;
8488 	}
8489 	result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
8490 	if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
8491 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8492 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8493 			      "max open files (%" PRIu64 ")"
8494 			      " is smaller than max sockets (%u)",
8495 			      nfiles, maxsocks);
8496 	}
8497 
8498 	/*
8499 	 * Set the number of socket reserved for TCP, stdio etc.
8500 	 */
8501 	obj = NULL;
8502 	result = named_config_get(maps, "reserved-sockets", &obj);
8503 	INSIST(result == ISC_R_SUCCESS);
8504 	reserved = cfg_obj_asuint32(obj);
8505 	if (maxsocks != 0) {
8506 		if (maxsocks < 128U) { /* Prevent underflow. */
8507 			reserved = 0;
8508 		} else if (reserved > maxsocks - 128U) { /* Minimum UDP space.
8509 							  */
8510 			reserved = maxsocks - 128;
8511 		}
8512 	}
8513 	/* Minimum TCP/stdio space. */
8514 	if (reserved < 128U) {
8515 		reserved = 128;
8516 	}
8517 	if (reserved + 128U > maxsocks && maxsocks != 0) {
8518 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8519 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8520 			      "less than 128 UDP sockets available after "
8521 			      "applying 'reserved-sockets' and 'maxsockets'");
8522 	}
8523 	isc_socketmgr_setreserved(named_g_socketmgr, reserved);
8524 
8525 #if defined(HAVE_GEOIP2)
8526 	/*
8527 	 * Release any previously opened GeoIP2 databases.
8528 	 */
8529 	named_geoip_unload();
8530 
8531 	/*
8532 	 * Initialize GeoIP databases from the configured location.
8533 	 * This should happen before configuring any ACLs, so that we
8534 	 * know what databases are available and can reject any GeoIP
8535 	 * ACLs that can't work.
8536 	 */
8537 	obj = NULL;
8538 	result = named_config_get(maps, "geoip-directory", &obj);
8539 	INSIST(result == ISC_R_SUCCESS);
8540 	if (cfg_obj_isstring(obj)) {
8541 		char *dir;
8542 		DE_CONST(cfg_obj_asstring(obj), dir);
8543 		named_geoip_load(dir);
8544 	}
8545 	named_g_aclconfctx->geoip = named_g_geoip;
8546 #endif /* HAVE_GEOIP2 */
8547 
8548 	/*
8549 	 * Configure various server options.
8550 	 */
8551 	configure_server_quota(maps, "transfers-out",
8552 			       &server->sctx->xfroutquota);
8553 	configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
8554 	configure_server_quota(maps, "recursive-clients",
8555 			       &server->sctx->recursionquota);
8556 	configure_server_quota(maps, "update-quota", &server->sctx->updquota);
8557 
8558 	max = isc_quota_getmax(&server->sctx->recursionquota);
8559 	if (max > 1000) {
8560 		unsigned margin = ISC_MAX(100, named_g_cpus + 1);
8561 		if (margin + 100 > max) {
8562 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8563 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8564 				      "'recursive-clients %d' too low when "
8565 				      "running with %d worker threads",
8566 				      max, named_g_cpus);
8567 			CHECK(ISC_R_RANGE);
8568 		}
8569 		softquota = max - margin;
8570 	} else {
8571 		softquota = (max * 90) / 100;
8572 	}
8573 
8574 	isc_quota_soft(&server->sctx->recursionquota, softquota);
8575 
8576 	/*
8577 	 * Set "blackhole". Only legal at options level; there is
8578 	 * no default.
8579 	 */
8580 	CHECK(configure_view_acl(NULL, config, NULL, "blackhole", NULL,
8581 				 named_g_aclconfctx, named_g_mctx,
8582 				 &server->sctx->blackholeacl));
8583 	if (server->sctx->blackholeacl != NULL) {
8584 		dns_dispatchmgr_setblackhole(named_g_dispatchmgr,
8585 					     server->sctx->blackholeacl);
8586 	}
8587 
8588 	/*
8589 	 * Set "keep-response-order". Only legal at options or
8590 	 * global defaults level.
8591 	 */
8592 	CHECK(configure_view_acl(NULL, config, named_g_config,
8593 				 "keep-response-order", NULL,
8594 				 named_g_aclconfctx, named_g_mctx,
8595 				 &server->sctx->keepresporder));
8596 
8597 	obj = NULL;
8598 	result = named_config_get(maps, "match-mapped-addresses", &obj);
8599 	INSIST(result == ISC_R_SUCCESS);
8600 	env->match_mapped = cfg_obj_asboolean(obj);
8601 
8602 	CHECKM(named_statschannels_configure(named_g_server, config,
8603 					     named_g_aclconfctx),
8604 	       "configuring statistics server(s)");
8605 
8606 	obj = NULL;
8607 	result = named_config_get(maps, "tcp-initial-timeout", &obj);
8608 	INSIST(result == ISC_R_SUCCESS);
8609 	initial = cfg_obj_asuint32(obj) * 100;
8610 	if (initial > MAX_INITIAL_TIMEOUT) {
8611 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8612 			    "tcp-initial-timeout value is out of range: "
8613 			    "lowering to %" PRIu32,
8614 			    MAX_INITIAL_TIMEOUT / 100);
8615 		initial = MAX_INITIAL_TIMEOUT;
8616 	} else if (initial < MIN_INITIAL_TIMEOUT) {
8617 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8618 			    "tcp-initial-timeout value is out of range: "
8619 			    "raising to %" PRIu32,
8620 			    MIN_INITIAL_TIMEOUT / 100);
8621 		initial = MIN_INITIAL_TIMEOUT;
8622 	}
8623 
8624 	obj = NULL;
8625 	result = named_config_get(maps, "tcp-idle-timeout", &obj);
8626 	INSIST(result == ISC_R_SUCCESS);
8627 	idle = cfg_obj_asuint32(obj) * 100;
8628 	if (idle > MAX_IDLE_TIMEOUT) {
8629 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8630 			    "tcp-idle-timeout value is out of range: "
8631 			    "lowering to %" PRIu32,
8632 			    MAX_IDLE_TIMEOUT / 100);
8633 		idle = MAX_IDLE_TIMEOUT;
8634 	} else if (idle < MIN_IDLE_TIMEOUT) {
8635 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8636 			    "tcp-idle-timeout value is out of range: "
8637 			    "raising to %" PRIu32,
8638 			    MIN_IDLE_TIMEOUT / 100);
8639 		idle = MIN_IDLE_TIMEOUT;
8640 	}
8641 
8642 	obj = NULL;
8643 	result = named_config_get(maps, "tcp-keepalive-timeout", &obj);
8644 	INSIST(result == ISC_R_SUCCESS);
8645 	keepalive = cfg_obj_asuint32(obj) * 100;
8646 	if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
8647 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8648 			    "tcp-keepalive-timeout value is out of range: "
8649 			    "lowering to %" PRIu32,
8650 			    MAX_KEEPALIVE_TIMEOUT / 100);
8651 		keepalive = MAX_KEEPALIVE_TIMEOUT;
8652 	} else if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
8653 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8654 			    "tcp-keepalive-timeout value is out of range: "
8655 			    "raising to %" PRIu32,
8656 			    MIN_KEEPALIVE_TIMEOUT / 100);
8657 		keepalive = MIN_KEEPALIVE_TIMEOUT;
8658 	}
8659 
8660 	obj = NULL;
8661 	result = named_config_get(maps, "tcp-advertised-timeout", &obj);
8662 	INSIST(result == ISC_R_SUCCESS);
8663 	advertised = cfg_obj_asuint32(obj) * 100;
8664 	if (advertised > MAX_ADVERTISED_TIMEOUT) {
8665 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8666 			    "tcp-advertized-timeout value is out of range: "
8667 			    "lowering to %" PRIu32,
8668 			    MAX_ADVERTISED_TIMEOUT / 100);
8669 		advertised = MAX_ADVERTISED_TIMEOUT;
8670 	}
8671 
8672 	isc_nm_settimeouts(named_g_nm, initial, idle, keepalive, advertised);
8673 
8674 	/*
8675 	 * Configure sets of UDP query source ports.
8676 	 */
8677 	CHECKM(isc_portset_create(named_g_mctx, &v4portset), "creating UDP "
8678 							     "port set");
8679 	CHECKM(isc_portset_create(named_g_mctx, &v6portset), "creating UDP "
8680 							     "port set");
8681 
8682 	usev4ports = NULL;
8683 	usev6ports = NULL;
8684 	avoidv4ports = NULL;
8685 	avoidv6ports = NULL;
8686 
8687 	(void)named_config_get(maps, "use-v4-udp-ports", &usev4ports);
8688 	if (usev4ports != NULL) {
8689 		portset_fromconf(v4portset, usev4ports, true);
8690 	} else {
8691 		CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
8692 					       &udpport_high),
8693 		       "get the default UDP/IPv4 port range");
8694 		if (udpport_low == udpport_high) {
8695 			isc_portset_add(v4portset, udpport_low);
8696 		} else {
8697 			isc_portset_addrange(v4portset, udpport_low,
8698 					     udpport_high);
8699 		}
8700 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) {
8701 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8702 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8703 				      "using default UDP/IPv4 port range: "
8704 				      "[%d, %d]",
8705 				      udpport_low, udpport_high);
8706 		}
8707 	}
8708 	(void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
8709 	if (avoidv4ports != NULL) {
8710 		portset_fromconf(v4portset, avoidv4ports, false);
8711 	}
8712 
8713 	(void)named_config_get(maps, "use-v6-udp-ports", &usev6ports);
8714 	if (usev6ports != NULL) {
8715 		portset_fromconf(v6portset, usev6ports, true);
8716 	} else {
8717 		CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
8718 					       &udpport_high),
8719 		       "get the default UDP/IPv6 port range");
8720 		if (udpport_low == udpport_high) {
8721 			isc_portset_add(v6portset, udpport_low);
8722 		} else {
8723 			isc_portset_addrange(v6portset, udpport_low,
8724 					     udpport_high);
8725 		}
8726 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) {
8727 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8728 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8729 				      "using default UDP/IPv6 port range: "
8730 				      "[%d, %d]",
8731 				      udpport_low, udpport_high);
8732 		}
8733 	}
8734 	(void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
8735 	if (avoidv6ports != NULL) {
8736 		portset_fromconf(v6portset, avoidv6ports, false);
8737 	}
8738 
8739 	dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset,
8740 				      v6portset);
8741 
8742 	/*
8743 	 * Set the EDNS UDP size when we don't match a view.
8744 	 */
8745 	obj = NULL;
8746 	result = named_config_get(maps, "edns-udp-size", &obj);
8747 	INSIST(result == ISC_R_SUCCESS);
8748 	udpsize = cfg_obj_asuint32(obj);
8749 	if (udpsize < 512) {
8750 		udpsize = 512;
8751 	}
8752 	if (udpsize > 4096) {
8753 		udpsize = 4096;
8754 	}
8755 	server->sctx->udpsize = (uint16_t)udpsize;
8756 
8757 	/* Set the transfer message size for TCP */
8758 	obj = NULL;
8759 	result = named_config_get(maps, "transfer-message-size", &obj);
8760 	INSIST(result == ISC_R_SUCCESS);
8761 	transfer_message_size = cfg_obj_asuint32(obj);
8762 	if (transfer_message_size < 512) {
8763 		transfer_message_size = 512;
8764 	} else if (transfer_message_size > 65535) {
8765 		transfer_message_size = 65535;
8766 	}
8767 	server->sctx->transfer_tcp_message_size =
8768 		(uint16_t)transfer_message_size;
8769 
8770 	/*
8771 	 * Configure the zone manager.
8772 	 */
8773 	obj = NULL;
8774 	result = named_config_get(maps, "transfers-in", &obj);
8775 	INSIST(result == ISC_R_SUCCESS);
8776 	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
8777 
8778 	obj = NULL;
8779 	result = named_config_get(maps, "transfers-per-ns", &obj);
8780 	INSIST(result == ISC_R_SUCCESS);
8781 	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
8782 
8783 	obj = NULL;
8784 	result = named_config_get(maps, "notify-rate", &obj);
8785 	INSIST(result == ISC_R_SUCCESS);
8786 	dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
8787 
8788 	obj = NULL;
8789 	result = named_config_get(maps, "startup-notify-rate", &obj);
8790 	INSIST(result == ISC_R_SUCCESS);
8791 	dns_zonemgr_setstartupnotifyrate(server->zonemgr,
8792 					 cfg_obj_asuint32(obj));
8793 
8794 	obj = NULL;
8795 	result = named_config_get(maps, "serial-query-rate", &obj);
8796 	INSIST(result == ISC_R_SUCCESS);
8797 	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
8798 
8799 	/*
8800 	 * Determine which port to use for listening for incoming connections.
8801 	 */
8802 	if (named_g_port != 0) {
8803 		listen_port = named_g_port;
8804 	} else {
8805 		CHECKM(named_config_getport(config, &listen_port), "port");
8806 	}
8807 
8808 	/*
8809 	 * Determining the default DSCP code point.
8810 	 */
8811 	CHECKM(named_config_getdscp(config, &named_g_dscp), "dscp");
8812 
8813 	/*
8814 	 * Find the listen queue depth.
8815 	 */
8816 	obj = NULL;
8817 	result = named_config_get(maps, "tcp-listen-queue", &obj);
8818 	INSIST(result == ISC_R_SUCCESS);
8819 	backlog = cfg_obj_asuint32(obj);
8820 	if ((backlog > 0) && (backlog < 10)) {
8821 		backlog = 10;
8822 	}
8823 	ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
8824 
8825 	obj = NULL;
8826 	result = named_config_get(maps, "reuseport", &obj);
8827 	INSIST(result == ISC_R_SUCCESS);
8828 	loadbalancesockets = cfg_obj_asboolean(obj);
8829 #if HAVE_SO_REUSEPORT_LB
8830 	if (first_time) {
8831 		isc_nm_setloadbalancesockets(named_g_nm,
8832 					     cfg_obj_asboolean(obj));
8833 	} else if (loadbalancesockets !=
8834 		   isc_nm_getloadbalancesockets(named_g_nm))
8835 	{
8836 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8837 			    "changing reuseport value requires server restart");
8838 	}
8839 #else
8840 	if (loadbalancesockets) {
8841 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8842 			    "reuseport has no effect on this system");
8843 	}
8844 #endif
8845 
8846 	/*
8847 	 * Configure the interface manager according to the "listen-on"
8848 	 * statement.
8849 	 */
8850 	{
8851 		const cfg_obj_t *clistenon = NULL;
8852 		ns_listenlist_t *listenon = NULL;
8853 
8854 		clistenon = NULL;
8855 		/*
8856 		 * Even though listen-on is present in the default
8857 		 * configuration, this way is easier.
8858 		 */
8859 		if (options != NULL) {
8860 			(void)cfg_map_get(options, "listen-on", &clistenon);
8861 		}
8862 		if (clistenon != NULL) {
8863 			/* check return code? */
8864 			(void)ns_listenlist_fromconfig(
8865 				clistenon, config, named_g_aclconfctx,
8866 				named_g_mctx, AF_INET, &listenon);
8867 		} else {
8868 			/*
8869 			 * Not specified, use default.
8870 			 */
8871 			CHECK(ns_listenlist_default(named_g_mctx, listen_port,
8872 						    -1, true, &listenon));
8873 		}
8874 		if (listenon != NULL) {
8875 			ns_interfacemgr_setlistenon4(server->interfacemgr,
8876 						     listenon);
8877 			ns_listenlist_detach(&listenon);
8878 		}
8879 	}
8880 	/*
8881 	 * Ditto for IPv6.
8882 	 */
8883 	{
8884 		const cfg_obj_t *clistenon = NULL;
8885 		ns_listenlist_t *listenon = NULL;
8886 
8887 		if (options != NULL) {
8888 			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
8889 		}
8890 		if (clistenon != NULL) {
8891 			/* check return code? */
8892 			(void)ns_listenlist_fromconfig(
8893 				clistenon, config, named_g_aclconfctx,
8894 				named_g_mctx, AF_INET6, &listenon);
8895 		} else {
8896 			/*
8897 			 * Not specified, use default.
8898 			 */
8899 			CHECK(ns_listenlist_default(named_g_mctx, listen_port,
8900 						    -1, true, &listenon));
8901 		}
8902 		if (listenon != NULL) {
8903 			ns_interfacemgr_setlistenon6(server->interfacemgr,
8904 						     listenon);
8905 			ns_listenlist_detach(&listenon);
8906 		}
8907 	}
8908 
8909 	/*
8910 	 * Rescan the interface list to pick up changes in the
8911 	 * listen-on option.  It's important that we do this before we try
8912 	 * to configure the query source, since the dispatcher we use might
8913 	 * be shared with an interface.
8914 	 */
8915 	result = ns_interfacemgr_scan(server->interfacemgr, true);
8916 
8917 	/*
8918 	 * Check that named is able to TCP listen on at least one
8919 	 * interface. Otherwise, another named process could be running
8920 	 * and we should fail.
8921 	 */
8922 	if (first_time && (result == ISC_R_ADDRINUSE)) {
8923 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8924 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8925 			      "unable to listen on any configured interfaces");
8926 		result = ISC_R_FAILURE;
8927 		goto cleanup;
8928 	}
8929 
8930 	/*
8931 	 * Arrange for further interface scanning to occur periodically
8932 	 * as specified by the "interface-interval" option.
8933 	 */
8934 	obj = NULL;
8935 	result = named_config_get(maps, "interface-interval", &obj);
8936 	INSIST(result == ISC_R_SUCCESS);
8937 	interface_interval = cfg_obj_asduration(obj);
8938 	if (interface_interval == 0) {
8939 		CHECK(isc_timer_reset(server->interface_timer,
8940 				      isc_timertype_inactive, NULL, NULL,
8941 				      true));
8942 	} else if (server->interface_interval != interface_interval) {
8943 		isc_interval_set(&interval, interface_interval, 0);
8944 		CHECK(isc_timer_reset(server->interface_timer,
8945 				      isc_timertype_ticker, NULL, &interval,
8946 				      false));
8947 	}
8948 	server->interface_interval = interface_interval;
8949 
8950 	/*
8951 	 * Enable automatic interface scans.
8952 	 */
8953 	obj = NULL;
8954 	result = named_config_get(maps, "automatic-interface-scan", &obj);
8955 	INSIST(result == ISC_R_SUCCESS);
8956 	server->sctx->interface_auto = cfg_obj_asboolean(obj);
8957 
8958 	/*
8959 	 * Configure the dialup heartbeat timer.
8960 	 */
8961 	obj = NULL;
8962 	result = named_config_get(maps, "heartbeat-interval", &obj);
8963 	INSIST(result == ISC_R_SUCCESS);
8964 	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
8965 	if (heartbeat_interval == 0) {
8966 		CHECK(isc_timer_reset(server->heartbeat_timer,
8967 				      isc_timertype_inactive, NULL, NULL,
8968 				      true));
8969 	} else if (server->heartbeat_interval != heartbeat_interval) {
8970 		isc_interval_set(&interval, heartbeat_interval, 0);
8971 		CHECK(isc_timer_reset(server->heartbeat_timer,
8972 				      isc_timertype_ticker, NULL, &interval,
8973 				      false));
8974 	}
8975 	server->heartbeat_interval = heartbeat_interval;
8976 
8977 	isc_interval_set(&interval, 1200, 0);
8978 	CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
8979 			      &interval, false));
8980 
8981 	isc_interval_set(&interval, named_g_tat_interval, 0);
8982 	CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker, NULL,
8983 			      &interval, false));
8984 
8985 	/*
8986 	 * Write the PID file.
8987 	 */
8988 	obj = NULL;
8989 	if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) {
8990 		if (cfg_obj_isvoid(obj)) {
8991 			named_os_writepidfile(NULL, first_time);
8992 		} else {
8993 			named_os_writepidfile(cfg_obj_asstring(obj),
8994 					      first_time);
8995 		}
8996 	} else {
8997 		named_os_writepidfile(named_g_defaultpidfile, first_time);
8998 	}
8999 
9000 	/*
9001 	 * Configure the server-wide session key.  This must be done before
9002 	 * configure views because zone configuration may need to know
9003 	 * session-keyname.
9004 	 *
9005 	 * Failure of session key generation isn't fatal at this time; if it
9006 	 * turns out that a session key is really needed but doesn't exist,
9007 	 * we'll treat it as a fatal error then.
9008 	 */
9009 	(void)configure_session_key(maps, server, named_g_mctx, first_time);
9010 
9011 	/*
9012 	 * Create the DNSSEC key and signing policies (KASP).
9013 	 */
9014 	kasps = NULL;
9015 	(void)cfg_map_get(config, "dnssec-policy", &kasps);
9016 	for (element = cfg_list_first(kasps); element != NULL;
9017 	     element = cfg_list_next(element))
9018 	{
9019 		cfg_obj_t *kconfig = cfg_listelt_value(element);
9020 		kasp = NULL;
9021 		CHECK(cfg_kasp_fromconfig(kconfig, NULL, named_g_mctx,
9022 					  named_g_lctx, &kasplist, &kasp));
9023 		INSIST(kasp != NULL);
9024 		dns_kasp_freeze(kasp);
9025 		dns_kasp_detach(&kasp);
9026 	}
9027 	/*
9028 	 * Create the built-in kasp policies ("default", "insecure").
9029 	 */
9030 	kasp = NULL;
9031 	CHECK(cfg_kasp_fromconfig(NULL, "default", named_g_mctx, named_g_lctx,
9032 				  &kasplist, &kasp));
9033 	INSIST(kasp != NULL);
9034 	dns_kasp_freeze(kasp);
9035 	dns_kasp_detach(&kasp);
9036 
9037 	kasp = NULL;
9038 	CHECK(cfg_kasp_fromconfig(NULL, "insecure", named_g_mctx, named_g_lctx,
9039 				  &kasplist, &kasp));
9040 	INSIST(kasp != NULL);
9041 	dns_kasp_freeze(kasp);
9042 	dns_kasp_detach(&kasp);
9043 
9044 	tmpkasplist = server->kasplist;
9045 	server->kasplist = kasplist;
9046 	kasplist = tmpkasplist;
9047 
9048 	/*
9049 	 * Configure the views.
9050 	 */
9051 	views = NULL;
9052 	(void)cfg_map_get(config, "view", &views);
9053 
9054 	/*
9055 	 * Create the views and count all the configured zones in
9056 	 * order to correctly size the zone manager's task table.
9057 	 * (We only count zones for configured views; the built-in
9058 	 * "bind" view can be ignored as it only adds a negligible
9059 	 * number of zones.)
9060 	 *
9061 	 * If we're allowing new zones, we need to be able to find the
9062 	 * new zone file and count those as well.  So we setup the new
9063 	 * zone configuration context, but otherwise view configuration
9064 	 * waits until after the zone manager's task list has been sized.
9065 	 */
9066 	for (element = cfg_list_first(views); element != NULL;
9067 	     element = cfg_list_next(element))
9068 	{
9069 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9070 		const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
9071 		int nzf_num_zones;
9072 
9073 		view = NULL;
9074 
9075 		CHECK(create_view(vconfig, &viewlist, &view));
9076 		INSIST(view != NULL);
9077 
9078 		num_zones += count_zones(voptions);
9079 
9080 		CHECK(setup_newzones(view, config, vconfig, conf_parser,
9081 				     named_g_aclconfctx, &nzf_num_zones));
9082 		num_zones += nzf_num_zones;
9083 
9084 		dns_view_detach(&view);
9085 	}
9086 
9087 	/*
9088 	 * If there were no explicit views then we do the default
9089 	 * view here.
9090 	 */
9091 	if (views == NULL) {
9092 		int nzf_num_zones;
9093 
9094 		CHECK(create_view(NULL, &viewlist, &view));
9095 		INSIST(view != NULL);
9096 
9097 		num_zones = count_zones(config);
9098 
9099 		CHECK(setup_newzones(view, config, NULL, conf_parser,
9100 				     named_g_aclconfctx, &nzf_num_zones));
9101 		num_zones += nzf_num_zones;
9102 
9103 		dns_view_detach(&view);
9104 	}
9105 
9106 	/*
9107 	 * Zones have been counted; set the zone manager task pool size.
9108 	 */
9109 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9110 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9111 		      "sizing zone task pool based on %d zones", num_zones);
9112 	CHECK(dns_zonemgr_setsize(named_g_server->zonemgr, num_zones));
9113 
9114 	/*
9115 	 * Configure and freeze all explicit views.  Explicit
9116 	 * views that have zones were already created at parsing
9117 	 * time, but views with no zones must be created here.
9118 	 */
9119 	for (element = cfg_list_first(views); element != NULL;
9120 	     element = cfg_list_next(element))
9121 	{
9122 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9123 
9124 		view = NULL;
9125 		CHECK(find_view(vconfig, &viewlist, &view));
9126 		CHECK(configure_view(view, &viewlist, config, vconfig,
9127 				     &cachelist, &server->kasplist, bindkeys,
9128 				     named_g_mctx, named_g_aclconfctx, true));
9129 		dns_view_freeze(view);
9130 		dns_view_detach(&view);
9131 	}
9132 
9133 	/*
9134 	 * Make sure we have a default view if and only if there
9135 	 * were no explicit views.
9136 	 */
9137 	if (views == NULL) {
9138 		view = NULL;
9139 		CHECK(find_view(NULL, &viewlist, &view));
9140 		CHECK(configure_view(view, &viewlist, config, NULL, &cachelist,
9141 				     &server->kasplist, bindkeys, named_g_mctx,
9142 				     named_g_aclconfctx, true));
9143 		dns_view_freeze(view);
9144 		dns_view_detach(&view);
9145 	}
9146 
9147 	/*
9148 	 * Create (or recreate) the built-in views.
9149 	 */
9150 	builtin_views = NULL;
9151 	RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) ==
9152 		      ISC_R_SUCCESS);
9153 	for (element = cfg_list_first(builtin_views); element != NULL;
9154 	     element = cfg_list_next(element))
9155 	{
9156 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9157 
9158 		CHECK(create_view(vconfig, &builtin_viewlist, &view));
9159 		CHECK(configure_view(view, &viewlist, config, vconfig,
9160 				     &cachelist, &server->kasplist, bindkeys,
9161 				     named_g_mctx, named_g_aclconfctx, false));
9162 		dns_view_freeze(view);
9163 		dns_view_detach(&view);
9164 		view = NULL;
9165 	}
9166 
9167 	/* Now combine the two viewlists into one */
9168 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9169 
9170 	/*
9171 	 * Commit any dns_zone_setview() calls on all zones in the new
9172 	 * view.
9173 	 */
9174 	for (view = ISC_LIST_HEAD(viewlist); view != NULL;
9175 	     view = ISC_LIST_NEXT(view, link))
9176 	{
9177 		dns_view_setviewcommit(view);
9178 	}
9179 
9180 	/* Swap our new view list with the production one. */
9181 	tmpviewlist = server->viewlist;
9182 	server->viewlist = viewlist;
9183 	viewlist = tmpviewlist;
9184 
9185 	/* Make the view list available to each of the views */
9186 	view = ISC_LIST_HEAD(server->viewlist);
9187 	while (view != NULL) {
9188 		view->viewlist = &server->viewlist;
9189 		view = ISC_LIST_NEXT(view, link);
9190 	}
9191 
9192 	/* Swap our new cache list with the production one. */
9193 	tmpcachelist = server->cachelist;
9194 	server->cachelist = cachelist;
9195 	cachelist = tmpcachelist;
9196 
9197 	/* Load the TKEY information from the configuration. */
9198 	if (options != NULL) {
9199 		dns_tkeyctx_t *t = NULL;
9200 		CHECKM(named_tkeyctx_fromconfig(options, named_g_mctx, &t),
9201 		       "configuring TKEY");
9202 		if (server->sctx->tkeyctx != NULL) {
9203 			dns_tkeyctx_destroy(&server->sctx->tkeyctx);
9204 		}
9205 		server->sctx->tkeyctx = t;
9206 	}
9207 
9208 	/*
9209 	 * Bind the control port(s).
9210 	 */
9211 	CHECKM(named_controls_configure(named_g_server->controls, config,
9212 					named_g_aclconfctx),
9213 	       "binding control channel(s)");
9214 
9215 #ifdef HAVE_LMDB
9216 	/*
9217 	 * If we're using LMDB, we may have created newzones databases
9218 	 * as root, making it impossible to reopen them later after
9219 	 * switching to a new userid. We close them now, and reopen
9220 	 * after relinquishing privileges them.
9221 	 */
9222 	if (first_time) {
9223 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9224 		     view = ISC_LIST_NEXT(view, link))
9225 		{
9226 			nzd_env_close(view);
9227 		}
9228 	}
9229 #endif /* HAVE_LMDB */
9230 
9231 	/*
9232 	 * Relinquish root privileges.
9233 	 */
9234 	if (first_time) {
9235 		named_os_changeuser();
9236 	}
9237 
9238 #if 0
9239 	/*
9240 	 * Check that the working directory is writable.
9241 	 */
9242 	if (!isc_file_isdirwritable(".")) {
9243 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9244 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9245 			      "the working directory is not writable");
9246 		result = ISC_R_NOPERM;
9247 		goto cleanup;
9248 	}
9249 #endif
9250 
9251 #ifdef HAVE_LMDB
9252 	/*
9253 	 * Reopen NZD databases.
9254 	 */
9255 	if (first_time) {
9256 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9257 		     view = ISC_LIST_NEXT(view, link))
9258 		{
9259 			nzd_env_reopen(view);
9260 		}
9261 	}
9262 #endif /* HAVE_LMDB */
9263 
9264 	/*
9265 	 * Configure the logging system.
9266 	 *
9267 	 * Do this after changing UID to make sure that any log
9268 	 * files specified in named.conf get created by the
9269 	 * unprivileged user, not root.
9270 	 */
9271 	if (named_g_logstderr) {
9272 		const cfg_obj_t *logobj = NULL;
9273 
9274 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9275 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9276 			      "not using config file logging "
9277 			      "statement for logging due to "
9278 			      "-g option");
9279 
9280 		(void)cfg_map_get(config, "logging", &logobj);
9281 		if (logobj != NULL) {
9282 			result = named_logconfig(NULL, logobj);
9283 			if (result != ISC_R_SUCCESS) {
9284 				isc_log_write(
9285 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9286 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9287 					"checking logging configuration "
9288 					"failed: %s",
9289 					isc_result_totext(result));
9290 				goto cleanup;
9291 			}
9292 		}
9293 	} else {
9294 		const cfg_obj_t *logobj = NULL;
9295 
9296 		isc_logconfig_create(named_g_lctx, &logc);
9297 
9298 		logobj = NULL;
9299 		(void)cfg_map_get(config, "logging", &logobj);
9300 		if (logobj != NULL) {
9301 			CHECKM(named_logconfig(logc, logobj),
9302 			       "configuring logging");
9303 		} else {
9304 			named_log_setdefaultchannels(logc);
9305 			CHECKM(named_log_setunmatchedcategory(logc),
9306 			       "setting up default 'category unmatched'");
9307 			CHECKM(named_log_setdefaultcategory(logc),
9308 			       "setting up default 'category default'");
9309 		}
9310 
9311 		isc_logconfig_use(named_g_lctx, logc);
9312 		logc = NULL;
9313 
9314 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9315 			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9316 			      "now using logging configuration from "
9317 			      "config file");
9318 	}
9319 
9320 	/*
9321 	 * Set the default value of the query logging flag depending
9322 	 * whether a "queries" category has been defined.  This is
9323 	 * a disgusting hack, but we need to do this for BIND 8
9324 	 * compatibility.
9325 	 */
9326 	if (first_time) {
9327 		const cfg_obj_t *logobj = NULL;
9328 		const cfg_obj_t *categories = NULL;
9329 
9330 		obj = NULL;
9331 		if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
9332 			ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES,
9333 					    cfg_obj_asboolean(obj));
9334 		} else {
9335 			(void)cfg_map_get(config, "logging", &logobj);
9336 			if (logobj != NULL) {
9337 				(void)cfg_map_get(logobj, "category",
9338 						  &categories);
9339 			}
9340 			if (categories != NULL) {
9341 				for (element = cfg_list_first(categories);
9342 				     element != NULL;
9343 				     element = cfg_list_next(element))
9344 				{
9345 					const cfg_obj_t *catobj;
9346 					const char *str;
9347 
9348 					obj = cfg_listelt_value(element);
9349 					catobj = cfg_tuple_get(obj, "name");
9350 					str = cfg_obj_asstring(catobj);
9351 					if (strcasecmp(str, "queries") == 0) {
9352 						ns_server_setoption(
9353 							server->sctx,
9354 							NS_SERVER_LOGQUERIES,
9355 							true);
9356 					}
9357 				}
9358 			}
9359 		}
9360 	}
9361 
9362 	obj = NULL;
9363 	if (options != NULL &&
9364 	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
9365 	{
9366 		named_g_memstatistics = cfg_obj_asboolean(obj);
9367 	} else {
9368 		named_g_memstatistics =
9369 			((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
9370 	}
9371 
9372 	obj = NULL;
9373 	if (named_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
9374 	{
9375 		named_main_setmemstats(cfg_obj_asstring(obj));
9376 	} else if (named_g_memstatistics) {
9377 		named_main_setmemstats("named.memstats");
9378 	} else {
9379 		named_main_setmemstats(NULL);
9380 	}
9381 
9382 	obj = NULL;
9383 	result = named_config_get(maps, "statistics-file", &obj);
9384 	INSIST(result == ISC_R_SUCCESS);
9385 	CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
9386 	       "strdup");
9387 
9388 	obj = NULL;
9389 	result = named_config_get(maps, "dump-file", &obj);
9390 	INSIST(result == ISC_R_SUCCESS);
9391 	CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
9392 	       "strdup");
9393 
9394 	obj = NULL;
9395 	result = named_config_get(maps, "secroots-file", &obj);
9396 	INSIST(result == ISC_R_SUCCESS);
9397 	CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
9398 	       "strdup");
9399 
9400 	obj = NULL;
9401 	result = named_config_get(maps, "recursing-file", &obj);
9402 	INSIST(result == ISC_R_SUCCESS);
9403 	CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
9404 	       "strdup");
9405 
9406 	obj = NULL;
9407 	result = named_config_get(maps, "version", &obj);
9408 	if (result == ISC_R_SUCCESS) {
9409 		CHECKM(setoptstring(server, &server->version, obj), "strdup");
9410 		server->version_set = true;
9411 	} else {
9412 		server->version_set = false;
9413 	}
9414 
9415 	obj = NULL;
9416 	result = named_config_get(maps, "hostname", &obj);
9417 	if (result == ISC_R_SUCCESS) {
9418 		CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
9419 		server->hostname_set = true;
9420 	} else {
9421 		server->hostname_set = false;
9422 	}
9423 
9424 	obj = NULL;
9425 	result = named_config_get(maps, "server-id", &obj);
9426 	server->sctx->gethostname = NULL;
9427 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
9428 		/* The parser translates "hostname" to true */
9429 		server->sctx->gethostname = named_os_gethostname;
9430 		result = ns_server_setserverid(server->sctx, NULL);
9431 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
9432 		/* Found a quoted string */
9433 		result = ns_server_setserverid(server->sctx,
9434 					       cfg_obj_asstring(obj));
9435 	} else {
9436 		result = ns_server_setserverid(server->sctx, NULL);
9437 	}
9438 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9439 
9440 	obj = NULL;
9441 	result = named_config_get(maps, "flush-zones-on-shutdown", &obj);
9442 	if (result == ISC_R_SUCCESS) {
9443 		server->flushonshutdown = cfg_obj_asboolean(obj);
9444 	} else {
9445 		server->flushonshutdown = false;
9446 	}
9447 
9448 	obj = NULL;
9449 	result = named_config_get(maps, "answer-cookie", &obj);
9450 	INSIST(result == ISC_R_SUCCESS);
9451 	server->sctx->answercookie = cfg_obj_asboolean(obj);
9452 
9453 	obj = NULL;
9454 	result = named_config_get(maps, "cookie-algorithm", &obj);
9455 	INSIST(result == ISC_R_SUCCESS);
9456 	if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
9457 		server->sctx->cookiealg = ns_cookiealg_siphash24;
9458 	} else if (strcasecmp(cfg_obj_asstring(obj), "aes") == 0) {
9459 		server->sctx->cookiealg = ns_cookiealg_aes;
9460 	} else {
9461 		UNREACHABLE();
9462 	}
9463 
9464 	obj = NULL;
9465 	result = named_config_get(maps, "cookie-secret", &obj);
9466 	if (result == ISC_R_SUCCESS) {
9467 		const char *str;
9468 		bool first = true;
9469 		isc_buffer_t b;
9470 		unsigned int usedlength;
9471 		unsigned int expectedlength;
9472 
9473 		for (element = cfg_list_first(obj); element != NULL;
9474 		     element = cfg_list_next(element))
9475 		{
9476 			obj = cfg_listelt_value(element);
9477 			str = cfg_obj_asstring(obj);
9478 
9479 			if (first) {
9480 				memset(server->sctx->secret, 0,
9481 				       sizeof(server->sctx->secret));
9482 				isc_buffer_init(&b, server->sctx->secret,
9483 						sizeof(server->sctx->secret));
9484 				result = isc_hex_decodestring(str, &b);
9485 				if (result != ISC_R_SUCCESS &&
9486 				    result != ISC_R_NOSPACE)
9487 				{
9488 					goto cleanup;
9489 				}
9490 				first = false;
9491 			} else {
9492 				altsecret = isc_mem_get(server->sctx->mctx,
9493 							sizeof(*altsecret));
9494 				isc_buffer_init(&b, altsecret->secret,
9495 						sizeof(altsecret->secret));
9496 				result = isc_hex_decodestring(str, &b);
9497 				if (result != ISC_R_SUCCESS &&
9498 				    result != ISC_R_NOSPACE)
9499 				{
9500 					isc_mem_put(server->sctx->mctx,
9501 						    altsecret,
9502 						    sizeof(*altsecret));
9503 					goto cleanup;
9504 				}
9505 				ISC_LIST_INITANDAPPEND(altsecrets, altsecret,
9506 						       link);
9507 			}
9508 
9509 			usedlength = isc_buffer_usedlength(&b);
9510 			switch (server->sctx->cookiealg) {
9511 			case ns_cookiealg_siphash24:
9512 				expectedlength = ISC_SIPHASH24_KEY_LENGTH;
9513 				if (usedlength != expectedlength) {
9514 					CHECKM(ISC_R_RANGE, "SipHash-2-4 "
9515 							    "cookie-secret "
9516 							    "must be 128 bits");
9517 				}
9518 				break;
9519 			case ns_cookiealg_aes:
9520 				expectedlength = ISC_AES128_KEYLENGTH;
9521 				if (usedlength != expectedlength) {
9522 					CHECKM(ISC_R_RANGE, "AES cookie-secret "
9523 							    "must be 128 bits");
9524 				}
9525 				break;
9526 			}
9527 		}
9528 	} else {
9529 		isc_nonce_buf(server->sctx->secret,
9530 			      sizeof(server->sctx->secret));
9531 	}
9532 
9533 	/*
9534 	 * Swap altsecrets lists.
9535 	 */
9536 	tmpaltsecrets = server->sctx->altsecrets;
9537 	server->sctx->altsecrets = altsecrets;
9538 	altsecrets = tmpaltsecrets;
9539 
9540 	(void)named_server_loadnta(server);
9541 
9542 #ifdef USE_DNSRPS
9543 	/*
9544 	 * Start and connect to the DNS Response Policy Service
9545 	 * daemon, dnsrpzd, for each view that uses DNSRPS.
9546 	 */
9547 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9548 	     view = ISC_LIST_NEXT(view, link))
9549 	{
9550 		result = dns_dnsrps_connect(view->rpzs);
9551 		if (result != ISC_R_SUCCESS) {
9552 			view = NULL;
9553 			goto cleanup;
9554 		}
9555 	}
9556 #endif /* ifdef USE_DNSRPS */
9557 
9558 	result = ISC_R_SUCCESS;
9559 
9560 cleanup:
9561 	if (logc != NULL) {
9562 		isc_logconfig_destroy(&logc);
9563 	}
9564 
9565 	if (v4portset != NULL) {
9566 		isc_portset_destroy(named_g_mctx, &v4portset);
9567 	}
9568 
9569 	if (v6portset != NULL) {
9570 		isc_portset_destroy(named_g_mctx, &v6portset);
9571 	}
9572 
9573 	if (conf_parser != NULL) {
9574 		if (config != NULL) {
9575 			cfg_obj_destroy(conf_parser, &config);
9576 		}
9577 		cfg_parser_destroy(&conf_parser);
9578 	}
9579 
9580 	if (bindkeys_parser != NULL) {
9581 		if (bindkeys != NULL) {
9582 			cfg_obj_destroy(bindkeys_parser, &bindkeys);
9583 		}
9584 		cfg_parser_destroy(&bindkeys_parser);
9585 	}
9586 
9587 	if (view != NULL) {
9588 		dns_view_detach(&view);
9589 	}
9590 
9591 	if (kasp != NULL) {
9592 		dns_kasp_detach(&kasp);
9593 	}
9594 
9595 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9596 
9597 	/*
9598 	 * This cleans up either the old production view list
9599 	 * or our temporary list depending on whether they
9600 	 * were swapped above or not.
9601 	 */
9602 	for (view = ISC_LIST_HEAD(viewlist); view != NULL; view = view_next) {
9603 		view_next = ISC_LIST_NEXT(view, link);
9604 		ISC_LIST_UNLINK(viewlist, view, link);
9605 		if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
9606 		{
9607 			dns_view_setviewrevert(view);
9608 			(void)dns_zt_apply(view->zonetable, isc_rwlocktype_read,
9609 					   false, NULL, removed, view);
9610 		}
9611 		dns_view_detach(&view);
9612 	}
9613 
9614 	/*
9615 	 * Same cleanup for kasp list.
9616 	 */
9617 	for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
9618 		kasp_next = ISC_LIST_NEXT(kasp, link);
9619 		ISC_LIST_UNLINK(kasplist, kasp, link);
9620 		dns_kasp_detach(&kasp);
9621 	}
9622 
9623 	/* Same cleanup for cache list. */
9624 	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
9625 		ISC_LIST_UNLINK(cachelist, nsc, link);
9626 		dns_cache_detach(&nsc->cache);
9627 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9628 	}
9629 
9630 	/* Cleanup for altsecrets list. */
9631 	while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) {
9632 		ISC_LIST_UNLINK(altsecrets, altsecret, link);
9633 		isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret));
9634 	}
9635 
9636 	/*
9637 	 * Record the time of most recent configuration
9638 	 */
9639 	tresult = isc_time_now(&named_g_configtime);
9640 	if (tresult != ISC_R_SUCCESS) {
9641 		named_main_earlyfatal("isc_time_now() failed: %s",
9642 				      isc_result_totext(result));
9643 	}
9644 
9645 	/* Relinquish exclusive access to configuration data. */
9646 	if (exclusive) {
9647 		isc_task_endexclusive(server->task);
9648 	}
9649 
9650 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9651 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9652 		      "load_configuration: %s", isc_result_totext(result));
9653 
9654 	return (result);
9655 }
9656 
9657 static isc_result_t
view_loaded(void * arg)9658 view_loaded(void *arg) {
9659 	isc_result_t result;
9660 	ns_zoneload_t *zl = (ns_zoneload_t *)arg;
9661 
9662 	/*
9663 	 * Force zone maintenance.  Do this after loading
9664 	 * so that we know when we need to force AXFR of
9665 	 * slave zones whose master files are missing.
9666 	 *
9667 	 * We use the zoneload reference counter to let us
9668 	 * know when all views are finished.
9669 	 */
9670 	if (isc_refcount_decrement(&zl->refs) == 1) {
9671 		named_server_t *server = zl->server;
9672 		bool reconfig = zl->reconfig;
9673 		dns_view_t *view = NULL;
9674 
9675 		isc_refcount_destroy(&zl->refs);
9676 		isc_mem_put(server->mctx, zl, sizeof(*zl));
9677 
9678 		/*
9679 		 * To maintain compatibility with log parsing tools that might
9680 		 * be looking for this string after "rndc reconfig", we keep it
9681 		 * as it is
9682 		 */
9683 		if (reconfig) {
9684 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9685 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9686 				      "any newly configured zones are now "
9687 				      "loaded");
9688 		} else {
9689 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9690 				      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9691 				      "all zones loaded");
9692 		}
9693 
9694 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9695 		     view = ISC_LIST_NEXT(view, link))
9696 		{
9697 			if (view->managed_keys != NULL) {
9698 				result = dns_zone_synckeyzone(
9699 					view->managed_keys);
9700 				if (result != ISC_R_SUCCESS) {
9701 					isc_log_write(
9702 						named_g_lctx,
9703 						DNS_LOGCATEGORY_DNSSEC,
9704 						DNS_LOGMODULE_DNSSEC,
9705 						ISC_LOG_ERROR,
9706 						"failed to initialize "
9707 						"managed-keys for view %s "
9708 						"(%s): DNSSEC validation is "
9709 						"at risk",
9710 						view->name,
9711 						isc_result_totext(result));
9712 				}
9713 			}
9714 		}
9715 
9716 		CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
9717 			   "forcing zone maintenance");
9718 
9719 		named_os_started();
9720 
9721 #ifdef HAVE_FIPS_MODE
9722 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9723 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9724 			      "FIPS mode is %s",
9725 			      FIPS_mode() ? "enabled" : "disabled");
9726 #endif /* ifdef HAVE_FIPS_MODE */
9727 		atomic_store(&server->reload_status, NAMED_RELOAD_DONE);
9728 
9729 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9730 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9731 			      "running");
9732 	}
9733 
9734 	return (ISC_R_SUCCESS);
9735 }
9736 
9737 static isc_result_t
load_zones(named_server_t * server,bool init,bool reconfig)9738 load_zones(named_server_t *server, bool init, bool reconfig) {
9739 	isc_result_t result;
9740 	isc_taskmgr_t *taskmgr = dns_zonemgr_gettaskmgr(server->zonemgr);
9741 	dns_view_t *view = NULL;
9742 	ns_zoneload_t *zl = NULL;
9743 
9744 	zl = isc_mem_get(server->mctx, sizeof(*zl));
9745 	zl->server = server;
9746 	zl->reconfig = reconfig;
9747 
9748 	result = isc_task_beginexclusive(server->task);
9749 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9750 
9751 	isc_refcount_init(&zl->refs, 1);
9752 
9753 	/*
9754 	 * Schedule zones to be loaded from disk.
9755 	 */
9756 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9757 	     view = ISC_LIST_NEXT(view, link))
9758 	{
9759 		if (view->managed_keys != NULL) {
9760 			result = dns_zone_load(view->managed_keys, false);
9761 			if (result != ISC_R_SUCCESS &&
9762 			    result != DNS_R_UPTODATE &&
9763 			    result != DNS_R_CONTINUE)
9764 			{
9765 				goto cleanup;
9766 			}
9767 		}
9768 		if (view->redirect != NULL) {
9769 			result = dns_zone_load(view->redirect, false);
9770 			if (result != ISC_R_SUCCESS &&
9771 			    result != DNS_R_UPTODATE &&
9772 			    result != DNS_R_CONTINUE)
9773 			{
9774 				goto cleanup;
9775 			}
9776 		}
9777 
9778 		/*
9779 		 * 'dns_view_asyncload' calls view_loaded if there are no
9780 		 * zones.
9781 		 */
9782 		isc_refcount_increment(&zl->refs);
9783 		result = dns_view_asyncload(view, reconfig, view_loaded, zl);
9784 		if (result != ISC_R_SUCCESS) {
9785 			isc_refcount_decrement1(&zl->refs);
9786 			goto cleanup;
9787 		}
9788 	}
9789 
9790 cleanup:
9791 	if (isc_refcount_decrement(&zl->refs) == 1) {
9792 		isc_refcount_destroy(&zl->refs);
9793 		isc_mem_put(server->mctx, zl, sizeof(*zl));
9794 	}
9795 
9796 	if (init) {
9797 		/*
9798 		 * If we're setting up the server for the first time, set
9799 		 * the task manager into privileged mode; this ensures
9800 		 * that no other tasks will begin to run until after zone
9801 		 * loading is complete. We won't return from exclusive mode
9802 		 * until the loading is finished; we can then drop out of
9803 		 * privileged mode.
9804 		 *
9805 		 * We do *not* want to do this in the case of reload or
9806 		 * reconfig, as loading a large zone could cause the server
9807 		 * to be inactive for too long a time.
9808 		 */
9809 		isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
9810 		isc_task_endexclusive(server->task);
9811 		isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal);
9812 	} else {
9813 		isc_task_endexclusive(server->task);
9814 	}
9815 
9816 	return (result);
9817 }
9818 
9819 static void
run_server(isc_task_t * task,isc_event_t * event)9820 run_server(isc_task_t *task, isc_event_t *event) {
9821 	isc_result_t result;
9822 	named_server_t *server = (named_server_t *)event->ev_arg;
9823 	dns_geoip_databases_t *geoip;
9824 
9825 	INSIST(task == server->task);
9826 
9827 	isc_event_free(&event);
9828 
9829 	CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, &named_g_dispatchmgr),
9830 		   "creating dispatch manager");
9831 
9832 	dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
9833 
9834 #if defined(HAVE_GEOIP2)
9835 	geoip = named_g_geoip;
9836 #else  /* if defined(HAVE_GEOIP2) */
9837 	geoip = NULL;
9838 #endif /* if defined(HAVE_GEOIP2) */
9839 
9840 	CHECKFATAL(ns_interfacemgr_create(
9841 			   named_g_mctx, server->sctx, named_g_taskmgr,
9842 			   named_g_timermgr, named_g_socketmgr, named_g_nm,
9843 			   named_g_dispatchmgr, server->task, named_g_udpdisp,
9844 			   geoip, named_g_cpus, &server->interfacemgr),
9845 		   "creating interface manager");
9846 
9847 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9848 				    NULL, NULL, server->task,
9849 				    interface_timer_tick, server,
9850 				    &server->interface_timer),
9851 		   "creating interface timer");
9852 
9853 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9854 				    NULL, NULL, server->task,
9855 				    heartbeat_timer_tick, server,
9856 				    &server->heartbeat_timer),
9857 		   "creating heartbeat timer");
9858 
9859 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9860 				    NULL, NULL, server->task, tat_timer_tick,
9861 				    server, &server->tat_timer),
9862 		   "creating trust anchor telemetry timer");
9863 
9864 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9865 				    NULL, NULL, server->task, pps_timer_tick,
9866 				    server, &server->pps_timer),
9867 		   "creating pps timer");
9868 
9869 	CHECKFATAL(
9870 		cfg_parser_create(named_g_mctx, named_g_lctx, &named_g_parser),
9871 		"creating default configuration parser");
9872 
9873 	CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx,
9874 				     &named_g_addparser),
9875 		   "creating additional configuration parser");
9876 
9877 	CHECKFATAL(load_configuration(named_g_conffile, server, true),
9878 		   "loading configuration");
9879 
9880 	CHECKFATAL(load_zones(server, true, false), "loading zones");
9881 #ifdef ENABLE_AFL
9882 	named_g_run_done = true;
9883 #endif /* ifdef ENABLE_AFL */
9884 }
9885 
9886 void
named_server_flushonshutdown(named_server_t * server,bool flush)9887 named_server_flushonshutdown(named_server_t *server, bool flush) {
9888 	REQUIRE(NAMED_SERVER_VALID(server));
9889 
9890 	server->flushonshutdown = flush;
9891 }
9892 
9893 static void
shutdown_server(isc_task_t * task,isc_event_t * event)9894 shutdown_server(isc_task_t *task, isc_event_t *event) {
9895 	isc_result_t result;
9896 	dns_view_t *view, *view_next = NULL;
9897 	dns_kasp_t *kasp, *kasp_next = NULL;
9898 	named_server_t *server = (named_server_t *)event->ev_arg;
9899 	bool flush = server->flushonshutdown;
9900 	named_cache_t *nsc;
9901 
9902 	UNUSED(task);
9903 	INSIST(task == server->task);
9904 
9905 	/*
9906 	 * We need to shutdown the interface before going
9907 	 * exclusive (which would pause the netmgr).
9908 	 */
9909 	ns_interfacemgr_shutdown(server->interfacemgr);
9910 
9911 	result = isc_task_beginexclusive(server->task);
9912 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9913 
9914 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9915 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "shutting down%s",
9916 		      flush ? ": flushing changes" : "");
9917 
9918 	named_statschannels_shutdown(server);
9919 	named_controls_shutdown(server->controls);
9920 	end_reserved_dispatches(server, true);
9921 	cleanup_session_key(server, server->mctx);
9922 
9923 	if (named_g_aclconfctx != NULL) {
9924 		cfg_aclconfctx_detach(&named_g_aclconfctx);
9925 	}
9926 
9927 	cfg_obj_destroy(named_g_parser, &named_g_config);
9928 	cfg_parser_destroy(&named_g_parser);
9929 	cfg_parser_destroy(&named_g_addparser);
9930 
9931 	(void)named_server_saventa(server);
9932 
9933 	for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL;
9934 	     kasp = kasp_next)
9935 	{
9936 		kasp_next = ISC_LIST_NEXT(kasp, link);
9937 		ISC_LIST_UNLINK(server->kasplist, kasp, link);
9938 		dns_kasp_detach(&kasp);
9939 	}
9940 
9941 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9942 	     view = view_next)
9943 	{
9944 		view_next = ISC_LIST_NEXT(view, link);
9945 		ISC_LIST_UNLINK(server->viewlist, view, link);
9946 		if (flush) {
9947 			dns_view_flushanddetach(&view);
9948 		} else {
9949 			dns_view_detach(&view);
9950 		}
9951 	}
9952 
9953 	/*
9954 	 * Shut down all dyndb instances.
9955 	 */
9956 	dns_dyndb_cleanup(true);
9957 
9958 	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
9959 		ISC_LIST_UNLINK(server->cachelist, nsc, link);
9960 		dns_cache_detach(&nsc->cache);
9961 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9962 	}
9963 
9964 	isc_timer_destroy(&server->interface_timer);
9965 	isc_timer_destroy(&server->heartbeat_timer);
9966 	isc_timer_destroy(&server->pps_timer);
9967 	isc_timer_destroy(&server->tat_timer);
9968 
9969 	ns_interfacemgr_detach(&server->interfacemgr);
9970 
9971 	dns_dispatchmgr_destroy(&named_g_dispatchmgr);
9972 
9973 	dns_zonemgr_shutdown(server->zonemgr);
9974 
9975 	if (named_g_sessionkey != NULL) {
9976 		dns_tsigkey_detach(&named_g_sessionkey);
9977 		dns_name_free(&named_g_sessionkeyname, server->mctx);
9978 	}
9979 #if defined(HAVE_GEOIP2)
9980 	named_geoip_shutdown();
9981 #endif /* HAVE_GEOIP2 */
9982 
9983 	dns_db_detach(&server->in_roothints);
9984 
9985 	isc_task_endexclusive(server->task);
9986 
9987 	isc_task_detach(&server->task);
9988 
9989 	isc_event_free(&event);
9990 }
9991 
9992 /*%
9993  * Find a view that matches the source and destination addresses of a query.
9994  */
9995 static isc_result_t
get_matching_view(isc_netaddr_t * srcaddr,isc_netaddr_t * destaddr,dns_message_t * message,dns_aclenv_t * env,isc_result_t * sigresult,dns_view_t ** viewp)9996 get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
9997 		  dns_message_t *message, dns_aclenv_t *env,
9998 		  isc_result_t *sigresult, dns_view_t **viewp) {
9999 	dns_view_t *view;
10000 
10001 	REQUIRE(message != NULL);
10002 	REQUIRE(sigresult != NULL);
10003 	REQUIRE(viewp != NULL && *viewp == NULL);
10004 
10005 	for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
10006 	     view = ISC_LIST_NEXT(view, link))
10007 	{
10008 		if (message->rdclass == view->rdclass ||
10009 		    message->rdclass == dns_rdataclass_any)
10010 		{
10011 			const dns_name_t *tsig = NULL;
10012 
10013 			*sigresult = dns_message_rechecksig(message, view);
10014 			if (*sigresult == ISC_R_SUCCESS) {
10015 				dns_tsigkey_t *tsigkey;
10016 
10017 				tsigkey = message->tsigkey;
10018 				tsig = dns_tsigkey_identity(tsigkey);
10019 			}
10020 
10021 			if (dns_acl_allowed(srcaddr, tsig, view->matchclients,
10022 					    env) &&
10023 			    dns_acl_allowed(destaddr, tsig,
10024 					    view->matchdestinations, env) &&
10025 			    !(view->matchrecursiveonly &&
10026 			      (message->flags & DNS_MESSAGEFLAG_RD) == 0))
10027 			{
10028 				dns_view_attach(view, viewp);
10029 				return (ISC_R_SUCCESS);
10030 			}
10031 		}
10032 	}
10033 
10034 	return (ISC_R_NOTFOUND);
10035 }
10036 
10037 void
named_server_create(isc_mem_t * mctx,named_server_t ** serverp)10038 named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
10039 	isc_result_t result;
10040 	named_server_t *server = isc_mem_get(mctx, sizeof(*server));
10041 
10042 	*server = (named_server_t){
10043 		.mctx = mctx,
10044 		.statsfile = isc_mem_strdup(mctx, "named.stats"),
10045 		.bindkeysfile = isc_mem_strdup(mctx, named_g_defaultbindkeys),
10046 		.dumpfile = isc_mem_strdup(mctx, "named_dump.db"),
10047 		.secrootsfile = isc_mem_strdup(mctx, "named.secroots"),
10048 		.recfile = isc_mem_strdup(mctx, "named.recursing"),
10049 	};
10050 
10051 #ifdef USE_DNSRPS
10052 	CHECKFATAL(dns_dnsrps_server_create(), "initializing RPZ service "
10053 					       "interface");
10054 #endif /* ifdef USE_DNSRPS */
10055 
10056 	/* Initialize server data structures. */
10057 	ISC_LIST_INIT(server->kasplist);
10058 	ISC_LIST_INIT(server->viewlist);
10059 
10060 	/* Must be first. */
10061 	CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine), "initializing "
10062 							       "DST");
10063 
10064 	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
10065 				     &server->in_roothints),
10066 		   "setting up root hints");
10067 
10068 	isc_mutex_init(&server->reload_event_lock);
10069 
10070 	server->reload_event = isc_event_allocate(
10071 		named_g_mctx, server, NAMED_EVENT_RELOAD, named_server_reload,
10072 		server, sizeof(isc_event_t));
10073 	CHECKFATAL(server->reload_event == NULL ? ISC_R_NOMEMORY
10074 						: ISC_R_SUCCESS,
10075 		   "allocating reload event");
10076 	atomic_init(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10077 
10078 	/*
10079 	 * Setup the server task, which is responsible for coordinating
10080 	 * startup and shutdown of the server, as well as all exclusive
10081 	 * tasks.
10082 	 */
10083 	CHECKFATAL(isc_task_create_bound(named_g_taskmgr, 0, &server->task, 0),
10084 		   "creating server task");
10085 	isc_task_setname(server->task, "server", server);
10086 	isc_taskmgr_setexcltask(named_g_taskmgr, server->task);
10087 
10088 	CHECKFATAL(ns_server_create(mctx, get_matching_view, &server->sctx),
10089 		   "creating server context");
10090 
10091 #if defined(HAVE_GEOIP2)
10092 	/*
10093 	 * GeoIP must be initialized before the interface
10094 	 * manager (which includes the ACL environment)
10095 	 * is created.
10096 	 */
10097 	named_geoip_init();
10098 #endif /* HAVE_GEOIP2 */
10099 
10100 #ifdef ENABLE_AFL
10101 	server->sctx->fuzztype = named_g_fuzz_type;
10102 	server->sctx->fuzznotify = named_fuzz_notify;
10103 #endif /* ifdef ENABLE_AFL */
10104 
10105 	CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
10106 		   "isc_task_onshutdown");
10107 	CHECKFATAL(
10108 		isc_app_onrun(named_g_mctx, server->task, run_server, server),
10109 		"isc_app_onrun");
10110 
10111 	CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr,
10112 				      named_g_timermgr, named_g_socketmgr,
10113 				      &server->zonemgr),
10114 		   "dns_zonemgr_create");
10115 	CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_"
10116 							       "setsize");
10117 
10118 	CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
10119 				    isc_sockstatscounter_max),
10120 		   "isc_stats_create");
10121 	isc_socketmgr_setstats(named_g_socketmgr, server->sockstats);
10122 	isc_nm_setstats(named_g_nm, server->sockstats);
10123 
10124 	CHECKFATAL(isc_stats_create(named_g_mctx, &server->zonestats,
10125 				    dns_zonestatscounter_max),
10126 		   "dns_stats_create (zone)");
10127 
10128 	CHECKFATAL(isc_stats_create(named_g_mctx, &server->resolverstats,
10129 				    dns_resstatscounter_max),
10130 		   "dns_stats_create (resolver)");
10131 
10132 	CHECKFATAL(named_controls_create(server, &server->controls),
10133 		   "named_controls_create");
10134 
10135 	ISC_LIST_INIT(server->dispatches);
10136 
10137 	ISC_LIST_INIT(server->statschannels);
10138 
10139 	ISC_LIST_INIT(server->cachelist);
10140 
10141 	server->magic = NAMED_SERVER_MAGIC;
10142 	*serverp = server;
10143 }
10144 
10145 void
named_server_destroy(named_server_t ** serverp)10146 named_server_destroy(named_server_t **serverp) {
10147 	named_server_t *server = *serverp;
10148 	REQUIRE(NAMED_SERVER_VALID(server));
10149 
10150 #ifdef HAVE_DNSTAP
10151 	if (server->dtenv != NULL) {
10152 		dns_dt_detach(&server->dtenv);
10153 	}
10154 #endif /* HAVE_DNSTAP */
10155 
10156 #ifdef USE_DNSRPS
10157 	dns_dnsrps_server_destroy();
10158 #endif /* ifdef USE_DNSRPS */
10159 
10160 	named_controls_destroy(&server->controls);
10161 
10162 	isc_stats_detach(&server->zonestats);
10163 	isc_stats_detach(&server->sockstats);
10164 	isc_stats_detach(&server->resolverstats);
10165 
10166 	if (server->sctx != NULL) {
10167 		ns_server_detach(&server->sctx);
10168 	}
10169 
10170 	isc_mem_free(server->mctx, server->statsfile);
10171 	isc_mem_free(server->mctx, server->bindkeysfile);
10172 	isc_mem_free(server->mctx, server->dumpfile);
10173 	isc_mem_free(server->mctx, server->secrootsfile);
10174 	isc_mem_free(server->mctx, server->recfile);
10175 
10176 	if (server->version != NULL) {
10177 		isc_mem_free(server->mctx, server->version);
10178 	}
10179 	if (server->hostname != NULL) {
10180 		isc_mem_free(server->mctx, server->hostname);
10181 	}
10182 	if (server->lockfile != NULL) {
10183 		isc_mem_free(server->mctx, server->lockfile);
10184 	}
10185 
10186 	if (server->zonemgr != NULL) {
10187 		dns_zonemgr_detach(&server->zonemgr);
10188 	}
10189 
10190 	dst_lib_destroy();
10191 
10192 	isc_event_free(&server->reload_event);
10193 	isc_mutex_destroy(&server->reload_event_lock);
10194 
10195 	INSIST(ISC_LIST_EMPTY(server->kasplist));
10196 	INSIST(ISC_LIST_EMPTY(server->viewlist));
10197 	INSIST(ISC_LIST_EMPTY(server->cachelist));
10198 
10199 	server->magic = 0;
10200 	isc_mem_put(server->mctx, server, sizeof(*server));
10201 	*serverp = NULL;
10202 }
10203 
10204 static void
fatal(named_server_t * server,const char * msg,isc_result_t result)10205 fatal(named_server_t *server, const char *msg, isc_result_t result) {
10206 	if (server != NULL && server->task != NULL) {
10207 		/*
10208 		 * Prevent races between the OpenSSL on_exit registered
10209 		 * function and any other OpenSSL calls from other tasks
10210 		 * by requesting exclusive access to the task manager.
10211 		 */
10212 		(void)isc_task_beginexclusive(server->task);
10213 	}
10214 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10215 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, "%s: %s", msg,
10216 		      isc_result_totext(result));
10217 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10218 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
10219 		      "exiting (due to fatal error)");
10220 	named_os_shutdown();
10221 	exit(1);
10222 }
10223 
10224 static void
start_reserved_dispatches(named_server_t * server)10225 start_reserved_dispatches(named_server_t *server) {
10226 	REQUIRE(NAMED_SERVER_VALID(server));
10227 
10228 	server->dispatchgen++;
10229 }
10230 
10231 static void
end_reserved_dispatches(named_server_t * server,bool all)10232 end_reserved_dispatches(named_server_t *server, bool all) {
10233 	named_dispatch_t *dispatch, *nextdispatch;
10234 
10235 	REQUIRE(NAMED_SERVER_VALID(server));
10236 
10237 	for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10238 	     dispatch = nextdispatch)
10239 	{
10240 		nextdispatch = ISC_LIST_NEXT(dispatch, link);
10241 		if (!all && server->dispatchgen == dispatch->dispatchgen) {
10242 			continue;
10243 		}
10244 		ISC_LIST_UNLINK(server->dispatches, dispatch, link);
10245 		dns_dispatch_detach(&dispatch->dispatch);
10246 		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10247 	}
10248 }
10249 
10250 void
named_add_reserved_dispatch(named_server_t * server,const isc_sockaddr_t * addr)10251 named_add_reserved_dispatch(named_server_t *server,
10252 			    const isc_sockaddr_t *addr) {
10253 	named_dispatch_t *dispatch;
10254 	in_port_t port;
10255 	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
10256 	isc_result_t result;
10257 	unsigned int attrs, attrmask;
10258 
10259 	REQUIRE(NAMED_SERVER_VALID(server));
10260 
10261 	port = isc_sockaddr_getport(addr);
10262 	if (port == 0 || port >= 1024) {
10263 		return;
10264 	}
10265 
10266 	for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10267 	     dispatch = ISC_LIST_NEXT(dispatch, link))
10268 	{
10269 		if (isc_sockaddr_equal(&dispatch->addr, addr)) {
10270 			break;
10271 		}
10272 	}
10273 	if (dispatch != NULL) {
10274 		dispatch->dispatchgen = server->dispatchgen;
10275 		return;
10276 	}
10277 
10278 	dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
10279 
10280 	dispatch->addr = *addr;
10281 	dispatch->dispatchgen = server->dispatchgen;
10282 	dispatch->dispatch = NULL;
10283 
10284 	attrs = 0;
10285 	attrs |= DNS_DISPATCHATTR_UDP;
10286 	switch (isc_sockaddr_pf(addr)) {
10287 	case AF_INET:
10288 		attrs |= DNS_DISPATCHATTR_IPV4;
10289 		break;
10290 	case AF_INET6:
10291 		attrs |= DNS_DISPATCHATTR_IPV6;
10292 		break;
10293 	default:
10294 		result = ISC_R_NOTIMPLEMENTED;
10295 		goto cleanup;
10296 	}
10297 	attrmask = 0;
10298 	attrmask |= DNS_DISPATCHATTR_UDP;
10299 	attrmask |= DNS_DISPATCHATTR_TCP;
10300 	attrmask |= DNS_DISPATCHATTR_IPV4;
10301 	attrmask |= DNS_DISPATCHATTR_IPV6;
10302 
10303 	result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr,
10304 				     named_g_taskmgr, &dispatch->addr, 4096,
10305 				     UDPBUFFERS, 32768, 16411, 16433, attrs,
10306 				     attrmask, &dispatch->dispatch);
10307 	if (result != ISC_R_SUCCESS) {
10308 		goto cleanup;
10309 	}
10310 
10311 	ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
10312 
10313 	return;
10314 
10315 cleanup:
10316 	isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10317 	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
10318 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10319 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
10320 		      "unable to create dispatch for reserved port %s: %s",
10321 		      addrbuf, isc_result_totext(result));
10322 }
10323 
10324 static isc_result_t
loadconfig(named_server_t * server)10325 loadconfig(named_server_t *server) {
10326 	isc_result_t result;
10327 	start_reserved_dispatches(server);
10328 	result = load_configuration(named_g_conffile, server, false);
10329 	if (result == ISC_R_SUCCESS) {
10330 		end_reserved_dispatches(server, false);
10331 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10332 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10333 			      "reloading configuration succeeded");
10334 	} else {
10335 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10336 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10337 			      "reloading configuration failed: %s",
10338 			      isc_result_totext(result));
10339 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10340 	}
10341 
10342 	return (result);
10343 }
10344 
10345 static isc_result_t
reload(named_server_t * server)10346 reload(named_server_t *server) {
10347 	isc_result_t result;
10348 
10349 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10350 
10351 	CHECK(loadconfig(server));
10352 
10353 	result = load_zones(server, false, false);
10354 	if (result == ISC_R_SUCCESS) {
10355 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10356 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10357 			      "reloading zones succeeded");
10358 	} else {
10359 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10360 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10361 			      "reloading zones failed: %s",
10362 			      isc_result_totext(result));
10363 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10364 	}
10365 cleanup:
10366 	return (result);
10367 }
10368 
10369 /*
10370  * Handle a reload event (from SIGHUP).
10371  */
10372 static void
named_server_reload(isc_task_t * task,isc_event_t * event)10373 named_server_reload(isc_task_t *task, isc_event_t *event) {
10374 	named_server_t *server = (named_server_t *)event->ev_arg;
10375 
10376 	INSIST(task == server->task);
10377 	UNUSED(task);
10378 
10379 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10380 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10381 		      "received SIGHUP signal to reload zones");
10382 	(void)reload(server);
10383 
10384 	LOCK(&server->reload_event_lock);
10385 	INSIST(server->reload_event == NULL);
10386 	server->reload_event = event;
10387 	UNLOCK(&server->reload_event_lock);
10388 }
10389 
10390 void
named_server_reloadwanted(named_server_t * server)10391 named_server_reloadwanted(named_server_t *server) {
10392 	LOCK(&server->reload_event_lock);
10393 	if (server->reload_event != NULL) {
10394 		isc_task_send(server->task, &server->reload_event);
10395 	}
10396 	UNLOCK(&server->reload_event_lock);
10397 }
10398 
10399 void
named_server_scan_interfaces(named_server_t * server)10400 named_server_scan_interfaces(named_server_t *server) {
10401 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10402 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
10403 		      "automatic interface rescan");
10404 
10405 	ns_interfacemgr_scan(server->interfacemgr, true);
10406 }
10407 
10408 /*
10409  * Get the next token from lexer 'lex'.
10410  *
10411  * NOTE: the token value for string tokens always uses the same pointer
10412  * value.  Multiple calls to this function on the same lexer will always
10413  * return either that value (lex->data) or NULL. It is necessary to copy
10414  * the token into local storage if it needs to be referenced after the next
10415  * call to next_token().
10416  */
10417 static char *
next_token(isc_lex_t * lex,isc_buffer_t ** text)10418 next_token(isc_lex_t *lex, isc_buffer_t **text) {
10419 	isc_result_t result;
10420 	isc_token_t token;
10421 
10422 	token.type = isc_tokentype_unknown;
10423 	result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING,
10424 				  &token);
10425 
10426 	switch (result) {
10427 	case ISC_R_NOMORE:
10428 		(void)isc_lex_close(lex);
10429 		break;
10430 	case ISC_R_SUCCESS:
10431 		if (token.type == isc_tokentype_eof) {
10432 			(void)isc_lex_close(lex);
10433 		}
10434 		break;
10435 	case ISC_R_NOSPACE:
10436 		if (text != NULL) {
10437 			(void)putstr(text, "token too large");
10438 			(void)putnull(text);
10439 		}
10440 		return (NULL);
10441 	default:
10442 		if (text != NULL) {
10443 			(void)putstr(text, isc_result_totext(result));
10444 			(void)putnull(text);
10445 		}
10446 		return (NULL);
10447 	}
10448 
10449 	if (token.type == isc_tokentype_string ||
10450 	    token.type == isc_tokentype_qstring)
10451 	{
10452 		return (token.value.as_textregion.base);
10453 	}
10454 
10455 	return (NULL);
10456 }
10457 
10458 /*
10459  * Find the zone specified in the control channel command, if any.
10460  * If a zone is specified, point '*zonep' at it, otherwise
10461  * set '*zonep' to NULL, and f 'zonename' is not NULL, copy
10462  * the zone name into it (N.B. 'zonename' must have space to hold
10463  * a full DNS name).
10464  *
10465  * If 'zonetxt' is set, the caller has already pulled a token
10466  * off the command line that is to be used as the zone name. (This
10467  * is sometimes done when it's necessary to check for an optional
10468  * argument before the zone name, as in "rndc sync [-clean] zone".)
10469  */
10470 static isc_result_t
zone_from_args(named_server_t * server,isc_lex_t * lex,const char * zonetxt,dns_zone_t ** zonep,char * zonename,isc_buffer_t ** text,bool skip)10471 zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
10472 	       dns_zone_t **zonep, char *zonename, isc_buffer_t **text,
10473 	       bool skip) {
10474 	char *ptr;
10475 	char *classtxt;
10476 	const char *viewtxt = NULL;
10477 	dns_fixedname_t fname;
10478 	dns_name_t *name;
10479 	isc_result_t result;
10480 	dns_view_t *view = NULL;
10481 	dns_rdataclass_t rdclass;
10482 	char problem[DNS_NAME_FORMATSIZE + 500] = "";
10483 	char zonebuf[DNS_NAME_FORMATSIZE];
10484 	bool redirect = false;
10485 
10486 	REQUIRE(zonep != NULL && *zonep == NULL);
10487 
10488 	if (skip) {
10489 		/* Skip the command name. */
10490 		ptr = next_token(lex, text);
10491 		if (ptr == NULL) {
10492 			return (ISC_R_UNEXPECTEDEND);
10493 		}
10494 	}
10495 
10496 	/* Look for the zone name. */
10497 	if (zonetxt == NULL) {
10498 		zonetxt = next_token(lex, text);
10499 	}
10500 	if (zonetxt == NULL) {
10501 		return (ISC_R_SUCCESS);
10502 	}
10503 
10504 	/* Copy zonetxt because it'll be overwritten by next_token() */
10505 	/* To locate a zone named "-redirect" use "-redirect." */
10506 	if (strcmp(zonetxt, "-redirect") == 0) {
10507 		redirect = true;
10508 		strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE);
10509 	} else {
10510 		strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE);
10511 	}
10512 	if (zonename != NULL) {
10513 		strlcpy(zonename, redirect ? "." : zonetxt,
10514 			DNS_NAME_FORMATSIZE);
10515 	}
10516 
10517 	name = dns_fixedname_initname(&fname);
10518 	CHECK(dns_name_fromstring(name, zonebuf, 0, NULL));
10519 
10520 	/* Look for the optional class name. */
10521 	classtxt = next_token(lex, text);
10522 	if (classtxt != NULL) {
10523 		isc_textregion_t r;
10524 		r.base = classtxt;
10525 		r.length = strlen(classtxt);
10526 		CHECK(dns_rdataclass_fromtext(&rdclass, &r));
10527 
10528 		/* Look for the optional view name. */
10529 		viewtxt = next_token(lex, text);
10530 	} else {
10531 		rdclass = dns_rdataclass_in;
10532 	}
10533 
10534 	if (viewtxt == NULL) {
10535 		if (redirect) {
10536 			result = dns_viewlist_find(&server->viewlist,
10537 						   "_default",
10538 						   dns_rdataclass_in, &view);
10539 			if (result != ISC_R_SUCCESS || view->redirect == NULL) {
10540 				result = ISC_R_NOTFOUND;
10541 				snprintf(problem, sizeof(problem),
10542 					 "redirect zone not found in "
10543 					 "_default view");
10544 			} else {
10545 				dns_zone_attach(view->redirect, zonep);
10546 				result = ISC_R_SUCCESS;
10547 			}
10548 		} else {
10549 			result = dns_viewlist_findzone(&server->viewlist, name,
10550 						       (classtxt == NULL),
10551 						       rdclass, zonep);
10552 			if (result == ISC_R_NOTFOUND) {
10553 				snprintf(problem, sizeof(problem),
10554 					 "no matching zone '%s' in any view",
10555 					 zonebuf);
10556 			} else if (result == ISC_R_MULTIPLE) {
10557 				snprintf(problem, sizeof(problem),
10558 					 "zone '%s' was found in multiple "
10559 					 "views",
10560 					 zonebuf);
10561 			}
10562 		}
10563 	} else {
10564 		result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass,
10565 					   &view);
10566 		if (result != ISC_R_SUCCESS) {
10567 			snprintf(problem, sizeof(problem),
10568 				 "no matching view '%s'", viewtxt);
10569 			goto report;
10570 		}
10571 
10572 		if (redirect) {
10573 			if (view->redirect != NULL) {
10574 				dns_zone_attach(view->redirect, zonep);
10575 				result = ISC_R_SUCCESS;
10576 			} else {
10577 				result = ISC_R_NOTFOUND;
10578 			}
10579 		} else {
10580 			result = dns_zt_find(view->zonetable, name, 0, NULL,
10581 					     zonep);
10582 		}
10583 		if (result != ISC_R_SUCCESS) {
10584 			snprintf(problem, sizeof(problem),
10585 				 "no matching zone '%s' in view '%s'", zonebuf,
10586 				 viewtxt);
10587 		}
10588 	}
10589 
10590 	/* Partial match? */
10591 	if (result != ISC_R_SUCCESS && *zonep != NULL) {
10592 		dns_zone_detach(zonep);
10593 	}
10594 	if (result == DNS_R_PARTIALMATCH) {
10595 		result = ISC_R_NOTFOUND;
10596 	}
10597 report:
10598 	if (result != ISC_R_SUCCESS) {
10599 		isc_result_t tresult;
10600 
10601 		tresult = putstr(text, problem);
10602 		if (tresult == ISC_R_SUCCESS) {
10603 			(void)putnull(text);
10604 		}
10605 	}
10606 
10607 cleanup:
10608 	if (view != NULL) {
10609 		dns_view_detach(&view);
10610 	}
10611 
10612 	return (result);
10613 }
10614 
10615 /*
10616  * Act on a "retransfer" command from the command channel.
10617  */
10618 isc_result_t
named_server_retransfercommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10619 named_server_retransfercommand(named_server_t *server, isc_lex_t *lex,
10620 			       isc_buffer_t **text) {
10621 	isc_result_t result;
10622 	dns_zone_t *zone = NULL;
10623 	dns_zone_t *raw = NULL;
10624 	dns_zonetype_t type;
10625 
10626 	REQUIRE(text != NULL);
10627 
10628 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10629 	if (result != ISC_R_SUCCESS) {
10630 		return (result);
10631 	}
10632 	if (zone == NULL) {
10633 		return (ISC_R_UNEXPECTEDEND);
10634 	}
10635 	dns_zone_getraw(zone, &raw);
10636 	if (raw != NULL) {
10637 		dns_zone_detach(&zone);
10638 		dns_zone_attach(raw, &zone);
10639 		dns_zone_detach(&raw);
10640 	}
10641 	type = dns_zone_gettype(zone);
10642 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
10643 	    type == dns_zone_stub ||
10644 	    (type == dns_zone_redirect &&
10645 	     dns_zone_getredirecttype(zone) == dns_zone_secondary))
10646 	{
10647 		dns_zone_forcereload(zone);
10648 	} else {
10649 		(void)putstr(text, "retransfer: inappropriate zone type: ");
10650 		(void)putstr(text, dns_zonetype_name(type));
10651 		if (type == dns_zone_redirect) {
10652 			type = dns_zone_getredirecttype(zone);
10653 			(void)putstr(text, "(");
10654 			(void)putstr(text, dns_zonetype_name(type));
10655 			(void)putstr(text, ")");
10656 		}
10657 		(void)putnull(text);
10658 		result = ISC_R_FAILURE;
10659 	}
10660 	dns_zone_detach(&zone);
10661 	return (result);
10662 }
10663 
10664 /*
10665  * Act on a "reload" command from the command channel.
10666  */
10667 isc_result_t
named_server_reloadcommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10668 named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
10669 			   isc_buffer_t **text) {
10670 	isc_result_t result;
10671 	dns_zone_t *zone = NULL;
10672 	dns_zonetype_t type;
10673 	const char *msg = NULL;
10674 
10675 	REQUIRE(text != NULL);
10676 
10677 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10678 	if (result != ISC_R_SUCCESS) {
10679 		return (result);
10680 	}
10681 	if (zone == NULL) {
10682 		result = reload(server);
10683 		if (result == ISC_R_SUCCESS) {
10684 			msg = "server reload successful";
10685 		}
10686 	} else {
10687 		type = dns_zone_gettype(zone);
10688 		if (type == dns_zone_secondary || type == dns_zone_mirror ||
10689 		    type == dns_zone_stub)
10690 		{
10691 			dns_zone_refresh(zone);
10692 			dns_zone_detach(&zone);
10693 			msg = "zone refresh queued";
10694 		} else {
10695 			result = dns_zone_load(zone, false);
10696 			dns_zone_detach(&zone);
10697 			switch (result) {
10698 			case ISC_R_SUCCESS:
10699 				msg = "zone reload successful";
10700 				break;
10701 			case DNS_R_CONTINUE:
10702 				msg = "zone reload queued";
10703 				result = ISC_R_SUCCESS;
10704 				break;
10705 			case DNS_R_UPTODATE:
10706 				msg = "zone reload up-to-date";
10707 				result = ISC_R_SUCCESS;
10708 				break;
10709 			default:
10710 				/* failure message will be generated by rndc */
10711 				break;
10712 			}
10713 		}
10714 	}
10715 	if (msg != NULL) {
10716 		(void)putstr(text, msg);
10717 		(void)putnull(text);
10718 	}
10719 	return (result);
10720 }
10721 
10722 /*
10723  * Act on a "reconfig" command from the command channel.
10724  */
10725 isc_result_t
named_server_reconfigcommand(named_server_t * server)10726 named_server_reconfigcommand(named_server_t *server) {
10727 	isc_result_t result;
10728 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10729 
10730 	CHECK(loadconfig(server));
10731 
10732 	result = load_zones(server, false, true);
10733 	if (result == ISC_R_SUCCESS) {
10734 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10735 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10736 			      "scheduled loading new zones");
10737 	} else {
10738 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10739 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10740 			      "loading new zones failed: %s",
10741 			      isc_result_totext(result));
10742 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10743 	}
10744 cleanup:
10745 	return (result);
10746 }
10747 
10748 /*
10749  * Act on a "notify" command from the command channel.
10750  */
10751 isc_result_t
named_server_notifycommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10752 named_server_notifycommand(named_server_t *server, isc_lex_t *lex,
10753 			   isc_buffer_t **text) {
10754 	isc_result_t result;
10755 	dns_zone_t *zone = NULL;
10756 	const char msg[] = "zone notify queued";
10757 
10758 	REQUIRE(text != NULL);
10759 
10760 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10761 	if (result != ISC_R_SUCCESS) {
10762 		return (result);
10763 	}
10764 	if (zone == NULL) {
10765 		return (ISC_R_UNEXPECTEDEND);
10766 	}
10767 
10768 	dns_zone_notify(zone);
10769 	dns_zone_detach(&zone);
10770 	(void)putstr(text, msg);
10771 	(void)putnull(text);
10772 
10773 	return (ISC_R_SUCCESS);
10774 }
10775 
10776 /*
10777  * Act on a "refresh" command from the command channel.
10778  */
10779 isc_result_t
named_server_refreshcommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10780 named_server_refreshcommand(named_server_t *server, isc_lex_t *lex,
10781 			    isc_buffer_t **text) {
10782 	isc_result_t result;
10783 	dns_zone_t *zone = NULL, *raw = NULL;
10784 	const char msg1[] = "zone refresh queued";
10785 	const char msg2[] = "not a slave, mirror, or stub zone";
10786 	dns_zonetype_t type;
10787 
10788 	REQUIRE(text != NULL);
10789 
10790 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10791 	if (result != ISC_R_SUCCESS) {
10792 		return (result);
10793 	}
10794 	if (zone == NULL) {
10795 		return (ISC_R_UNEXPECTEDEND);
10796 	}
10797 
10798 	dns_zone_getraw(zone, &raw);
10799 	if (raw != NULL) {
10800 		dns_zone_detach(&zone);
10801 		dns_zone_attach(raw, &zone);
10802 		dns_zone_detach(&raw);
10803 	}
10804 
10805 	type = dns_zone_gettype(zone);
10806 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
10807 	    type == dns_zone_stub)
10808 	{
10809 		dns_zone_refresh(zone);
10810 		dns_zone_detach(&zone);
10811 		(void)putstr(text, msg1);
10812 		(void)putnull(text);
10813 		return (ISC_R_SUCCESS);
10814 	}
10815 
10816 	dns_zone_detach(&zone);
10817 	(void)putstr(text, msg2);
10818 	(void)putnull(text);
10819 	return (ISC_R_FAILURE);
10820 }
10821 
10822 isc_result_t
named_server_togglequerylog(named_server_t * server,isc_lex_t * lex)10823 named_server_togglequerylog(named_server_t *server, isc_lex_t *lex) {
10824 	bool prev, value;
10825 	char *ptr;
10826 
10827 	/* Skip the command name. */
10828 	ptr = next_token(lex, NULL);
10829 	if (ptr == NULL) {
10830 		return (ISC_R_UNEXPECTEDEND);
10831 	}
10832 
10833 	prev = ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES);
10834 
10835 	ptr = next_token(lex, NULL);
10836 	if (ptr == NULL) {
10837 		value = !prev;
10838 	} else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
10839 		   !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
10840 	{
10841 		value = true;
10842 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
10843 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
10844 	{
10845 		value = false;
10846 	} else {
10847 		return (DNS_R_SYNTAX);
10848 	}
10849 
10850 	if (value == prev) {
10851 		return (ISC_R_SUCCESS);
10852 	}
10853 
10854 	ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES, value);
10855 
10856 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10857 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10858 		      "query logging is now %s", value ? "on" : "off");
10859 	return (ISC_R_SUCCESS);
10860 }
10861 
10862 static isc_result_t
ns_listenlist_fromconfig(const cfg_obj_t * listenlist,const cfg_obj_t * config,cfg_aclconfctx_t * actx,isc_mem_t * mctx,uint16_t family,ns_listenlist_t ** target)10863 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
10864 			 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
10865 			 uint16_t family, ns_listenlist_t **target) {
10866 	isc_result_t result;
10867 	const cfg_listelt_t *element;
10868 	ns_listenlist_t *dlist = NULL;
10869 
10870 	REQUIRE(target != NULL && *target == NULL);
10871 
10872 	result = ns_listenlist_create(mctx, &dlist);
10873 	if (result != ISC_R_SUCCESS) {
10874 		return (result);
10875 	}
10876 
10877 	for (element = cfg_list_first(listenlist); element != NULL;
10878 	     element = cfg_list_next(element))
10879 	{
10880 		ns_listenelt_t *delt = NULL;
10881 		const cfg_obj_t *listener = cfg_listelt_value(element);
10882 		result = ns_listenelt_fromconfig(listener, config, actx, mctx,
10883 						 family, &delt);
10884 		if (result != ISC_R_SUCCESS) {
10885 			goto cleanup;
10886 		}
10887 		ISC_LIST_APPEND(dlist->elts, delt, link);
10888 	}
10889 	*target = dlist;
10890 	return (ISC_R_SUCCESS);
10891 
10892 cleanup:
10893 	ns_listenlist_detach(&dlist);
10894 	return (result);
10895 }
10896 
10897 /*
10898  * Create a listen list from the corresponding configuration
10899  * data structure.
10900  */
10901 static isc_result_t
ns_listenelt_fromconfig(const cfg_obj_t * listener,const cfg_obj_t * config,cfg_aclconfctx_t * actx,isc_mem_t * mctx,uint16_t family,ns_listenelt_t ** target)10902 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
10903 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
10904 			uint16_t family, ns_listenelt_t **target) {
10905 	isc_result_t result;
10906 	const cfg_obj_t *portobj, *dscpobj;
10907 	in_port_t port;
10908 	isc_dscp_t dscp = -1;
10909 	ns_listenelt_t *delt = NULL;
10910 	REQUIRE(target != NULL && *target == NULL);
10911 
10912 	portobj = cfg_tuple_get(listener, "port");
10913 	if (!cfg_obj_isuint32(portobj)) {
10914 		if (named_g_port != 0) {
10915 			port = named_g_port;
10916 		} else {
10917 			result = named_config_getport(config, &port);
10918 			if (result != ISC_R_SUCCESS) {
10919 				return (result);
10920 			}
10921 		}
10922 	} else {
10923 		if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
10924 			cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR,
10925 				    "port value '%u' is out of range",
10926 				    cfg_obj_asuint32(portobj));
10927 			return (ISC_R_RANGE);
10928 		}
10929 		port = (in_port_t)cfg_obj_asuint32(portobj);
10930 	}
10931 
10932 	dscpobj = cfg_tuple_get(listener, "dscp");
10933 	if (!cfg_obj_isuint32(dscpobj)) {
10934 		dscp = named_g_dscp;
10935 	} else {
10936 		if (cfg_obj_asuint32(dscpobj) > 63) {
10937 			cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR,
10938 				    "dscp value '%u' is out of range",
10939 				    cfg_obj_asuint32(dscpobj));
10940 			return (ISC_R_RANGE);
10941 		}
10942 		dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
10943 	}
10944 
10945 	result = ns_listenelt_create(mctx, port, dscp, NULL, &delt);
10946 	if (result != ISC_R_SUCCESS) {
10947 		return (result);
10948 	}
10949 
10950 	result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"), config,
10951 				     named_g_lctx, actx, mctx, 0, family,
10952 				     &delt->acl);
10953 	if (result != ISC_R_SUCCESS) {
10954 		ns_listenelt_destroy(delt);
10955 		return (result);
10956 	}
10957 	*target = delt;
10958 	return (ISC_R_SUCCESS);
10959 }
10960 
10961 isc_result_t
named_server_dumpstats(named_server_t * server)10962 named_server_dumpstats(named_server_t *server) {
10963 	isc_result_t result;
10964 	FILE *fp = NULL;
10965 
10966 	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
10967 		"could not open statistics dump file", server->statsfile);
10968 
10969 	result = named_stats_dump(server, fp);
10970 
10971 cleanup:
10972 	if (fp != NULL) {
10973 		(void)isc_stdio_close(fp);
10974 	}
10975 	if (result == ISC_R_SUCCESS) {
10976 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10977 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10978 			      "dumpstats complete");
10979 	} else {
10980 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10981 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10982 			      "dumpstats failed: %s",
10983 			      dns_result_totext(result));
10984 	}
10985 	return (result);
10986 }
10987 
10988 static isc_result_t
add_zone_tolist(dns_zone_t * zone,void * uap)10989 add_zone_tolist(dns_zone_t *zone, void *uap) {
10990 	struct dumpcontext *dctx = uap;
10991 	struct zonelistentry *zle;
10992 
10993 	zle = isc_mem_get(dctx->mctx, sizeof *zle);
10994 	zle->zone = NULL;
10995 	dns_zone_attach(zone, &zle->zone);
10996 	ISC_LINK_INIT(zle, link);
10997 	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
10998 	return (ISC_R_SUCCESS);
10999 }
11000 
11001 static isc_result_t
add_view_tolist(struct dumpcontext * dctx,dns_view_t * view)11002 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
11003 	struct viewlistentry *vle;
11004 	isc_result_t result = ISC_R_SUCCESS;
11005 
11006 	/*
11007 	 * Prevent duplicate views.
11008 	 */
11009 	for (vle = ISC_LIST_HEAD(dctx->viewlist); vle != NULL;
11010 	     vle = ISC_LIST_NEXT(vle, link))
11011 	{
11012 		if (vle->view == view) {
11013 			return (ISC_R_SUCCESS);
11014 		}
11015 	}
11016 
11017 	vle = isc_mem_get(dctx->mctx, sizeof *vle);
11018 	vle->view = NULL;
11019 	dns_view_attach(view, &vle->view);
11020 	ISC_LINK_INIT(vle, link);
11021 	ISC_LIST_INIT(vle->zonelist);
11022 	ISC_LIST_APPEND(dctx->viewlist, vle, link);
11023 	if (dctx->dumpzones) {
11024 		result = dns_zt_apply(view->zonetable, isc_rwlocktype_read,
11025 				      true, NULL, add_zone_tolist, dctx);
11026 	}
11027 	return (result);
11028 }
11029 
11030 static void
dumpcontext_destroy(struct dumpcontext * dctx)11031 dumpcontext_destroy(struct dumpcontext *dctx) {
11032 	struct viewlistentry *vle;
11033 	struct zonelistentry *zle;
11034 
11035 	vle = ISC_LIST_HEAD(dctx->viewlist);
11036 	while (vle != NULL) {
11037 		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
11038 		zle = ISC_LIST_HEAD(vle->zonelist);
11039 		while (zle != NULL) {
11040 			ISC_LIST_UNLINK(vle->zonelist, zle, link);
11041 			dns_zone_detach(&zle->zone);
11042 			isc_mem_put(dctx->mctx, zle, sizeof *zle);
11043 			zle = ISC_LIST_HEAD(vle->zonelist);
11044 		}
11045 		dns_view_detach(&vle->view);
11046 		isc_mem_put(dctx->mctx, vle, sizeof *vle);
11047 		vle = ISC_LIST_HEAD(dctx->viewlist);
11048 	}
11049 	if (dctx->version != NULL) {
11050 		dns_db_closeversion(dctx->db, &dctx->version, false);
11051 	}
11052 	if (dctx->db != NULL) {
11053 		dns_db_detach(&dctx->db);
11054 	}
11055 	if (dctx->cache != NULL) {
11056 		dns_db_detach(&dctx->cache);
11057 	}
11058 	if (dctx->task != NULL) {
11059 		isc_task_detach(&dctx->task);
11060 	}
11061 	if (dctx->fp != NULL) {
11062 		(void)isc_stdio_close(dctx->fp);
11063 	}
11064 	if (dctx->mdctx != NULL) {
11065 		dns_dumpctx_detach(&dctx->mdctx);
11066 	}
11067 	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
11068 }
11069 
11070 static void
dumpdone(void * arg,isc_result_t result)11071 dumpdone(void *arg, isc_result_t result) {
11072 	struct dumpcontext *dctx = arg;
11073 	char buf[1024 + 32];
11074 	const dns_master_style_t *style;
11075 
11076 	if (result != ISC_R_SUCCESS) {
11077 		goto cleanup;
11078 	}
11079 	if (dctx->mdctx != NULL) {
11080 		dns_dumpctx_detach(&dctx->mdctx);
11081 	}
11082 	if (dctx->view == NULL) {
11083 		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
11084 		if (dctx->view == NULL) {
11085 			goto done;
11086 		}
11087 		INSIST(dctx->zone == NULL);
11088 	} else {
11089 		goto resume;
11090 	}
11091 nextview:
11092 	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
11093 resume:
11094 	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
11095 		fprintf(dctx->fp, ";\n; Cache of view '%s' is shared as '%s'\n",
11096 			dctx->view->view->name,
11097 			dns_cache_getname(dctx->view->view->cache));
11098 	} else if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache)
11099 	{
11100 		if (dctx->dumpexpired) {
11101 			style = &dns_master_style_cache_with_expired;
11102 		} else {
11103 			style = &dns_master_style_cache;
11104 		}
11105 		/* start cache dump */
11106 		if (dctx->view->view->cachedb != NULL) {
11107 			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11108 		}
11109 		if (dctx->cache != NULL) {
11110 			fprintf(dctx->fp,
11111 				";\n; Cache dump of view '%s' (cache %s)\n;\n",
11112 				dctx->view->view->name,
11113 				dns_cache_getname(dctx->view->view->cache));
11114 			result = dns_master_dumptostreamasync(
11115 				dctx->mctx, dctx->cache, NULL, style, dctx->fp,
11116 				dctx->task, dumpdone, dctx, &dctx->mdctx);
11117 			if (result == DNS_R_CONTINUE) {
11118 				return;
11119 			}
11120 			if (result == ISC_R_NOTIMPLEMENTED) {
11121 				fprintf(dctx->fp, "; %s\n",
11122 					dns_result_totext(result));
11123 			} else if (result != ISC_R_SUCCESS) {
11124 				goto cleanup;
11125 			}
11126 		}
11127 	}
11128 
11129 	if ((dctx->dumpadb || dctx->dumpbad || dctx->dumpfail) &&
11130 	    dctx->cache == NULL && dctx->view->view->cachedb != NULL)
11131 	{
11132 		dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11133 	}
11134 
11135 	if (dctx->cache != NULL) {
11136 		if (dctx->dumpadb) {
11137 			dns_adb_dump(dctx->view->view->adb, dctx->fp);
11138 		}
11139 		if (dctx->dumpbad) {
11140 			dns_resolver_printbadcache(dctx->view->view->resolver,
11141 						   dctx->fp);
11142 		}
11143 		if (dctx->dumpfail) {
11144 			dns_badcache_print(dctx->view->view->failcache,
11145 					   "SERVFAIL cache", dctx->fp);
11146 		}
11147 		dns_db_detach(&dctx->cache);
11148 	}
11149 	if (dctx->dumpzones) {
11150 		style = &dns_master_style_full;
11151 	nextzone:
11152 		if (dctx->version != NULL) {
11153 			dns_db_closeversion(dctx->db, &dctx->version, false);
11154 		}
11155 		if (dctx->db != NULL) {
11156 			dns_db_detach(&dctx->db);
11157 		}
11158 		if (dctx->zone == NULL) {
11159 			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
11160 		} else {
11161 			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
11162 		}
11163 		if (dctx->zone != NULL) {
11164 			/* start zone dump */
11165 			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
11166 			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
11167 			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
11168 			if (result != ISC_R_SUCCESS) {
11169 				fprintf(dctx->fp, "; %s\n",
11170 					dns_result_totext(result));
11171 				goto nextzone;
11172 			}
11173 			dns_db_currentversion(dctx->db, &dctx->version);
11174 			result = dns_master_dumptostreamasync(
11175 				dctx->mctx, dctx->db, dctx->version, style,
11176 				dctx->fp, dctx->task, dumpdone, dctx,
11177 				&dctx->mdctx);
11178 			if (result == DNS_R_CONTINUE) {
11179 				return;
11180 			}
11181 			if (result == ISC_R_NOTIMPLEMENTED) {
11182 				fprintf(dctx->fp, "; %s\n",
11183 					dns_result_totext(result));
11184 				result = ISC_R_SUCCESS;
11185 				POST(result);
11186 				goto nextzone;
11187 			}
11188 			if (result != ISC_R_SUCCESS) {
11189 				goto cleanup;
11190 			}
11191 		}
11192 	}
11193 	if (dctx->view != NULL) {
11194 		dctx->view = ISC_LIST_NEXT(dctx->view, link);
11195 		if (dctx->view != NULL) {
11196 			goto nextview;
11197 		}
11198 	}
11199 done:
11200 	fprintf(dctx->fp, "; Dump complete\n");
11201 	result = isc_stdio_flush(dctx->fp);
11202 	if (result == ISC_R_SUCCESS) {
11203 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11204 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11205 			      "dumpdb complete");
11206 	}
11207 cleanup:
11208 	if (result != ISC_R_SUCCESS) {
11209 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11210 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11211 			      "dumpdb failed: %s", dns_result_totext(result));
11212 	}
11213 	dumpcontext_destroy(dctx);
11214 }
11215 
11216 isc_result_t
named_server_dumpdb(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)11217 named_server_dumpdb(named_server_t *server, isc_lex_t *lex,
11218 		    isc_buffer_t **text) {
11219 	struct dumpcontext *dctx = NULL;
11220 	dns_view_t *view;
11221 	isc_result_t result;
11222 	char *ptr;
11223 	const char *sep;
11224 	bool found;
11225 
11226 	REQUIRE(text != NULL);
11227 
11228 	/* Skip the command name. */
11229 	ptr = next_token(lex, NULL);
11230 	if (ptr == NULL) {
11231 		return (ISC_R_UNEXPECTEDEND);
11232 	}
11233 
11234 	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
11235 
11236 	dctx->mctx = server->mctx;
11237 	dctx->dumpcache = true;
11238 	dctx->dumpadb = true;
11239 	dctx->dumpbad = true;
11240 	dctx->dumpexpired = false;
11241 	dctx->dumpfail = true;
11242 	dctx->dumpzones = false;
11243 	dctx->fp = NULL;
11244 	ISC_LIST_INIT(dctx->viewlist);
11245 	dctx->view = NULL;
11246 	dctx->zone = NULL;
11247 	dctx->cache = NULL;
11248 	dctx->mdctx = NULL;
11249 	dctx->db = NULL;
11250 	dctx->cache = NULL;
11251 	dctx->task = NULL;
11252 	dctx->version = NULL;
11253 	isc_task_attach(server->task, &dctx->task);
11254 
11255 	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
11256 		"could not open dump file", server->dumpfile);
11257 
11258 	ptr = next_token(lex, NULL);
11259 	sep = (ptr == NULL) ? "" : ": ";
11260 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11261 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11262 		      "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : "");
11263 
11264 	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
11265 		/* also dump zones */
11266 		dctx->dumpzones = true;
11267 		ptr = next_token(lex, NULL);
11268 	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
11269 		/* this is the default */
11270 		ptr = next_token(lex, NULL);
11271 	} else if (ptr != NULL && strcmp(ptr, "-expired") == 0) {
11272 		/* this is the same as -cache but includes expired data */
11273 		dctx->dumpexpired = true;
11274 		ptr = next_token(lex, NULL);
11275 	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
11276 		/* only dump zones, suppress caches */
11277 		dctx->dumpadb = false;
11278 		dctx->dumpbad = false;
11279 		dctx->dumpcache = false;
11280 		dctx->dumpfail = false;
11281 		dctx->dumpzones = true;
11282 		ptr = next_token(lex, NULL);
11283 	} else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
11284 		/* only dump adb, suppress other caches */
11285 		dctx->dumpbad = false;
11286 		dctx->dumpcache = false;
11287 		dctx->dumpfail = false;
11288 		ptr = next_token(lex, NULL);
11289 	} else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
11290 		/* only dump badcache, suppress other caches */
11291 		dctx->dumpadb = false;
11292 		dctx->dumpcache = false;
11293 		dctx->dumpfail = false;
11294 		ptr = next_token(lex, NULL);
11295 	} else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
11296 		/* only dump servfail cache, suppress other caches */
11297 		dctx->dumpadb = false;
11298 		dctx->dumpbad = false;
11299 		dctx->dumpcache = false;
11300 		ptr = next_token(lex, NULL);
11301 	}
11302 
11303 nextview:
11304 	found = false;
11305 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11306 	     view = ISC_LIST_NEXT(view, link))
11307 	{
11308 		if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11309 			continue;
11310 		}
11311 		found = true;
11312 		CHECK(add_view_tolist(dctx, view));
11313 	}
11314 	if (ptr != NULL) {
11315 		if (!found) {
11316 			CHECK(putstr(text, "view '"));
11317 			CHECK(putstr(text, ptr));
11318 			CHECK(putstr(text, "' not found"));
11319 			CHECK(putnull(text));
11320 			result = ISC_R_NOTFOUND;
11321 			dumpdone(dctx, result);
11322 			return (result);
11323 		}
11324 		ptr = next_token(lex, NULL);
11325 		if (ptr != NULL) {
11326 			goto nextview;
11327 		}
11328 	}
11329 	dumpdone(dctx, ISC_R_SUCCESS);
11330 	return (ISC_R_SUCCESS);
11331 
11332 cleanup:
11333 	dumpcontext_destroy(dctx);
11334 	return (result);
11335 }
11336 
11337 isc_result_t
named_server_dumpsecroots(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)11338 named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex,
11339 			  isc_buffer_t **text) {
11340 	dns_view_t *view;
11341 	dns_keytable_t *secroots = NULL;
11342 	dns_ntatable_t *ntatable = NULL;
11343 	isc_result_t result;
11344 	char *ptr;
11345 	FILE *fp = NULL;
11346 	isc_time_t now;
11347 	char tbuf[64];
11348 	unsigned int used = isc_buffer_usedlength(*text);
11349 	bool first = true;
11350 
11351 	REQUIRE(text != NULL);
11352 
11353 	/* Skip the command name. */
11354 	ptr = next_token(lex, text);
11355 	if (ptr == NULL) {
11356 		return (ISC_R_UNEXPECTEDEND);
11357 	}
11358 
11359 	/* "-" here means print the output instead of dumping to file */
11360 	ptr = next_token(lex, text);
11361 	if (ptr != NULL && strcmp(ptr, "-") == 0) {
11362 		ptr = next_token(lex, text);
11363 	} else {
11364 		result = isc_stdio_open(server->secrootsfile, "w", &fp);
11365 		if (result != ISC_R_SUCCESS) {
11366 			(void)putstr(text, "could not open ");
11367 			(void)putstr(text, server->secrootsfile);
11368 			CHECKMF(result, "could not open secroots dump file",
11369 				server->secrootsfile);
11370 		}
11371 	}
11372 
11373 	TIME_NOW(&now);
11374 	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
11375 	CHECK(putstr(text, "secure roots as of "));
11376 	CHECK(putstr(text, tbuf));
11377 	CHECK(putstr(text, ":\n"));
11378 	used = isc_buffer_usedlength(*text);
11379 
11380 	do {
11381 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11382 		     view = ISC_LIST_NEXT(view, link))
11383 		{
11384 			if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11385 				continue;
11386 			}
11387 			if (secroots != NULL) {
11388 				dns_keytable_detach(&secroots);
11389 			}
11390 			result = dns_view_getsecroots(view, &secroots);
11391 			if (result == ISC_R_NOTFOUND) {
11392 				result = ISC_R_SUCCESS;
11393 				continue;
11394 			}
11395 			if (first || used != isc_buffer_usedlength(*text)) {
11396 				CHECK(putstr(text, "\n"));
11397 				first = false;
11398 			}
11399 			CHECK(putstr(text, " Start view "));
11400 			CHECK(putstr(text, view->name));
11401 			CHECK(putstr(text, "\n   Secure roots:\n\n"));
11402 			used = isc_buffer_usedlength(*text);
11403 			CHECK(dns_keytable_totext(secroots, text));
11404 
11405 			if (ntatable != NULL) {
11406 				dns_ntatable_detach(&ntatable);
11407 			}
11408 			result = dns_view_getntatable(view, &ntatable);
11409 			if (result == ISC_R_NOTFOUND) {
11410 				result = ISC_R_SUCCESS;
11411 				continue;
11412 			}
11413 			if (used != isc_buffer_usedlength(*text)) {
11414 				CHECK(putstr(text, "\n"));
11415 			}
11416 			CHECK(putstr(text, "   Negative trust anchors:\n\n"));
11417 			used = isc_buffer_usedlength(*text);
11418 			CHECK(dns_ntatable_totext(ntatable, NULL, text));
11419 		}
11420 
11421 		if (ptr != NULL) {
11422 			ptr = next_token(lex, text);
11423 		}
11424 	} while (ptr != NULL);
11425 
11426 cleanup:
11427 	if (secroots != NULL) {
11428 		dns_keytable_detach(&secroots);
11429 	}
11430 	if (ntatable != NULL) {
11431 		dns_ntatable_detach(&ntatable);
11432 	}
11433 
11434 	if (fp != NULL) {
11435 		if (used != isc_buffer_usedlength(*text)) {
11436 			(void)putstr(text, "\n");
11437 		}
11438 		fprintf(fp, "%.*s", (int)isc_buffer_usedlength(*text),
11439 			(char *)isc_buffer_base(*text));
11440 		isc_buffer_clear(*text);
11441 		(void)isc_stdio_close(fp);
11442 	} else if (isc_buffer_usedlength(*text) > 0) {
11443 		(void)putnull(text);
11444 	}
11445 
11446 	if (result == ISC_R_SUCCESS) {
11447 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11448 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11449 			      "dumpsecroots complete");
11450 	} else {
11451 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11452 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11453 			      "dumpsecroots failed: %s",
11454 			      dns_result_totext(result));
11455 	}
11456 	return (result);
11457 }
11458 
11459 isc_result_t
named_server_dumprecursing(named_server_t * server)11460 named_server_dumprecursing(named_server_t *server) {
11461 	FILE *fp = NULL;
11462 	dns_view_t *view;
11463 	isc_result_t result;
11464 
11465 	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
11466 		"could not open dump file", server->recfile);
11467 	fprintf(fp, ";\n; Recursing Queries\n;\n");
11468 	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
11469 
11470 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11471 	     view = ISC_LIST_NEXT(view, link))
11472 	{
11473 		fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
11474 			view->name);
11475 		dns_resolver_dumpfetches(view->resolver, isc_statsformat_file,
11476 					 fp);
11477 	}
11478 
11479 	fprintf(fp, "; Dump complete\n");
11480 
11481 cleanup:
11482 	if (fp != NULL) {
11483 		result = isc_stdio_close(fp);
11484 	}
11485 	if (result == ISC_R_SUCCESS) {
11486 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11487 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11488 			      "dumprecursing complete");
11489 	} else {
11490 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11491 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11492 			      "dumprecursing failed: %s",
11493 			      dns_result_totext(result));
11494 	}
11495 	return (result);
11496 }
11497 
11498 isc_result_t
named_server_setdebuglevel(named_server_t * server,isc_lex_t * lex)11499 named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
11500 	char *ptr;
11501 	char *endp;
11502 	long newlevel;
11503 
11504 	UNUSED(server);
11505 
11506 	/* Skip the command name. */
11507 	ptr = next_token(lex, NULL);
11508 	if (ptr == NULL) {
11509 		return (ISC_R_UNEXPECTEDEND);
11510 	}
11511 
11512 	/* Look for the new level name. */
11513 	ptr = next_token(lex, NULL);
11514 	if (ptr == NULL) {
11515 		if (named_g_debuglevel < 99) {
11516 			named_g_debuglevel++;
11517 		}
11518 	} else {
11519 		newlevel = strtol(ptr, &endp, 10);
11520 		if (*endp != '\0' || newlevel < 0 || newlevel > 99) {
11521 			return (ISC_R_RANGE);
11522 		}
11523 		named_g_debuglevel = (unsigned int)newlevel;
11524 	}
11525 	isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel);
11526 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11527 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11528 		      "debug level is now %u", named_g_debuglevel);
11529 	return (ISC_R_SUCCESS);
11530 }
11531 
11532 isc_result_t
named_server_validation(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)11533 named_server_validation(named_server_t *server, isc_lex_t *lex,
11534 			isc_buffer_t **text) {
11535 	char *ptr;
11536 	dns_view_t *view;
11537 	bool changed = false;
11538 	isc_result_t result;
11539 	bool enable = true, set = true, first = true;
11540 
11541 	REQUIRE(text != NULL);
11542 
11543 	/* Skip the command name. */
11544 	ptr = next_token(lex, text);
11545 	if (ptr == NULL) {
11546 		return (ISC_R_UNEXPECTEDEND);
11547 	}
11548 
11549 	/* Find out what we are to do. */
11550 	ptr = next_token(lex, text);
11551 	if (ptr == NULL) {
11552 		return (ISC_R_UNEXPECTEDEND);
11553 	}
11554 
11555 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
11556 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
11557 	{
11558 		enable = true;
11559 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
11560 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
11561 	{
11562 		enable = false;
11563 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
11564 		set = false;
11565 	} else {
11566 		return (DNS_R_SYNTAX);
11567 	}
11568 
11569 	/* Look for the view name. */
11570 	ptr = next_token(lex, text);
11571 
11572 	result = isc_task_beginexclusive(server->task);
11573 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
11574 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11575 	     view = ISC_LIST_NEXT(view, link))
11576 	{
11577 		if ((ptr != NULL && strcasecmp(ptr, view->name) != 0) ||
11578 		    strcasecmp("_bind", view->name) == 0)
11579 		{
11580 			continue;
11581 		}
11582 
11583 		if (set) {
11584 			CHECK(dns_view_flushcache(view, false));
11585 			view->enablevalidation = enable;
11586 			changed = true;
11587 		} else {
11588 			if (!first) {
11589 				CHECK(putstr(text, "\n"));
11590 			}
11591 			CHECK(putstr(text, "DNSSEC validation is "));
11592 			CHECK(putstr(text, view->enablevalidation
11593 						   ? "enabled"
11594 						   : "disabled"));
11595 			CHECK(putstr(text, " (view "));
11596 			CHECK(putstr(text, view->name));
11597 			CHECK(putstr(text, ")"));
11598 			first = false;
11599 		}
11600 	}
11601 	CHECK(putnull(text));
11602 
11603 	if (!set) {
11604 		result = ISC_R_SUCCESS;
11605 	} else if (changed) {
11606 		result = ISC_R_SUCCESS;
11607 	} else {
11608 		result = ISC_R_FAILURE;
11609 	}
11610 cleanup:
11611 	isc_task_endexclusive(server->task);
11612 	return (result);
11613 }
11614 
11615 isc_result_t
named_server_flushcache(named_server_t * server,isc_lex_t * lex)11616 named_server_flushcache(named_server_t *server, isc_lex_t *lex) {
11617 	char *ptr;
11618 	dns_view_t *view;
11619 	bool flushed;
11620 	bool found;
11621 	isc_result_t result;
11622 	named_cache_t *nsc;
11623 
11624 	/* Skip the command name. */
11625 	ptr = next_token(lex, NULL);
11626 	if (ptr == NULL) {
11627 		return (ISC_R_UNEXPECTEDEND);
11628 	}
11629 
11630 	/* Look for the view name. */
11631 	ptr = next_token(lex, NULL);
11632 
11633 	result = isc_task_beginexclusive(server->task);
11634 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
11635 	flushed = true;
11636 	found = false;
11637 
11638 	/*
11639 	 * Flushing a cache is tricky when caches are shared by multiple views.
11640 	 * We first identify which caches should be flushed in the local cache
11641 	 * list, flush these caches, and then update other views that refer to
11642 	 * the flushed cache DB.
11643 	 */
11644 	if (ptr != NULL) {
11645 		/*
11646 		 * Mark caches that need to be flushed.  This is an O(#view^2)
11647 		 * operation in the very worst case, but should be normally
11648 		 * much more lightweight because only a few (most typically just
11649 		 * one) views will match.
11650 		 */
11651 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11652 		     view = ISC_LIST_NEXT(view, link))
11653 		{
11654 			if (strcasecmp(ptr, view->name) != 0) {
11655 				continue;
11656 			}
11657 			found = true;
11658 			for (nsc = ISC_LIST_HEAD(server->cachelist);
11659 			     nsc != NULL; nsc = ISC_LIST_NEXT(nsc, link))
11660 			{
11661 				if (nsc->cache == view->cache) {
11662 					break;
11663 				}
11664 			}
11665 			INSIST(nsc != NULL);
11666 			nsc->needflush = true;
11667 		}
11668 	} else {
11669 		found = true;
11670 	}
11671 
11672 	/* Perform flush */
11673 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
11674 	     nsc = ISC_LIST_NEXT(nsc, link))
11675 	{
11676 		if (ptr != NULL && !nsc->needflush) {
11677 			continue;
11678 		}
11679 		nsc->needflush = true;
11680 		result = dns_view_flushcache(nsc->primaryview, false);
11681 		if (result != ISC_R_SUCCESS) {
11682 			flushed = false;
11683 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11684 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11685 				      "flushing cache in view '%s' failed: %s",
11686 				      nsc->primaryview->name,
11687 				      isc_result_totext(result));
11688 		}
11689 	}
11690 
11691 	/*
11692 	 * Fix up views that share a flushed cache: let the views update the
11693 	 * cache DB they're referring to.  This could also be an expensive
11694 	 * operation, but should typically be marginal: the inner loop is only
11695 	 * necessary for views that share a cache, and if there are many such
11696 	 * views the number of shared cache should normally be small.
11697 	 * A worst case is that we have n views and n/2 caches, each shared by
11698 	 * two views.  Then this will be a O(n^2/4) operation.
11699 	 */
11700 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11701 	     view = ISC_LIST_NEXT(view, link))
11702 	{
11703 		if (!dns_view_iscacheshared(view)) {
11704 			continue;
11705 		}
11706 		for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
11707 		     nsc = ISC_LIST_NEXT(nsc, link))
11708 		{
11709 			if (!nsc->needflush || nsc->cache != view->cache) {
11710 				continue;
11711 			}
11712 			result = dns_view_flushcache(view, true);
11713 			if (result != ISC_R_SUCCESS) {
11714 				flushed = false;
11715 				isc_log_write(
11716 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11717 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11718 					"fixing cache in view '%s' "
11719 					"failed: %s",
11720 					view->name, isc_result_totext(result));
11721 			}
11722 		}
11723 	}
11724 
11725 	/* Cleanup the cache list. */
11726 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
11727 	     nsc = ISC_LIST_NEXT(nsc, link))
11728 	{
11729 		nsc->needflush = false;
11730 	}
11731 
11732 	if (flushed && found) {
11733 		if (ptr != NULL) {
11734 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11735 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11736 				      "flushing cache in view '%s' succeeded",
11737 				      ptr);
11738 		} else {
11739 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11740 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11741 				      "flushing caches in all views succeeded");
11742 		}
11743 		result = ISC_R_SUCCESS;
11744 	} else {
11745 		if (!found) {
11746 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11747 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11748 				      "flushing cache in view '%s' failed: "
11749 				      "view not found",
11750 				      ptr);
11751 			result = ISC_R_NOTFOUND;
11752 		} else {
11753 			result = ISC_R_FAILURE;
11754 		}
11755 	}
11756 	isc_task_endexclusive(server->task);
11757 	return (result);
11758 }
11759 
11760 isc_result_t
named_server_flushnode(named_server_t * server,isc_lex_t * lex,bool tree)11761 named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) {
11762 	char *ptr, *viewname;
11763 	char target[DNS_NAME_FORMATSIZE];
11764 	dns_view_t *view;
11765 	bool flushed;
11766 	bool found;
11767 	isc_result_t result;
11768 	isc_buffer_t b;
11769 	dns_fixedname_t fixed;
11770 	dns_name_t *name;
11771 
11772 	/* Skip the command name. */
11773 	ptr = next_token(lex, NULL);
11774 	if (ptr == NULL) {
11775 		return (ISC_R_UNEXPECTEDEND);
11776 	}
11777 
11778 	/* Find the domain name to flush. */
11779 	ptr = next_token(lex, NULL);
11780 	if (ptr == NULL) {
11781 		return (ISC_R_UNEXPECTEDEND);
11782 	}
11783 
11784 	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
11785 	isc_buffer_constinit(&b, target, strlen(target));
11786 	isc_buffer_add(&b, strlen(target));
11787 	name = dns_fixedname_initname(&fixed);
11788 	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
11789 	if (result != ISC_R_SUCCESS) {
11790 		return (result);
11791 	}
11792 
11793 	/* Look for the view name. */
11794 	viewname = next_token(lex, NULL);
11795 
11796 	result = isc_task_beginexclusive(server->task);
11797 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
11798 	flushed = true;
11799 	found = false;
11800 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11801 	     view = ISC_LIST_NEXT(view, link))
11802 	{
11803 		if (viewname != NULL && strcasecmp(viewname, view->name) != 0) {
11804 			continue;
11805 		}
11806 		found = true;
11807 		/*
11808 		 * It's a little inefficient to try flushing name for all views
11809 		 * if some of the views share a single cache.  But since the
11810 		 * operation is lightweight we prefer simplicity here.
11811 		 */
11812 		result = dns_view_flushnode(view, name, tree);
11813 		if (result != ISC_R_SUCCESS) {
11814 			flushed = false;
11815 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11816 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11817 				      "flushing %s '%s' in cache view '%s' "
11818 				      "failed: %s",
11819 				      tree ? "tree" : "name", target,
11820 				      view->name, isc_result_totext(result));
11821 		}
11822 	}
11823 	if (flushed && found) {
11824 		if (viewname != NULL) {
11825 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11826 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11827 				      "flushing %s '%s' in cache view '%s' "
11828 				      "succeeded",
11829 				      tree ? "tree" : "name", target, viewname);
11830 		} else {
11831 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11832 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11833 				      "flushing %s '%s' in all cache views "
11834 				      "succeeded",
11835 				      tree ? "tree" : "name", target);
11836 		}
11837 		result = ISC_R_SUCCESS;
11838 	} else {
11839 		if (!found) {
11840 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11841 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11842 				      "flushing %s '%s' in cache view '%s' "
11843 				      "failed: view not found",
11844 				      tree ? "tree" : "name", target, viewname);
11845 		}
11846 		result = ISC_R_FAILURE;
11847 	}
11848 	isc_task_endexclusive(server->task);
11849 	return (result);
11850 }
11851 
11852 isc_result_t
named_server_status(named_server_t * server,isc_buffer_t ** text)11853 named_server_status(named_server_t *server, isc_buffer_t **text) {
11854 	isc_result_t result;
11855 	unsigned int zonecount, xferrunning, xferdeferred, soaqueries;
11856 	unsigned int automatic;
11857 	const char *ob = "", *cb = "", *alt = "";
11858 	char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
11859 	char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
11860 	char line[1024], hostname[256];
11861 	named_reload_t reload_status;
11862 
11863 	REQUIRE(text != NULL);
11864 
11865 	if (named_g_server->version_set) {
11866 		ob = " (";
11867 		cb = ")";
11868 		if (named_g_server->version == NULL) {
11869 			alt = "version.bind/txt/ch disabled";
11870 		} else {
11871 			alt = named_g_server->version;
11872 		}
11873 	}
11874 	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
11875 	xferrunning = dns_zonemgr_getcount(server->zonemgr,
11876 					   DNS_ZONESTATE_XFERRUNNING);
11877 	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
11878 					    DNS_ZONESTATE_XFERDEFERRED);
11879 	soaqueries = dns_zonemgr_getcount(server->zonemgr,
11880 					  DNS_ZONESTATE_SOAQUERY);
11881 	automatic = dns_zonemgr_getcount(server->zonemgr,
11882 					 DNS_ZONESTATE_AUTOMATIC);
11883 
11884 	isc_time_formathttptimestamp(&named_g_boottime, boottime,
11885 				     sizeof(boottime));
11886 	isc_time_formathttptimestamp(&named_g_configtime, configtime,
11887 				     sizeof(configtime));
11888 
11889 	snprintf(line, sizeof(line), "version: %s %s%s%s <id:%s>%s%s%s\n",
11890 		 named_g_product, named_g_version,
11891 		 (*named_g_description != '\0') ? " " : "", named_g_description,
11892 		 named_g_srcid, ob, alt, cb);
11893 	CHECK(putstr(text, line));
11894 
11895 	result = named_os_gethostname(hostname, sizeof(hostname));
11896 	if (result != ISC_R_SUCCESS) {
11897 		strlcpy(hostname, "localhost", sizeof(hostname));
11898 	}
11899 	snprintf(line, sizeof(line), "running on %s: %s\n", hostname,
11900 		 named_os_uname());
11901 	CHECK(putstr(text, line));
11902 
11903 	snprintf(line, sizeof(line), "boot time: %s\n", boottime);
11904 	CHECK(putstr(text, line));
11905 
11906 	snprintf(line, sizeof(line), "last configured: %s\n", configtime);
11907 	CHECK(putstr(text, line));
11908 
11909 	if (named_g_chrootdir != NULL) {
11910 		snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n",
11911 			 named_g_conffile, named_g_chrootdir, named_g_conffile);
11912 	} else {
11913 		snprintf(line, sizeof(line), "configuration file: %s\n",
11914 			 named_g_conffile);
11915 	}
11916 	CHECK(putstr(text, line));
11917 
11918 	snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected);
11919 	CHECK(putstr(text, line));
11920 
11921 	snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
11922 	CHECK(putstr(text, line));
11923 
11924 	snprintf(line, sizeof(line), "UDP listeners per interface: %u\n",
11925 		 named_g_udpdisp);
11926 	CHECK(putstr(text, line));
11927 
11928 	snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
11929 		 zonecount, automatic);
11930 	CHECK(putstr(text, line));
11931 
11932 	snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel);
11933 	CHECK(putstr(text, line));
11934 
11935 	snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
11936 	CHECK(putstr(text, line));
11937 
11938 	snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
11939 	CHECK(putstr(text, line));
11940 
11941 	snprintf(line, sizeof(line), "soa queries in progress: %u\n",
11942 		 soaqueries);
11943 	CHECK(putstr(text, line));
11944 
11945 	snprintf(line, sizeof(line), "query logging is %s\n",
11946 		 ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES)
11947 			 ? "ON"
11948 			 : "OFF");
11949 	CHECK(putstr(text, line));
11950 
11951 	snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
11952 		 isc_quota_getused(&server->sctx->recursionquota),
11953 		 isc_quota_getsoft(&server->sctx->recursionquota),
11954 		 isc_quota_getmax(&server->sctx->recursionquota));
11955 	CHECK(putstr(text, line));
11956 
11957 	snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
11958 		 isc_quota_getused(&server->sctx->tcpquota),
11959 		 isc_quota_getmax(&server->sctx->tcpquota));
11960 	CHECK(putstr(text, line));
11961 
11962 	snprintf(line, sizeof(line), "TCP high-water: %u\n",
11963 		 (unsigned)ns_stats_get_counter(server->sctx->nsstats,
11964 						ns_statscounter_tcphighwater));
11965 	CHECK(putstr(text, line));
11966 
11967 	reload_status = atomic_load(&server->reload_status);
11968 	if (reload_status != NAMED_RELOAD_DONE) {
11969 		snprintf(line, sizeof(line), "reload/reconfig %s\n",
11970 			 (reload_status == NAMED_RELOAD_FAILED
11971 				  ? "failed"
11972 				  : "in progress"));
11973 		CHECK(putstr(text, line));
11974 	}
11975 
11976 	CHECK(putstr(text, "server is up and running"));
11977 	CHECK(putnull(text));
11978 
11979 	return (ISC_R_SUCCESS);
11980 cleanup:
11981 	return (result);
11982 }
11983 
11984 isc_result_t
named_server_testgen(isc_lex_t * lex,isc_buffer_t ** text)11985 named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) {
11986 	isc_result_t result;
11987 	char *ptr;
11988 	unsigned long count;
11989 	unsigned long i;
11990 	const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
11991 
11992 	REQUIRE(text != NULL);
11993 
11994 	/* Skip the command name. */
11995 	ptr = next_token(lex, text);
11996 	if (ptr == NULL) {
11997 		return (ISC_R_UNEXPECTEDEND);
11998 	}
11999 
12000 	ptr = next_token(lex, text);
12001 	if (ptr == NULL) {
12002 		count = 26;
12003 	} else {
12004 		count = strtoul(ptr, NULL, 10);
12005 	}
12006 
12007 	CHECK(isc_buffer_reserve(text, count));
12008 	for (i = 0; i < count; i++) {
12009 		CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
12010 	}
12011 
12012 	CHECK(putnull(text));
12013 
12014 cleanup:
12015 	return (result);
12016 }
12017 
12018 static isc_result_t
delete_keynames(dns_tsig_keyring_t * ring,char * target,unsigned int * foundkeys)12019 delete_keynames(dns_tsig_keyring_t *ring, char *target,
12020 		unsigned int *foundkeys) {
12021 	char namestr[DNS_NAME_FORMATSIZE];
12022 	isc_result_t result;
12023 	dns_rbtnodechain_t chain;
12024 	dns_name_t foundname;
12025 	dns_fixedname_t fixedorigin;
12026 	dns_name_t *origin;
12027 	dns_rbtnode_t *node;
12028 	dns_tsigkey_t *tkey;
12029 
12030 	dns_name_init(&foundname, NULL);
12031 	origin = dns_fixedname_initname(&fixedorigin);
12032 
12033 again:
12034 	dns_rbtnodechain_init(&chain);
12035 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12036 	if (result == ISC_R_NOTFOUND) {
12037 		dns_rbtnodechain_invalidate(&chain);
12038 		return (ISC_R_SUCCESS);
12039 	}
12040 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12041 		dns_rbtnodechain_invalidate(&chain);
12042 		return (result);
12043 	}
12044 
12045 	for (;;) {
12046 		node = NULL;
12047 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12048 		tkey = node->data;
12049 
12050 		if (tkey != NULL) {
12051 			if (!tkey->generated) {
12052 				goto nextkey;
12053 			}
12054 
12055 			dns_name_format(&tkey->name, namestr, sizeof(namestr));
12056 			if (strcmp(namestr, target) == 0) {
12057 				(*foundkeys)++;
12058 				dns_rbtnodechain_invalidate(&chain);
12059 				(void)dns_rbt_deletename(ring->keys,
12060 							 &tkey->name, false);
12061 				goto again;
12062 			}
12063 		}
12064 
12065 	nextkey:
12066 		result = dns_rbtnodechain_next(&chain, &foundname, origin);
12067 		if (result == ISC_R_NOMORE) {
12068 			break;
12069 		}
12070 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12071 			dns_rbtnodechain_invalidate(&chain);
12072 			return (result);
12073 		}
12074 	}
12075 
12076 	return (ISC_R_SUCCESS);
12077 }
12078 
12079 isc_result_t
named_server_tsigdelete(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)12080 named_server_tsigdelete(named_server_t *server, isc_lex_t *lex,
12081 			isc_buffer_t **text) {
12082 	isc_result_t result;
12083 	dns_view_t *view;
12084 	unsigned int foundkeys = 0;
12085 	char *ptr, *viewname;
12086 	char target[DNS_NAME_FORMATSIZE];
12087 	char fbuf[16];
12088 
12089 	REQUIRE(text != NULL);
12090 
12091 	(void)next_token(lex, text); /* skip command name */
12092 
12093 	ptr = next_token(lex, text);
12094 	if (ptr == NULL) {
12095 		return (ISC_R_UNEXPECTEDEND);
12096 	}
12097 	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
12098 
12099 	viewname = next_token(lex, text);
12100 
12101 	result = isc_task_beginexclusive(server->task);
12102 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12103 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12104 	     view = ISC_LIST_NEXT(view, link))
12105 	{
12106 		if (viewname == NULL || strcmp(view->name, viewname) == 0) {
12107 			RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
12108 			result = delete_keynames(view->dynamickeys, target,
12109 						 &foundkeys);
12110 			RWUNLOCK(&view->dynamickeys->lock,
12111 				 isc_rwlocktype_write);
12112 			if (result != ISC_R_SUCCESS) {
12113 				isc_task_endexclusive(server->task);
12114 				return (result);
12115 			}
12116 		}
12117 	}
12118 	isc_task_endexclusive(server->task);
12119 
12120 	snprintf(fbuf, sizeof(fbuf), "%u", foundkeys);
12121 
12122 	CHECK(putstr(text, fbuf));
12123 	CHECK(putstr(text, " tsig keys deleted."));
12124 	CHECK(putnull(text));
12125 
12126 cleanup:
12127 	return (result);
12128 }
12129 
12130 static isc_result_t
list_keynames(dns_view_t * view,dns_tsig_keyring_t * ring,isc_buffer_t ** text,unsigned int * foundkeys)12131 list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t **text,
12132 	      unsigned int *foundkeys) {
12133 	char namestr[DNS_NAME_FORMATSIZE];
12134 	char creatorstr[DNS_NAME_FORMATSIZE];
12135 	isc_result_t result;
12136 	dns_rbtnodechain_t chain;
12137 	dns_name_t foundname;
12138 	dns_fixedname_t fixedorigin;
12139 	dns_name_t *origin;
12140 	dns_rbtnode_t *node;
12141 	dns_tsigkey_t *tkey;
12142 	const char *viewname;
12143 
12144 	if (view != NULL) {
12145 		viewname = view->name;
12146 	} else {
12147 		viewname = "(global)";
12148 	}
12149 
12150 	dns_name_init(&foundname, NULL);
12151 	origin = dns_fixedname_initname(&fixedorigin);
12152 	dns_rbtnodechain_init(&chain);
12153 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12154 	if (result == ISC_R_NOTFOUND) {
12155 		dns_rbtnodechain_invalidate(&chain);
12156 		return (ISC_R_SUCCESS);
12157 	}
12158 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12159 		dns_rbtnodechain_invalidate(&chain);
12160 		return (result);
12161 	}
12162 
12163 	for (;;) {
12164 		node = NULL;
12165 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12166 		tkey = node->data;
12167 
12168 		if (tkey != NULL) {
12169 			dns_name_format(&tkey->name, namestr, sizeof(namestr));
12170 			if (tkey->generated) {
12171 				dns_name_format(tkey->creator, creatorstr,
12172 						sizeof(creatorstr));
12173 				if (*foundkeys != 0) {
12174 					CHECK(putstr(text, "\n"));
12175 				}
12176 				CHECK(putstr(text, "view \""));
12177 				CHECK(putstr(text, viewname));
12178 				CHECK(putstr(text, "\"; type \"dynamic\"; key "
12179 						   "\""));
12180 				CHECK(putstr(text, namestr));
12181 				CHECK(putstr(text, "\"; creator \""));
12182 				CHECK(putstr(text, creatorstr));
12183 				CHECK(putstr(text, "\";"));
12184 			} else {
12185 				if (*foundkeys != 0) {
12186 					CHECK(putstr(text, "\n"));
12187 				}
12188 				CHECK(putstr(text, "view \""));
12189 				CHECK(putstr(text, viewname));
12190 				CHECK(putstr(text, "\"; type \"static\"; key "
12191 						   "\""));
12192 				CHECK(putstr(text, namestr));
12193 				CHECK(putstr(text, "\";"));
12194 			}
12195 			(*foundkeys)++;
12196 		}
12197 		result = dns_rbtnodechain_next(&chain, &foundname, origin);
12198 		if (result == ISC_R_NOMORE || result == DNS_R_NEWORIGIN) {
12199 			break;
12200 		}
12201 	}
12202 
12203 	return (ISC_R_SUCCESS);
12204 cleanup:
12205 	dns_rbtnodechain_invalidate(&chain);
12206 	return (result);
12207 }
12208 
12209 isc_result_t
named_server_tsiglist(named_server_t * server,isc_buffer_t ** text)12210 named_server_tsiglist(named_server_t *server, isc_buffer_t **text) {
12211 	isc_result_t result = ISC_R_SUCCESS;
12212 	dns_view_t *view;
12213 	unsigned int foundkeys = 0;
12214 
12215 	REQUIRE(text != NULL);
12216 
12217 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12218 	     view = ISC_LIST_NEXT(view, link))
12219 	{
12220 		RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12221 		result = list_keynames(view, view->statickeys, text,
12222 				       &foundkeys);
12223 		RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12224 		if (result != ISC_R_SUCCESS) {
12225 			return (result);
12226 		}
12227 		RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12228 		result = list_keynames(view, view->dynamickeys, text,
12229 				       &foundkeys);
12230 		RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12231 		if (result != ISC_R_SUCCESS) {
12232 			return (result);
12233 		}
12234 	}
12235 
12236 	if (foundkeys == 0) {
12237 		CHECK(putstr(text, "no tsig keys found."));
12238 	}
12239 
12240 	if (isc_buffer_usedlength(*text) > 0) {
12241 		CHECK(putnull(text));
12242 	}
12243 
12244 cleanup:
12245 	return (result);
12246 }
12247 
12248 /*
12249  * Act on a "sign" or "loadkeys" command from the command channel.
12250  */
12251 isc_result_t
named_server_rekey(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)12252 named_server_rekey(named_server_t *server, isc_lex_t *lex,
12253 		   isc_buffer_t **text) {
12254 	isc_result_t result;
12255 	dns_zone_t *zone = NULL;
12256 	dns_zonetype_t type;
12257 	uint16_t keyopts;
12258 	bool fullsign = false;
12259 	char *ptr;
12260 
12261 	REQUIRE(text != NULL);
12262 
12263 	ptr = next_token(lex, text);
12264 	if (ptr == NULL) {
12265 		return (ISC_R_UNEXPECTEDEND);
12266 	}
12267 
12268 	if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0) {
12269 		fullsign = true;
12270 	}
12271 
12272 	REQUIRE(text != NULL);
12273 
12274 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, false);
12275 	if (result != ISC_R_SUCCESS) {
12276 		return (result);
12277 	}
12278 	if (zone == NULL) {
12279 		return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */
12280 	}
12281 
12282 	type = dns_zone_gettype(zone);
12283 	if (type != dns_zone_primary) {
12284 		dns_zone_detach(&zone);
12285 		return (DNS_R_NOTMASTER);
12286 	}
12287 
12288 	keyopts = dns_zone_getkeyopts(zone);
12289 
12290 	/*
12291 	 * "rndc loadkeys" requires "auto-dnssec maintain"
12292 	 * or a "dnssec-policy".
12293 	 */
12294 	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) {
12295 		result = ISC_R_NOPERM;
12296 	} else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) {
12297 		result = ISC_R_NOPERM;
12298 	} else {
12299 		dns_zone_rekey(zone, fullsign);
12300 	}
12301 
12302 	dns_zone_detach(&zone);
12303 	return (result);
12304 }
12305 
12306 /*
12307  * Act on a "sync" command from the command channel.
12308  */
12309 static isc_result_t
synczone(dns_zone_t * zone,void * uap)12310 synczone(dns_zone_t *zone, void *uap) {
12311 	bool cleanup = *(bool *)uap;
12312 	isc_result_t result;
12313 	dns_zone_t *raw = NULL;
12314 	char *journal;
12315 
12316 	dns_zone_getraw(zone, &raw);
12317 	if (raw != NULL) {
12318 		synczone(raw, uap);
12319 		dns_zone_detach(&raw);
12320 	}
12321 
12322 	result = dns_zone_flush(zone);
12323 	if (result != ISC_R_SUCCESS) {
12324 		cleanup = false;
12325 	}
12326 	if (cleanup) {
12327 		journal = dns_zone_getjournal(zone);
12328 		if (journal != NULL) {
12329 			(void)isc_file_remove(journal);
12330 		}
12331 	}
12332 
12333 	return (result);
12334 }
12335 
12336 isc_result_t
named_server_sync(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)12337 named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
12338 	isc_result_t result, tresult;
12339 	dns_view_t *view;
12340 	dns_zone_t *zone = NULL;
12341 	char classstr[DNS_RDATACLASS_FORMATSIZE];
12342 	char zonename[DNS_NAME_FORMATSIZE];
12343 	const char *vname, *sep, *arg;
12344 	bool cleanup = false;
12345 
12346 	REQUIRE(text != NULL);
12347 
12348 	(void)next_token(lex, text);
12349 
12350 	arg = next_token(lex, text);
12351 	if (arg != NULL &&
12352 	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0))
12353 	{
12354 		cleanup = true;
12355 		arg = next_token(lex, text);
12356 	}
12357 
12358 	REQUIRE(text != NULL);
12359 
12360 	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
12361 	if (result != ISC_R_SUCCESS) {
12362 		return (result);
12363 	}
12364 
12365 	if (zone == NULL) {
12366 		result = isc_task_beginexclusive(server->task);
12367 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
12368 		tresult = ISC_R_SUCCESS;
12369 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12370 		     view = ISC_LIST_NEXT(view, link))
12371 		{
12372 			result = dns_zt_apply(view->zonetable,
12373 					      isc_rwlocktype_none, false, NULL,
12374 					      synczone, &cleanup);
12375 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12376 			{
12377 				tresult = result;
12378 			}
12379 		}
12380 		isc_task_endexclusive(server->task);
12381 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12382 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12383 			      "dumping all zones%s: %s",
12384 			      cleanup ? ", removing journal files" : "",
12385 			      isc_result_totext(result));
12386 		return (tresult);
12387 	}
12388 
12389 	result = isc_task_beginexclusive(server->task);
12390 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12391 	result = synczone(zone, &cleanup);
12392 	isc_task_endexclusive(server->task);
12393 
12394 	view = dns_zone_getview(zone);
12395 	if (strcmp(view->name, "_default") == 0 ||
12396 	    strcmp(view->name, "_bind") == 0)
12397 	{
12398 		vname = "";
12399 		sep = "";
12400 	} else {
12401 		vname = view->name;
12402 		sep = " ";
12403 	}
12404 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
12405 			      sizeof(classstr));
12406 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
12407 	isc_log_write(
12408 		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12409 		ISC_LOG_INFO, "sync: dumping zone '%s/%s'%s%s%s: %s", zonename,
12410 		classstr, sep, vname, cleanup ? ", removing journal file" : "",
12411 		isc_result_totext(result));
12412 	dns_zone_detach(&zone);
12413 	return (result);
12414 }
12415 
12416 /*
12417  * Act on a "freeze" or "thaw" command from the command channel.
12418  */
12419 isc_result_t
named_server_freeze(named_server_t * server,bool freeze,isc_lex_t * lex,isc_buffer_t ** text)12420 named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex,
12421 		    isc_buffer_t **text) {
12422 	isc_result_t result, tresult;
12423 	dns_zone_t *mayberaw = NULL, *raw = NULL;
12424 	dns_zonetype_t type;
12425 	char classstr[DNS_RDATACLASS_FORMATSIZE];
12426 	char zonename[DNS_NAME_FORMATSIZE];
12427 	dns_view_t *view;
12428 	const char *vname, *sep;
12429 	bool frozen;
12430 	const char *msg = NULL;
12431 
12432 	REQUIRE(text != NULL);
12433 
12434 	result = zone_from_args(server, lex, NULL, &mayberaw, NULL, text, true);
12435 	if (result != ISC_R_SUCCESS) {
12436 		return (result);
12437 	}
12438 	if (mayberaw == NULL) {
12439 		result = isc_task_beginexclusive(server->task);
12440 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
12441 		tresult = ISC_R_SUCCESS;
12442 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12443 		     view = ISC_LIST_NEXT(view, link))
12444 		{
12445 			result = dns_view_freezezones(view, freeze);
12446 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12447 			{
12448 				tresult = result;
12449 			}
12450 		}
12451 		isc_task_endexclusive(server->task);
12452 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12453 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12454 			      "%s all zones: %s",
12455 			      freeze ? "freezing" : "thawing",
12456 			      isc_result_totext(tresult));
12457 		return (tresult);
12458 	}
12459 	dns_zone_getraw(mayberaw, &raw);
12460 	if (raw != NULL) {
12461 		dns_zone_detach(&mayberaw);
12462 		dns_zone_attach(raw, &mayberaw);
12463 		dns_zone_detach(&raw);
12464 	}
12465 	type = dns_zone_gettype(mayberaw);
12466 	if (type != dns_zone_primary) {
12467 		dns_zone_detach(&mayberaw);
12468 		return (DNS_R_NOTMASTER);
12469 	}
12470 
12471 	if (freeze && !dns_zone_isdynamic(mayberaw, true)) {
12472 		dns_zone_detach(&mayberaw);
12473 		return (DNS_R_NOTDYNAMIC);
12474 	}
12475 
12476 	result = isc_task_beginexclusive(server->task);
12477 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12478 	frozen = dns_zone_getupdatedisabled(mayberaw);
12479 	if (freeze) {
12480 		if (frozen) {
12481 			msg = "WARNING: The zone was already frozen.\n"
12482 			      "Someone else may be editing it or "
12483 			      "it may still be re-loading.";
12484 			result = DNS_R_FROZEN;
12485 		}
12486 		if (result == ISC_R_SUCCESS) {
12487 			result = dns_zone_flush(mayberaw);
12488 			if (result != ISC_R_SUCCESS) {
12489 				msg = "Flushing the zone updates to "
12490 				      "disk failed.";
12491 			}
12492 		}
12493 		if (result == ISC_R_SUCCESS) {
12494 			dns_zone_setupdatedisabled(mayberaw, freeze);
12495 		}
12496 	} else {
12497 		if (frozen) {
12498 			result = dns_zone_loadandthaw(mayberaw);
12499 			switch (result) {
12500 			case ISC_R_SUCCESS:
12501 			case DNS_R_UPTODATE:
12502 				msg = "The zone reload and thaw was "
12503 				      "successful.";
12504 				result = ISC_R_SUCCESS;
12505 				break;
12506 			case DNS_R_CONTINUE:
12507 				msg = "A zone reload and thaw was started.\n"
12508 				      "Check the logs to see the result.";
12509 				result = ISC_R_SUCCESS;
12510 				break;
12511 			}
12512 		}
12513 	}
12514 	isc_task_endexclusive(server->task);
12515 
12516 	if (msg != NULL) {
12517 		(void)putstr(text, msg);
12518 		(void)putnull(text);
12519 	}
12520 
12521 	view = dns_zone_getview(mayberaw);
12522 	if (strcmp(view->name, "_default") == 0 ||
12523 	    strcmp(view->name, "_bind") == 0)
12524 	{
12525 		vname = "";
12526 		sep = "";
12527 	} else {
12528 		vname = view->name;
12529 		sep = " ";
12530 	}
12531 	dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr,
12532 			      sizeof(classstr));
12533 	dns_name_format(dns_zone_getorigin(mayberaw), zonename,
12534 			sizeof(zonename));
12535 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12536 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12537 		      "%s zone '%s/%s'%s%s: %s",
12538 		      freeze ? "freezing" : "thawing", zonename, classstr, sep,
12539 		      vname, isc_result_totext(result));
12540 	dns_zone_detach(&mayberaw);
12541 	return (result);
12542 }
12543 
12544 #ifdef HAVE_LIBSCF
12545 /*
12546  * This function adds a message for rndc to echo if named
12547  * is managed by smf and is also running chroot.
12548  */
12549 isc_result_t
named_smf_add_message(isc_buffer_t ** text)12550 named_smf_add_message(isc_buffer_t **text) {
12551 	REQUIRE(text != NULL);
12552 
12553 	return (putstr(text, "use svcadm(1M) to manage named"));
12554 }
12555 #endif /* HAVE_LIBSCF */
12556 
12557 #ifndef HAVE_LMDB
12558 
12559 /*
12560  * Emit a comment at the top of the nzf file containing the viewname
12561  * Expects the fp to already be open for writing
12562  */
12563 #define HEADER1 "# New zone file for view: "
12564 #define HEADER2                                                     \
12565 	"\n# This file contains configuration for zones added by\n" \
12566 	"# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
12567 static isc_result_t
add_comment(FILE * fp,const char * viewname)12568 add_comment(FILE *fp, const char *viewname) {
12569 	isc_result_t result;
12570 	CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
12571 	CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
12572 	CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
12573 cleanup:
12574 	return (result);
12575 }
12576 
12577 static void
dumpzone(void * arg,const char * buf,int len)12578 dumpzone(void *arg, const char *buf, int len) {
12579 	FILE *fp = arg;
12580 
12581 	(void)isc_stdio_write(buf, len, 1, fp, NULL);
12582 }
12583 
12584 static isc_result_t
nzf_append(dns_view_t * view,const cfg_obj_t * zconfig)12585 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
12586 	isc_result_t result;
12587 	off_t offset;
12588 	FILE *fp = NULL;
12589 	bool offsetok = false;
12590 
12591 	LOCK(&view->new_zone_lock);
12592 
12593 	CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
12594 	CHECK(isc_stdio_seek(fp, 0, SEEK_END));
12595 
12596 	CHECK(isc_stdio_tell(fp, &offset));
12597 	offsetok = true;
12598 	if (offset == 0) {
12599 		CHECK(add_comment(fp, view->name));
12600 	}
12601 
12602 	CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
12603 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
12604 	CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
12605 	CHECK(isc_stdio_flush(fp));
12606 	result = isc_stdio_close(fp);
12607 	fp = NULL;
12608 
12609 cleanup:
12610 	if (fp != NULL) {
12611 		(void)isc_stdio_close(fp);
12612 		if (offsetok) {
12613 			isc_result_t result2;
12614 
12615 			result2 = isc_file_truncate(view->new_zone_file,
12616 						    offset);
12617 			if (result2 != ISC_R_SUCCESS) {
12618 				isc_log_write(
12619 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12620 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12621 					"Error truncating NZF file '%s' "
12622 					"during rollback from append: "
12623 					"%s",
12624 					view->new_zone_file,
12625 					isc_result_totext(result2));
12626 			}
12627 		}
12628 	}
12629 	UNLOCK(&view->new_zone_lock);
12630 	return (result);
12631 }
12632 
12633 static isc_result_t
nzf_writeconf(const cfg_obj_t * config,dns_view_t * view)12634 nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
12635 	const cfg_obj_t *zl = NULL;
12636 	cfg_list_t *list;
12637 	const cfg_listelt_t *elt;
12638 
12639 	FILE *fp = NULL;
12640 	char tmp[1024];
12641 	isc_result_t result;
12642 
12643 	result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp,
12644 				   sizeof(tmp));
12645 	if (result == ISC_R_SUCCESS) {
12646 		result = isc_file_openunique(tmp, &fp);
12647 	}
12648 	if (result != ISC_R_SUCCESS) {
12649 		return (result);
12650 	}
12651 
12652 	cfg_map_get(config, "zone", &zl);
12653 	if (!cfg_obj_islist(zl)) {
12654 		CHECK(ISC_R_FAILURE);
12655 	}
12656 
12657 	DE_CONST(&zl->value.list, list);
12658 
12659 	CHECK(add_comment(fp, view->name)); /* force a comment */
12660 
12661 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
12662 	     elt = ISC_LIST_NEXT(elt, link))
12663 	{
12664 		const cfg_obj_t *zconfig = cfg_listelt_value(elt);
12665 
12666 		CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
12667 		cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
12668 		CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
12669 	}
12670 
12671 	CHECK(isc_stdio_flush(fp));
12672 	result = isc_stdio_close(fp);
12673 	fp = NULL;
12674 	if (result != ISC_R_SUCCESS) {
12675 		goto cleanup;
12676 	}
12677 	CHECK(isc_file_rename(tmp, view->new_zone_file));
12678 	return (result);
12679 
12680 cleanup:
12681 	if (fp != NULL) {
12682 		(void)isc_stdio_close(fp);
12683 	}
12684 	(void)isc_file_remove(tmp);
12685 	return (result);
12686 }
12687 
12688 #else /* HAVE_LMDB */
12689 
12690 static void
nzd_setkey(MDB_val * key,dns_name_t * name,char * namebuf,size_t buflen)12691 nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
12692 	dns_fixedname_t fixed;
12693 
12694 	dns_fixedname_init(&fixed);
12695 	dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
12696 	dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
12697 
12698 	key->mv_data = namebuf;
12699 	key->mv_size = strlen(namebuf);
12700 }
12701 
12702 static void
dumpzone(void * arg,const char * buf,int len)12703 dumpzone(void *arg, const char *buf, int len) {
12704 	ns_dzarg_t *dzarg = arg;
12705 	isc_result_t result;
12706 
12707 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
12708 
12709 	result = putmem(dzarg->text, buf, len);
12710 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
12711 		dzarg->result = result;
12712 	}
12713 }
12714 
12715 static isc_result_t
nzd_save(MDB_txn ** txnp,MDB_dbi dbi,dns_zone_t * zone,const cfg_obj_t * zconfig)12716 nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
12717 	 const cfg_obj_t *zconfig) {
12718 	isc_result_t result;
12719 	int status;
12720 	dns_view_t *view;
12721 	bool commit = false;
12722 	isc_buffer_t *text = NULL;
12723 	char namebuf[1024];
12724 	MDB_val key, data;
12725 	ns_dzarg_t dzarg;
12726 
12727 	view = dns_zone_getview(zone);
12728 
12729 	nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
12730 
12731 	if (zconfig == NULL) {
12732 		/* We're deleting the zone from the database */
12733 		status = mdb_del(*txnp, dbi, &key, NULL);
12734 		if (status != MDB_SUCCESS && status != MDB_NOTFOUND) {
12735 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12736 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12737 				      "Error deleting zone %s "
12738 				      "from NZD database: %s",
12739 				      namebuf, mdb_strerror(status));
12740 			result = ISC_R_FAILURE;
12741 			goto cleanup;
12742 		} else if (status != MDB_NOTFOUND) {
12743 			commit = true;
12744 		}
12745 	} else {
12746 		/* We're creating or overwriting the zone */
12747 		const cfg_obj_t *zoptions;
12748 
12749 		isc_buffer_allocate(view->mctx, &text, 256);
12750 
12751 		zoptions = cfg_tuple_get(zconfig, "options");
12752 		if (zoptions == NULL) {
12753 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12754 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12755 				      "Unable to get options from config in "
12756 				      "nzd_save()");
12757 			result = ISC_R_FAILURE;
12758 			goto cleanup;
12759 		}
12760 
12761 		dzarg.magic = DZARG_MAGIC;
12762 		dzarg.text = &text;
12763 		dzarg.result = ISC_R_SUCCESS;
12764 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
12765 		if (dzarg.result != ISC_R_SUCCESS) {
12766 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12767 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12768 				      "Error writing zone config to "
12769 				      "buffer in nzd_save(): %s",
12770 				      isc_result_totext(dzarg.result));
12771 			result = dzarg.result;
12772 			goto cleanup;
12773 		}
12774 
12775 		data.mv_data = isc_buffer_base(text);
12776 		data.mv_size = isc_buffer_usedlength(text);
12777 
12778 		status = mdb_put(*txnp, dbi, &key, &data, 0);
12779 		if (status != MDB_SUCCESS) {
12780 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12781 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12782 				      "Error inserting zone in "
12783 				      "NZD database: %s",
12784 				      mdb_strerror(status));
12785 			result = ISC_R_FAILURE;
12786 			goto cleanup;
12787 		}
12788 
12789 		commit = true;
12790 	}
12791 
12792 	result = ISC_R_SUCCESS;
12793 
12794 cleanup:
12795 	if (!commit || result != ISC_R_SUCCESS) {
12796 		(void)mdb_txn_abort(*txnp);
12797 	} else {
12798 		status = mdb_txn_commit(*txnp);
12799 		if (status != MDB_SUCCESS) {
12800 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12801 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12802 				      "Error committing "
12803 				      "NZD database: %s",
12804 				      mdb_strerror(status));
12805 			result = ISC_R_FAILURE;
12806 		}
12807 	}
12808 	*txnp = NULL;
12809 
12810 	if (text != NULL) {
12811 		isc_buffer_free(&text);
12812 	}
12813 
12814 	return (result);
12815 }
12816 
12817 /*
12818  * Check whether the new zone database for 'view' can be opened for writing.
12819  *
12820  * Caller must hold 'view->new_zone_lock'.
12821  */
12822 static isc_result_t
nzd_writable(dns_view_t * view)12823 nzd_writable(dns_view_t *view) {
12824 	isc_result_t result = ISC_R_SUCCESS;
12825 	int status;
12826 	MDB_dbi dbi;
12827 	MDB_txn *txn = NULL;
12828 
12829 	REQUIRE(view != NULL);
12830 
12831 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn);
12832 	if (status != MDB_SUCCESS) {
12833 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12834 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12835 			      "mdb_txn_begin: %s", mdb_strerror(status));
12836 		return (ISC_R_FAILURE);
12837 	}
12838 
12839 	status = mdb_dbi_open(txn, NULL, 0, &dbi);
12840 	if (status != MDB_SUCCESS) {
12841 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12842 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12843 			      "mdb_dbi_open: %s", mdb_strerror(status));
12844 		result = ISC_R_FAILURE;
12845 	}
12846 
12847 	mdb_txn_abort(txn);
12848 	return (result);
12849 }
12850 
12851 /*
12852  * Open the new zone database for 'view' and start a transaction for it.
12853  *
12854  * Caller must hold 'view->new_zone_lock'.
12855  */
12856 static isc_result_t
nzd_open(dns_view_t * view,unsigned int flags,MDB_txn ** txnp,MDB_dbi * dbi)12857 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
12858 	int status;
12859 	MDB_txn *txn = NULL;
12860 
12861 	REQUIRE(view != NULL);
12862 	REQUIRE(txnp != NULL && *txnp == NULL);
12863 	REQUIRE(dbi != NULL);
12864 
12865 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn);
12866 	if (status != MDB_SUCCESS) {
12867 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12868 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12869 			      "mdb_txn_begin: %s", mdb_strerror(status));
12870 		goto cleanup;
12871 	}
12872 
12873 	status = mdb_dbi_open(txn, NULL, 0, dbi);
12874 	if (status != MDB_SUCCESS) {
12875 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12876 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12877 			      "mdb_dbi_open: %s", mdb_strerror(status));
12878 		goto cleanup;
12879 	}
12880 
12881 	*txnp = txn;
12882 
12883 cleanup:
12884 	if (status != MDB_SUCCESS) {
12885 		if (txn != NULL) {
12886 			mdb_txn_abort(txn);
12887 		}
12888 		return (ISC_R_FAILURE);
12889 	}
12890 
12891 	return (ISC_R_SUCCESS);
12892 }
12893 
12894 /*
12895  * nzd_env_close() and nzd_env_reopen are a kluge to address the
12896  * problem of an NZD file possibly being created before we drop
12897  * root privileges.
12898  */
12899 static void
nzd_env_close(dns_view_t * view)12900 nzd_env_close(dns_view_t *view) {
12901 	const char *dbpath = NULL;
12902 	char dbpath_copy[PATH_MAX];
12903 	char lockpath[PATH_MAX];
12904 	int status, ret;
12905 
12906 	if (view->new_zone_dbenv == NULL) {
12907 		return;
12908 	}
12909 
12910 	status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
12911 	INSIST(status == MDB_SUCCESS);
12912 	snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
12913 	strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
12914 	mdb_env_close((MDB_env *)view->new_zone_dbenv);
12915 
12916 	/*
12917 	 * Database files must be owned by the eventual user, not by root.
12918 	 */
12919 	ret = chown(dbpath_copy, ns_os_uid(), -1);
12920 	UNUSED(ret);
12921 
12922 	/*
12923 	 * Some platforms need the lockfile not to exist when we reopen the
12924 	 * environment.
12925 	 */
12926 	(void)isc_file_remove(lockpath);
12927 
12928 	view->new_zone_dbenv = NULL;
12929 }
12930 
12931 static isc_result_t
nzd_env_reopen(dns_view_t * view)12932 nzd_env_reopen(dns_view_t *view) {
12933 	isc_result_t result;
12934 	MDB_env *env = NULL;
12935 	int status;
12936 
12937 	if (view->new_zone_db == NULL) {
12938 		return (ISC_R_SUCCESS);
12939 	}
12940 
12941 	nzd_env_close(view);
12942 
12943 	status = mdb_env_create(&env);
12944 	if (status != MDB_SUCCESS) {
12945 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
12946 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
12947 			      "mdb_env_create failed: %s",
12948 			      mdb_strerror(status));
12949 		CHECK(ISC_R_FAILURE);
12950 	}
12951 
12952 	if (view->new_zone_mapsize != 0ULL) {
12953 		status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
12954 		if (status != MDB_SUCCESS) {
12955 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
12956 				      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
12957 				      "mdb_env_set_mapsize failed: %s",
12958 				      mdb_strerror(status));
12959 			CHECK(ISC_R_FAILURE);
12960 		}
12961 	}
12962 
12963 	status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
12964 	if (status != MDB_SUCCESS) {
12965 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
12966 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
12967 			      "mdb_env_open of '%s' failed: %s",
12968 			      view->new_zone_db, mdb_strerror(status));
12969 		CHECK(ISC_R_FAILURE);
12970 	}
12971 
12972 	view->new_zone_dbenv = env;
12973 	env = NULL;
12974 	result = ISC_R_SUCCESS;
12975 
12976 cleanup:
12977 	if (env != NULL) {
12978 		mdb_env_close(env);
12979 	}
12980 	return (result);
12981 }
12982 
12983 /*
12984  * If 'commit' is true, commit the new zone database transaction pointed to by
12985  * 'txnp'; otherwise, abort that transaction.
12986  *
12987  * Caller must hold 'view->new_zone_lock' for the view that the transaction
12988  * pointed to by 'txnp' was started for.
12989  */
12990 static isc_result_t
nzd_close(MDB_txn ** txnp,bool commit)12991 nzd_close(MDB_txn **txnp, bool commit) {
12992 	isc_result_t result = ISC_R_SUCCESS;
12993 	int status;
12994 
12995 	REQUIRE(txnp != NULL);
12996 
12997 	if (*txnp != NULL) {
12998 		if (commit) {
12999 			status = mdb_txn_commit(*txnp);
13000 			if (status != MDB_SUCCESS) {
13001 				result = ISC_R_FAILURE;
13002 			}
13003 		} else {
13004 			mdb_txn_abort(*txnp);
13005 		}
13006 		*txnp = NULL;
13007 	}
13008 
13009 	return (result);
13010 }
13011 
13012 /*
13013  * Count the zones configured in the new zone database for 'view' and store the
13014  * result in 'countp'.
13015  *
13016  * Caller must hold 'view->new_zone_lock'.
13017  */
13018 static isc_result_t
nzd_count(dns_view_t * view,int * countp)13019 nzd_count(dns_view_t *view, int *countp) {
13020 	isc_result_t result;
13021 	int status;
13022 	MDB_txn *txn = NULL;
13023 	MDB_dbi dbi;
13024 	MDB_stat statbuf;
13025 
13026 	REQUIRE(countp != NULL);
13027 
13028 	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
13029 	if (result != ISC_R_SUCCESS) {
13030 		goto cleanup;
13031 	}
13032 
13033 	status = mdb_stat(txn, dbi, &statbuf);
13034 	if (status != MDB_SUCCESS) {
13035 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13036 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13037 			      "mdb_stat: %s", mdb_strerror(status));
13038 		result = ISC_R_FAILURE;
13039 		goto cleanup;
13040 	}
13041 
13042 	*countp = statbuf.ms_entries;
13043 
13044 cleanup:
13045 	(void)nzd_close(&txn, false);
13046 
13047 	return (result);
13048 }
13049 
13050 /*
13051  * Migrate zone configuration from an NZF file to an NZD database.
13052  * Caller must hold view->new_zone_lock.
13053  */
13054 static isc_result_t
migrate_nzf(dns_view_t * view)13055 migrate_nzf(dns_view_t *view) {
13056 	isc_result_t result;
13057 	cfg_obj_t *nzf_config = NULL;
13058 	int status, n;
13059 	isc_buffer_t *text = NULL;
13060 	bool commit = false;
13061 	const cfg_obj_t *zonelist;
13062 	const cfg_listelt_t *element;
13063 	char tempname[PATH_MAX];
13064 	MDB_txn *txn = NULL;
13065 	MDB_dbi dbi;
13066 	MDB_val key, data;
13067 	ns_dzarg_t dzarg;
13068 
13069 	/*
13070 	 * If NZF file doesn't exist, or NZD DB exists and already
13071 	 * has data, return without attempting migration.
13072 	 */
13073 	if (!isc_file_exists(view->new_zone_file)) {
13074 		result = ISC_R_SUCCESS;
13075 		goto cleanup;
13076 	}
13077 
13078 	result = nzd_count(view, &n);
13079 	if (result == ISC_R_SUCCESS && n > 0) {
13080 		result = ISC_R_SUCCESS;
13081 		goto cleanup;
13082 	}
13083 
13084 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13085 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13086 		      "Migrating zones from NZF file '%s' to "
13087 		      "NZD database '%s'",
13088 		      view->new_zone_file, view->new_zone_db);
13089 	/*
13090 	 * Instead of blindly copying lines, we parse the NZF file using
13091 	 * the configuration parser, because it validates it against the
13092 	 * config type, giving us a guarantee that valid configuration
13093 	 * will be written to DB.
13094 	 */
13095 	cfg_parser_reset(named_g_addparser);
13096 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
13097 				&cfg_type_addzoneconf, &nzf_config);
13098 	if (result != ISC_R_SUCCESS) {
13099 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13100 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13101 			      "Error parsing NZF file '%s': %s",
13102 			      view->new_zone_file, isc_result_totext(result));
13103 		goto cleanup;
13104 	}
13105 
13106 	zonelist = NULL;
13107 	CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
13108 	if (!cfg_obj_islist(zonelist)) {
13109 		CHECK(ISC_R_FAILURE);
13110 	}
13111 
13112 	CHECK(nzd_open(view, 0, &txn, &dbi));
13113 
13114 	isc_buffer_allocate(view->mctx, &text, 256);
13115 
13116 	for (element = cfg_list_first(zonelist); element != NULL;
13117 	     element = cfg_list_next(element))
13118 	{
13119 		const cfg_obj_t *zconfig;
13120 		const cfg_obj_t *zoptions;
13121 		char zname[DNS_NAME_FORMATSIZE];
13122 		dns_fixedname_t fname;
13123 		dns_name_t *name;
13124 		const char *origin;
13125 		isc_buffer_t b;
13126 
13127 		zconfig = cfg_listelt_value(element);
13128 
13129 		origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
13130 		if (origin == NULL) {
13131 			result = ISC_R_FAILURE;
13132 			goto cleanup;
13133 		}
13134 
13135 		/* Normalize zone name */
13136 		isc_buffer_constinit(&b, origin, strlen(origin));
13137 		isc_buffer_add(&b, strlen(origin));
13138 		name = dns_fixedname_initname(&fname);
13139 		CHECK(dns_name_fromtext(name, &b, dns_rootname,
13140 					DNS_NAME_DOWNCASE, NULL));
13141 		dns_name_format(name, zname, sizeof(zname));
13142 
13143 		key.mv_data = zname;
13144 		key.mv_size = strlen(zname);
13145 
13146 		zoptions = cfg_tuple_get(zconfig, "options");
13147 		if (zoptions == NULL) {
13148 			result = ISC_R_FAILURE;
13149 			goto cleanup;
13150 		}
13151 
13152 		isc_buffer_clear(text);
13153 		dzarg.magic = DZARG_MAGIC;
13154 		dzarg.text = &text;
13155 		dzarg.result = ISC_R_SUCCESS;
13156 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13157 		if (dzarg.result != ISC_R_SUCCESS) {
13158 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13159 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13160 				      "Error writing zone config to "
13161 				      "buffer in migrate_nzf(): %s",
13162 				      isc_result_totext(result));
13163 			result = dzarg.result;
13164 			goto cleanup;
13165 		}
13166 
13167 		data.mv_data = isc_buffer_base(text);
13168 		data.mv_size = isc_buffer_usedlength(text);
13169 
13170 		status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
13171 		if (status != MDB_SUCCESS) {
13172 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13173 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13174 				      "Error inserting zone in "
13175 				      "NZD database: %s",
13176 				      mdb_strerror(status));
13177 			result = ISC_R_FAILURE;
13178 			goto cleanup;
13179 		}
13180 
13181 		commit = true;
13182 	}
13183 
13184 	result = ISC_R_SUCCESS;
13185 
13186 	/*
13187 	 * Leaving the NZF file in place is harmless as we won't use it
13188 	 * if an NZD database is found for the view. But we rename NZF file
13189 	 * to a backup name here.
13190 	 */
13191 	strlcpy(tempname, view->new_zone_file, sizeof(tempname));
13192 	if (strlen(tempname) < sizeof(tempname) - 1) {
13193 		strlcat(tempname, "~", sizeof(tempname));
13194 		isc_file_rename(view->new_zone_file, tempname);
13195 	}
13196 
13197 cleanup:
13198 	if (result != ISC_R_SUCCESS) {
13199 		(void)nzd_close(&txn, false);
13200 	} else {
13201 		result = nzd_close(&txn, commit);
13202 	}
13203 
13204 	if (text != NULL) {
13205 		isc_buffer_free(&text);
13206 	}
13207 
13208 	if (nzf_config != NULL) {
13209 		cfg_obj_destroy(named_g_addparser, &nzf_config);
13210 	}
13211 
13212 	return (result);
13213 }
13214 
13215 #endif /* HAVE_LMDB */
13216 
13217 static isc_result_t
newzone_parse(named_server_t * server,char * command,dns_view_t ** viewp,cfg_obj_t ** zoneconfp,const cfg_obj_t ** zoneobjp,bool * redirectp,isc_buffer_t ** text)13218 newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
13219 	      cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
13220 	      bool *redirectp, isc_buffer_t **text) {
13221 	isc_result_t result;
13222 	isc_buffer_t argbuf;
13223 	bool redirect = false;
13224 	cfg_obj_t *zoneconf = NULL;
13225 	const cfg_obj_t *zlist = NULL;
13226 	const cfg_obj_t *zoneobj = NULL;
13227 	const cfg_obj_t *zoptions = NULL;
13228 	const cfg_obj_t *obj = NULL;
13229 	const char *viewname = NULL;
13230 	dns_rdataclass_t rdclass;
13231 	dns_view_t *view = NULL;
13232 	const char *bn = NULL;
13233 
13234 	REQUIRE(viewp != NULL && *viewp == NULL);
13235 	REQUIRE(zoneobjp != NULL && *zoneobjp == NULL);
13236 	REQUIRE(zoneconfp != NULL && *zoneconfp == NULL);
13237 	REQUIRE(redirectp != NULL);
13238 
13239 	/* Try to parse the argument string */
13240 	isc_buffer_init(&argbuf, command, (unsigned int)strlen(command));
13241 	isc_buffer_add(&argbuf, strlen(command));
13242 
13243 	if (strncasecmp(command, "add", 3) == 0) {
13244 		bn = "addzone";
13245 	} else if (strncasecmp(command, "mod", 3) == 0) {
13246 		bn = "modzone";
13247 	} else {
13248 		UNREACHABLE();
13249 	}
13250 
13251 	/*
13252 	 * Convert the "addzone" or "modzone" to just "zone", for
13253 	 * the benefit of the parser
13254 	 */
13255 	isc_buffer_forward(&argbuf, 3);
13256 
13257 	cfg_parser_reset(named_g_addparser);
13258 	CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0,
13259 			       &cfg_type_addzoneconf, 0, &zoneconf));
13260 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
13261 	if (!cfg_obj_islist(zlist)) {
13262 		CHECK(ISC_R_FAILURE);
13263 	}
13264 
13265 	/* For now we only support adding one zone at a time */
13266 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
13267 
13268 	/* Check the zone type for ones that are not supported by addzone. */
13269 	zoptions = cfg_tuple_get(zoneobj, "options");
13270 
13271 	obj = NULL;
13272 	(void)cfg_map_get(zoptions, "type", &obj);
13273 	if (obj == NULL) {
13274 		(void)cfg_map_get(zoptions, "in-view", &obj);
13275 		if (obj != NULL) {
13276 			(void)putstr(text, "'in-view' zones not supported by ");
13277 			(void)putstr(text, bn);
13278 		} else {
13279 			(void)putstr(text, "zone type not specified");
13280 		}
13281 		CHECK(ISC_R_FAILURE);
13282 	}
13283 
13284 	if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
13285 	    strcasecmp(cfg_obj_asstring(obj), "forward") == 0 ||
13286 	    strcasecmp(cfg_obj_asstring(obj), "delegation-only") == 0)
13287 	{
13288 		(void)putstr(text, "'");
13289 		(void)putstr(text, cfg_obj_asstring(obj));
13290 		(void)putstr(text, "' zones not supported by ");
13291 		(void)putstr(text, bn);
13292 		CHECK(ISC_R_FAILURE);
13293 	}
13294 
13295 	if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0) {
13296 		redirect = true;
13297 	}
13298 
13299 	/* Make sense of optional class argument */
13300 	obj = cfg_tuple_get(zoneobj, "class");
13301 	CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass));
13302 
13303 	/* Make sense of optional view argument */
13304 	obj = cfg_tuple_get(zoneobj, "view");
13305 	if (obj && cfg_obj_isstring(obj)) {
13306 		viewname = cfg_obj_asstring(obj);
13307 	}
13308 	if (viewname == NULL || *viewname == '\0') {
13309 		viewname = "_default";
13310 	}
13311 	result = dns_viewlist_find(&server->viewlist, viewname, rdclass, &view);
13312 	if (result == ISC_R_NOTFOUND) {
13313 		(void)putstr(text, "no matching view found for '");
13314 		(void)putstr(text, viewname);
13315 		(void)putstr(text, "'");
13316 		goto cleanup;
13317 	} else if (result != ISC_R_SUCCESS) {
13318 		goto cleanup;
13319 	}
13320 
13321 	*viewp = view;
13322 	*zoneobjp = zoneobj;
13323 	*zoneconfp = zoneconf;
13324 	*redirectp = redirect;
13325 
13326 	return (ISC_R_SUCCESS);
13327 
13328 cleanup:
13329 	if (zoneconf != NULL) {
13330 		cfg_obj_destroy(named_g_addparser, &zoneconf);
13331 	}
13332 	if (view != NULL) {
13333 		dns_view_detach(&view);
13334 	}
13335 
13336 	return (result);
13337 }
13338 
13339 static isc_result_t
delete_zoneconf(dns_view_t * view,cfg_parser_t * pctx,const cfg_obj_t * config,const dns_name_t * zname,nzfwriter_t nzfwriter)13340 delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config,
13341 		const dns_name_t *zname, nzfwriter_t nzfwriter) {
13342 	isc_result_t result = ISC_R_NOTFOUND;
13343 	const cfg_listelt_t *elt = NULL;
13344 	const cfg_obj_t *zl = NULL;
13345 	cfg_list_t *list;
13346 	dns_fixedname_t myfixed;
13347 	dns_name_t *myname;
13348 
13349 	REQUIRE(view != NULL);
13350 	REQUIRE(pctx != NULL);
13351 	REQUIRE(config != NULL);
13352 	REQUIRE(zname != NULL);
13353 
13354 	LOCK(&view->new_zone_lock);
13355 
13356 	cfg_map_get(config, "zone", &zl);
13357 
13358 	if (!cfg_obj_islist(zl)) {
13359 		CHECK(ISC_R_FAILURE);
13360 	}
13361 
13362 	DE_CONST(&zl->value.list, list);
13363 
13364 	myname = dns_fixedname_initname(&myfixed);
13365 
13366 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13367 	     elt = ISC_LIST_NEXT(elt, link))
13368 	{
13369 		const cfg_obj_t *zconf = cfg_listelt_value(elt);
13370 		const char *zn;
13371 		cfg_listelt_t *e;
13372 
13373 		zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
13374 		result = dns_name_fromstring(myname, zn, 0, NULL);
13375 		if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname)) {
13376 			continue;
13377 		}
13378 
13379 		DE_CONST(elt, e);
13380 		ISC_LIST_UNLINK(*list, e, link);
13381 		cfg_obj_destroy(pctx, &e->obj);
13382 		isc_mem_put(pctx->mctx, e, sizeof(*e));
13383 		result = ISC_R_SUCCESS;
13384 		break;
13385 	}
13386 
13387 	/*
13388 	 * Write config to NZF file if appropriate
13389 	 */
13390 	if (nzfwriter != NULL && view->new_zone_file != NULL) {
13391 		result = nzfwriter(config, view);
13392 	}
13393 
13394 cleanup:
13395 	UNLOCK(&view->new_zone_lock);
13396 	return (result);
13397 }
13398 
13399 static isc_result_t
do_addzone(named_server_t * server,ns_cfgctx_t * cfg,dns_view_t * view,dns_name_t * name,cfg_obj_t * zoneconf,const cfg_obj_t * zoneobj,bool redirect,isc_buffer_t ** text)13400 do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13401 	   dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
13402 	   bool redirect, isc_buffer_t **text) {
13403 	isc_result_t result, tresult;
13404 	dns_zone_t *zone = NULL;
13405 #ifndef HAVE_LMDB
13406 	FILE *fp = NULL;
13407 	bool cleanup_config = false;
13408 #else /* HAVE_LMDB */
13409 	MDB_txn *txn = NULL;
13410 	MDB_dbi dbi;
13411 	bool locked = false;
13412 
13413 	UNUSED(zoneconf);
13414 #endif
13415 
13416 	/* Zone shouldn't already exist */
13417 	if (redirect) {
13418 		result = (view->redirect != NULL) ? ISC_R_SUCCESS
13419 						  : ISC_R_NOTFOUND;
13420 	} else {
13421 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13422 	}
13423 	if (result == ISC_R_SUCCESS) {
13424 		result = ISC_R_EXISTS;
13425 		goto cleanup;
13426 	} else if (result == DNS_R_PARTIALMATCH) {
13427 		/* Create our sub-zone anyway */
13428 		dns_zone_detach(&zone);
13429 		zone = NULL;
13430 	} else if (result != ISC_R_NOTFOUND) {
13431 		goto cleanup;
13432 	}
13433 
13434 	result = isc_task_beginexclusive(server->task);
13435 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
13436 
13437 #ifndef HAVE_LMDB
13438 	/*
13439 	 * Make sure we can open the configuration save file
13440 	 */
13441 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
13442 	if (result != ISC_R_SUCCESS) {
13443 		isc_task_endexclusive(server->task);
13444 		TCHECK(putstr(text, "unable to create '"));
13445 		TCHECK(putstr(text, view->new_zone_file));
13446 		TCHECK(putstr(text, "': "));
13447 		TCHECK(putstr(text, isc_result_totext(result)));
13448 		goto cleanup;
13449 	}
13450 
13451 	(void)isc_stdio_close(fp);
13452 	fp = NULL;
13453 #else  /* HAVE_LMDB */
13454 	LOCK(&view->new_zone_lock);
13455 	locked = true;
13456 	/* Make sure we can open the NZD database */
13457 	result = nzd_writable(view);
13458 	if (result != ISC_R_SUCCESS) {
13459 		isc_task_endexclusive(server->task);
13460 		TCHECK(putstr(text, "unable to open NZD database for '"));
13461 		TCHECK(putstr(text, view->new_zone_db));
13462 		TCHECK(putstr(text, "'"));
13463 		result = ISC_R_FAILURE;
13464 		goto cleanup;
13465 	}
13466 #endif /* HAVE_LMDB */
13467 
13468 	/* Mark view unfrozen and configure zone */
13469 	dns_view_thaw(view);
13470 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
13471 				server->mctx, view, &server->viewlist,
13472 				&server->kasplist, cfg->actx, true, false,
13473 				false);
13474 	dns_view_freeze(view);
13475 
13476 	isc_task_endexclusive(server->task);
13477 
13478 	if (result != ISC_R_SUCCESS) {
13479 		TCHECK(putstr(text, "configure_zone failed: "));
13480 		TCHECK(putstr(text, isc_result_totext(result)));
13481 		goto cleanup;
13482 	}
13483 
13484 	/* Is it there yet? */
13485 	if (redirect) {
13486 		if (view->redirect == NULL) {
13487 			CHECK(ISC_R_NOTFOUND);
13488 		}
13489 		dns_zone_attach(view->redirect, &zone);
13490 	} else {
13491 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13492 		if (result != ISC_R_SUCCESS) {
13493 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13494 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13495 				      "added new zone was not found: %s",
13496 				      isc_result_totext(result));
13497 			goto cleanup;
13498 		}
13499 	}
13500 
13501 #ifndef HAVE_LMDB
13502 	/*
13503 	 * If there wasn't a previous newzone config, just save the one
13504 	 * we've created. If there was a previous one, merge the new
13505 	 * zone into it.
13506 	 */
13507 	if (cfg->nzf_config == NULL) {
13508 		cfg_obj_attach(zoneconf, &cfg->nzf_config);
13509 	} else {
13510 		cfg_obj_t *z;
13511 		DE_CONST(zoneobj, z);
13512 		CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z,
13513 					"zone"));
13514 	}
13515 	cleanup_config = true;
13516 #endif /* HAVE_LMDB */
13517 
13518 	/*
13519 	 * Load the zone from the master file.  If this fails, we'll
13520 	 * need to undo the configuration we've done already.
13521 	 */
13522 	result = dns_zone_load(zone, true);
13523 	if (result != ISC_R_SUCCESS) {
13524 		dns_db_t *dbp = NULL;
13525 
13526 		TCHECK(putstr(text, "dns_zone_loadnew failed: "));
13527 		TCHECK(putstr(text, isc_result_totext(result)));
13528 
13529 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13530 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13531 			      "addzone failed; reverting.");
13532 
13533 		/* If the zone loaded partially, unload it */
13534 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13535 			dns_db_detach(&dbp);
13536 			dns_zone_unload(zone);
13537 		}
13538 
13539 		/* Remove the zone from the zone table */
13540 		dns_zt_unmount(view->zonetable, zone);
13541 		goto cleanup;
13542 	}
13543 
13544 	/* Flag the zone as having been added at runtime */
13545 	dns_zone_setadded(zone, true);
13546 
13547 #ifdef HAVE_LMDB
13548 	/* Save the new zone configuration into the NZD */
13549 	CHECK(nzd_open(view, 0, &txn, &dbi));
13550 	CHECK(nzd_save(&txn, dbi, zone, zoneobj));
13551 #else  /* ifdef HAVE_LMDB */
13552 	/* Append the zone configuration to the NZF */
13553 	result = nzf_append(view, zoneobj);
13554 #endif /* HAVE_LMDB */
13555 
13556 cleanup:
13557 
13558 #ifndef HAVE_LMDB
13559 	if (fp != NULL) {
13560 		(void)isc_stdio_close(fp);
13561 	}
13562 	if (result != ISC_R_SUCCESS && cleanup_config) {
13563 		tresult = delete_zoneconf(view, cfg->add_parser,
13564 					  cfg->nzf_config, name, NULL);
13565 		RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
13566 	}
13567 #else  /* HAVE_LMDB */
13568 	if (txn != NULL) {
13569 		(void)nzd_close(&txn, false);
13570 	}
13571 	if (locked) {
13572 		UNLOCK(&view->new_zone_lock);
13573 	}
13574 #endif /* HAVE_LMDB */
13575 
13576 	if (zone != NULL) {
13577 		dns_zone_detach(&zone);
13578 	}
13579 
13580 	return (result);
13581 }
13582 
13583 static isc_result_t
do_modzone(named_server_t * server,ns_cfgctx_t * cfg,dns_view_t * view,dns_name_t * name,const char * zname,const cfg_obj_t * zoneobj,bool redirect,isc_buffer_t ** text)13584 do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13585 	   dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
13586 	   bool redirect, isc_buffer_t **text) {
13587 	isc_result_t result, tresult;
13588 	dns_zone_t *zone = NULL;
13589 	bool added;
13590 	bool exclusive = false;
13591 #ifndef HAVE_LMDB
13592 	FILE *fp = NULL;
13593 	cfg_obj_t *z;
13594 #else  /* HAVE_LMDB */
13595 	MDB_txn *txn = NULL;
13596 	MDB_dbi dbi;
13597 	bool locked = false;
13598 #endif /* HAVE_LMDB */
13599 
13600 	/* Zone must already exist */
13601 	if (redirect) {
13602 		if (view->redirect != NULL) {
13603 			dns_zone_attach(view->redirect, &zone);
13604 			result = ISC_R_SUCCESS;
13605 		} else {
13606 			result = ISC_R_NOTFOUND;
13607 		}
13608 	} else {
13609 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13610 	}
13611 	if (result != ISC_R_SUCCESS) {
13612 		goto cleanup;
13613 	}
13614 
13615 	added = dns_zone_getadded(zone);
13616 	dns_zone_detach(&zone);
13617 
13618 #ifndef HAVE_LMDB
13619 	cfg = (ns_cfgctx_t *)view->new_zone_config;
13620 	if (cfg == NULL) {
13621 		TCHECK(putstr(text, "new zone config is not set"));
13622 		CHECK(ISC_R_FAILURE);
13623 	}
13624 #endif /* ifndef HAVE_LMDB */
13625 
13626 	result = isc_task_beginexclusive(server->task);
13627 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
13628 	exclusive = true;
13629 
13630 #ifndef HAVE_LMDB
13631 	/* Make sure we can open the configuration save file */
13632 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
13633 	if (result != ISC_R_SUCCESS) {
13634 		TCHECK(putstr(text, "unable to open '"));
13635 		TCHECK(putstr(text, view->new_zone_file));
13636 		TCHECK(putstr(text, "': "));
13637 		TCHECK(putstr(text, isc_result_totext(result)));
13638 		goto cleanup;
13639 	}
13640 	(void)isc_stdio_close(fp);
13641 	fp = NULL;
13642 #else  /* HAVE_LMDB */
13643 	LOCK(&view->new_zone_lock);
13644 	locked = true;
13645 	/* Make sure we can open the NZD database */
13646 	result = nzd_writable(view);
13647 	if (result != ISC_R_SUCCESS) {
13648 		TCHECK(putstr(text, "unable to open NZD database for '"));
13649 		TCHECK(putstr(text, view->new_zone_db));
13650 		TCHECK(putstr(text, "'"));
13651 		result = ISC_R_FAILURE;
13652 		goto cleanup;
13653 	}
13654 #endif /* HAVE_LMDB */
13655 
13656 	/* Reconfigure the zone */
13657 	dns_view_thaw(view);
13658 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
13659 				server->mctx, view, &server->viewlist,
13660 				&server->kasplist, cfg->actx, true, false,
13661 				true);
13662 	dns_view_freeze(view);
13663 
13664 	exclusive = false;
13665 	isc_task_endexclusive(server->task);
13666 
13667 	if (result != ISC_R_SUCCESS) {
13668 		TCHECK(putstr(text, "configure_zone failed: "));
13669 		TCHECK(putstr(text, isc_result_totext(result)));
13670 		goto cleanup;
13671 	}
13672 
13673 	/* Is it there yet? */
13674 	if (redirect) {
13675 		if (view->redirect == NULL) {
13676 			CHECK(ISC_R_NOTFOUND);
13677 		}
13678 		dns_zone_attach(view->redirect, &zone);
13679 	} else {
13680 		CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
13681 	}
13682 
13683 #ifndef HAVE_LMDB
13684 	/* Remove old zone from configuration (and NZF file if applicable) */
13685 	if (added) {
13686 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
13687 					 dns_zone_getorigin(zone),
13688 					 nzf_writeconf);
13689 		if (result != ISC_R_SUCCESS) {
13690 			TCHECK(putstr(text, "former zone configuration "
13691 					    "not deleted: "));
13692 			TCHECK(putstr(text, isc_result_totext(result)));
13693 			goto cleanup;
13694 		}
13695 	}
13696 #endif /* HAVE_LMDB */
13697 
13698 	if (!added) {
13699 		if (cfg->vconfig == NULL) {
13700 			result = delete_zoneconf(
13701 				view, cfg->conf_parser, cfg->config,
13702 				dns_zone_getorigin(zone), NULL);
13703 		} else {
13704 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
13705 								  "options");
13706 			result = delete_zoneconf(
13707 				view, cfg->conf_parser, voptions,
13708 				dns_zone_getorigin(zone), NULL);
13709 		}
13710 
13711 		if (result != ISC_R_SUCCESS) {
13712 			TCHECK(putstr(text, "former zone configuration "
13713 					    "not deleted: "));
13714 			TCHECK(putstr(text, isc_result_totext(result)));
13715 			goto cleanup;
13716 		}
13717 	}
13718 
13719 	/* Load the zone from the master file if it needs reloading. */
13720 	result = dns_zone_load(zone, true);
13721 
13722 	/*
13723 	 * Dynamic zones need no reloading, so we can pass this result.
13724 	 */
13725 	if (result == DNS_R_DYNAMIC) {
13726 		result = ISC_R_SUCCESS;
13727 	}
13728 
13729 	if (result != ISC_R_SUCCESS) {
13730 		dns_db_t *dbp = NULL;
13731 
13732 		TCHECK(putstr(text, "failed to load zone '"));
13733 		TCHECK(putstr(text, zname));
13734 		TCHECK(putstr(text, "': "));
13735 		TCHECK(putstr(text, isc_result_totext(result)));
13736 		TCHECK(putstr(text, "\nThe zone is no longer being served. "));
13737 		TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
13738 		TCHECK(putstr(text, "the problem and restore service."));
13739 
13740 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13741 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13742 			      "modzone failed; removing zone.");
13743 
13744 		/* If the zone loaded partially, unload it */
13745 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13746 			dns_db_detach(&dbp);
13747 			dns_zone_unload(zone);
13748 		}
13749 
13750 		/* Remove the zone from the zone table */
13751 		dns_zt_unmount(view->zonetable, zone);
13752 		goto cleanup;
13753 	}
13754 
13755 #ifndef HAVE_LMDB
13756 	/* Store the new zone configuration; also in NZF if applicable */
13757 	DE_CONST(zoneobj, z);
13758 	CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone"));
13759 #endif /* HAVE_LMDB */
13760 
13761 	if (added) {
13762 #ifdef HAVE_LMDB
13763 		CHECK(nzd_open(view, 0, &txn, &dbi));
13764 		CHECK(nzd_save(&txn, dbi, zone, zoneobj));
13765 #else  /* ifdef HAVE_LMDB */
13766 		result = nzf_append(view, zoneobj);
13767 		if (result != ISC_R_SUCCESS) {
13768 			TCHECK(putstr(text, "\nNew zone config not saved: "));
13769 			TCHECK(putstr(text, isc_result_totext(result)));
13770 			goto cleanup;
13771 		}
13772 #endif /* HAVE_LMDB */
13773 
13774 		TCHECK(putstr(text, "zone '"));
13775 		TCHECK(putstr(text, zname));
13776 		TCHECK(putstr(text, "' reconfigured."));
13777 	} else {
13778 		TCHECK(putstr(text, "zone '"));
13779 		TCHECK(putstr(text, zname));
13780 		TCHECK(putstr(text, "' must also be reconfigured in\n"));
13781 		TCHECK(putstr(text, "named.conf to make changes permanent."));
13782 	}
13783 
13784 cleanup:
13785 	if (exclusive) {
13786 		isc_task_endexclusive(server->task);
13787 	}
13788 
13789 #ifndef HAVE_LMDB
13790 	if (fp != NULL) {
13791 		(void)isc_stdio_close(fp);
13792 	}
13793 #else  /* HAVE_LMDB */
13794 	if (txn != NULL) {
13795 		(void)nzd_close(&txn, false);
13796 	}
13797 	if (locked) {
13798 		UNLOCK(&view->new_zone_lock);
13799 	}
13800 #endif /* HAVE_LMDB */
13801 
13802 	if (zone != NULL) {
13803 		dns_zone_detach(&zone);
13804 	}
13805 
13806 	return (result);
13807 }
13808 
13809 /*
13810  * Act on an "addzone" or "modzone" command from the command channel.
13811  */
13812 isc_result_t
named_server_changezone(named_server_t * server,char * command,isc_buffer_t ** text)13813 named_server_changezone(named_server_t *server, char *command,
13814 			isc_buffer_t **text) {
13815 	isc_result_t result;
13816 	bool addzone;
13817 	bool redirect = false;
13818 	ns_cfgctx_t *cfg = NULL;
13819 	cfg_obj_t *zoneconf = NULL;
13820 	const cfg_obj_t *zoneobj = NULL;
13821 	const char *zonename;
13822 	dns_view_t *view = NULL;
13823 	isc_buffer_t buf;
13824 	dns_fixedname_t fname;
13825 	dns_name_t *dnsname;
13826 
13827 	REQUIRE(text != NULL);
13828 
13829 	if (strncasecmp(command, "add", 3) == 0) {
13830 		addzone = true;
13831 	} else {
13832 		INSIST(strncasecmp(command, "mod", 3) == 0);
13833 		addzone = false;
13834 	}
13835 
13836 	CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj,
13837 			    &redirect, text));
13838 
13839 	/* Are we accepting new zones in this view? */
13840 #ifdef HAVE_LMDB
13841 	if (view->new_zone_db == NULL)
13842 #else  /* ifdef HAVE_LMDB */
13843 	if (view->new_zone_file == NULL)
13844 #endif /* HAVE_LMDB */
13845 	{
13846 		(void)putstr(text, "Not allowing new zones in view '");
13847 		(void)putstr(text, view->name);
13848 		(void)putstr(text, "'");
13849 		result = ISC_R_NOPERM;
13850 		goto cleanup;
13851 	}
13852 
13853 	cfg = (ns_cfgctx_t *)view->new_zone_config;
13854 	if (cfg == NULL) {
13855 		result = ISC_R_FAILURE;
13856 		goto cleanup;
13857 	}
13858 
13859 	zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
13860 	isc_buffer_constinit(&buf, zonename, strlen(zonename));
13861 	isc_buffer_add(&buf, strlen(zonename));
13862 
13863 	dnsname = dns_fixedname_initname(&fname);
13864 	CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL));
13865 
13866 	if (redirect) {
13867 		if (!dns_name_equal(dnsname, dns_rootname)) {
13868 			(void)putstr(text, "redirect zones must be called "
13869 					   "\".\"");
13870 			CHECK(ISC_R_FAILURE);
13871 		}
13872 	}
13873 
13874 	if (addzone) {
13875 		CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj,
13876 				 redirect, text));
13877 	} else {
13878 		CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj,
13879 				 redirect, text));
13880 	}
13881 
13882 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13883 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13884 		      "%s zone %s in view %s via %s",
13885 		      addzone ? "added" : "updated", zonename, view->name,
13886 		      addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
13887 
13888 	/* Changing a zone counts as reconfiguration */
13889 	CHECK(isc_time_now(&named_g_configtime));
13890 
13891 cleanup:
13892 	if (isc_buffer_usedlength(*text) > 0) {
13893 		(void)putnull(text);
13894 	}
13895 	if (zoneconf != NULL) {
13896 		cfg_obj_destroy(named_g_addparser, &zoneconf);
13897 	}
13898 	if (view != NULL) {
13899 		dns_view_detach(&view);
13900 	}
13901 
13902 	return (result);
13903 }
13904 
13905 static bool
inuse(const char * file,bool first,isc_buffer_t ** text)13906 inuse(const char *file, bool first, isc_buffer_t **text) {
13907 	if (file != NULL && isc_file_exists(file)) {
13908 		if (first) {
13909 			(void)putstr(text, "The following files were in use "
13910 					   "and may now be removed:\n");
13911 		} else {
13912 			(void)putstr(text, "\n");
13913 		}
13914 		(void)putstr(text, file);
13915 		(void)putnull(text);
13916 		return (false);
13917 	}
13918 	return (first);
13919 }
13920 
13921 typedef struct {
13922 	dns_zone_t *zone;
13923 	bool cleanup;
13924 } ns_dzctx_t;
13925 
13926 /*
13927  * Carry out a zone deletion scheduled by named_server_delzone().
13928  */
13929 static void
rmzone(isc_task_t * task,isc_event_t * event)13930 rmzone(isc_task_t *task, isc_event_t *event) {
13931 	ns_dzctx_t *dz = (ns_dzctx_t *)event->ev_arg;
13932 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
13933 	dns_catz_zone_t *catz = NULL;
13934 	char zonename[DNS_NAME_FORMATSIZE];
13935 	dns_view_t *view = NULL;
13936 	ns_cfgctx_t *cfg = NULL;
13937 	dns_db_t *dbp = NULL;
13938 	bool added;
13939 	isc_result_t result;
13940 #ifdef HAVE_LMDB
13941 	MDB_txn *txn = NULL;
13942 	MDB_dbi dbi;
13943 #endif /* ifdef HAVE_LMDB */
13944 
13945 	REQUIRE(dz != NULL);
13946 
13947 	isc_event_free(&event);
13948 
13949 	/* Dig out configuration for this zone */
13950 	zone = dz->zone;
13951 	view = dns_zone_getview(zone);
13952 	cfg = (ns_cfgctx_t *)view->new_zone_config;
13953 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
13954 
13955 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13956 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13957 		      "deleting zone %s in view %s via delzone", zonename,
13958 		      view->name);
13959 
13960 	/*
13961 	 * Remove the zone from configuration (and NZF file if applicable)
13962 	 * (If this is a catalog zone member then nzf_config can be NULL)
13963 	 */
13964 	added = dns_zone_getadded(zone);
13965 	catz = dns_zone_get_parentcatz(zone);
13966 
13967 	if (added && catz == NULL && cfg != NULL) {
13968 #ifdef HAVE_LMDB
13969 		/* Make sure we can open the NZD database */
13970 		LOCK(&view->new_zone_lock);
13971 		result = nzd_open(view, 0, &txn, &dbi);
13972 		if (result != ISC_R_SUCCESS) {
13973 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13974 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13975 				      "unable to open NZD database for '%s'",
13976 				      view->new_zone_db);
13977 		} else {
13978 			result = nzd_save(&txn, dbi, zone, NULL);
13979 		}
13980 
13981 		if (result != ISC_R_SUCCESS) {
13982 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13983 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13984 				      "unable to delete zone configuration: %s",
13985 				      isc_result_totext(result));
13986 		}
13987 
13988 		if (txn != NULL) {
13989 			(void)nzd_close(&txn, false);
13990 		}
13991 		UNLOCK(&view->new_zone_lock);
13992 #else  /* ifdef HAVE_LMDB */
13993 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
13994 					 dns_zone_getorigin(zone),
13995 					 nzf_writeconf);
13996 		if (result != ISC_R_SUCCESS) {
13997 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13998 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13999 				      "unable to delete zone configuration: %s",
14000 				      isc_result_totext(result));
14001 		}
14002 #endif /* HAVE_LMDB */
14003 	}
14004 
14005 	if (!added && cfg != NULL) {
14006 		if (cfg->vconfig != NULL) {
14007 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14008 								  "options");
14009 			result = delete_zoneconf(
14010 				view, cfg->conf_parser, voptions,
14011 				dns_zone_getorigin(zone), NULL);
14012 		} else {
14013 			result = delete_zoneconf(
14014 				view, cfg->conf_parser, cfg->config,
14015 				dns_zone_getorigin(zone), NULL);
14016 		}
14017 		if (result != ISC_R_SUCCESS) {
14018 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14019 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14020 				      "unable to delete zone configuration: %s",
14021 				      isc_result_totext(result));
14022 		}
14023 	}
14024 
14025 	/* Unload zone database */
14026 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14027 		dns_db_detach(&dbp);
14028 		dns_zone_unload(zone);
14029 	}
14030 
14031 	/* Clean up stub/slave zone files if requested to do so */
14032 	dns_zone_getraw(zone, &raw);
14033 	mayberaw = (raw != NULL) ? raw : zone;
14034 
14035 	if (added && dz->cleanup) {
14036 		const char *file;
14037 
14038 		file = dns_zone_getfile(mayberaw);
14039 		result = isc_file_remove(file);
14040 		if (result != ISC_R_SUCCESS) {
14041 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14042 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14043 				      "file %s not removed: %s", file,
14044 				      isc_result_totext(result));
14045 		}
14046 
14047 		file = dns_zone_getjournal(mayberaw);
14048 		result = isc_file_remove(file);
14049 		if (result != ISC_R_SUCCESS) {
14050 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14051 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14052 				      "file %s not removed: %s", file,
14053 				      isc_result_totext(result));
14054 		}
14055 
14056 		if (zone != mayberaw) {
14057 			file = dns_zone_getfile(zone);
14058 			result = isc_file_remove(file);
14059 			if (result != ISC_R_SUCCESS) {
14060 				isc_log_write(
14061 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14062 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14063 					"file %s not removed: %s", file,
14064 					isc_result_totext(result));
14065 			}
14066 
14067 			file = dns_zone_getjournal(zone);
14068 			result = isc_file_remove(file);
14069 			if (result != ISC_R_SUCCESS) {
14070 				isc_log_write(
14071 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14072 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14073 					"file %s not removed: %s", file,
14074 					isc_result_totext(result));
14075 			}
14076 		}
14077 	}
14078 
14079 	if (raw != NULL) {
14080 		dns_zone_detach(&raw);
14081 	}
14082 	dns_zone_detach(&zone);
14083 	isc_mem_put(named_g_mctx, dz, sizeof(*dz));
14084 	isc_task_detach(&task);
14085 }
14086 
14087 /*
14088  * Act on a "delzone" command from the command channel.
14089  */
14090 isc_result_t
named_server_delzone(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14091 named_server_delzone(named_server_t *server, isc_lex_t *lex,
14092 		     isc_buffer_t **text) {
14093 	isc_result_t result, tresult;
14094 	dns_zone_t *zone = NULL;
14095 	dns_zone_t *raw = NULL;
14096 	dns_zone_t *mayberaw;
14097 	dns_view_t *view = NULL;
14098 	char zonename[DNS_NAME_FORMATSIZE];
14099 	bool cleanup = false;
14100 	const char *ptr;
14101 	bool added;
14102 	ns_dzctx_t *dz = NULL;
14103 	isc_event_t *dzevent = NULL;
14104 	isc_task_t *task = NULL;
14105 
14106 	REQUIRE(text != NULL);
14107 
14108 	/* Skip the command name. */
14109 	ptr = next_token(lex, text);
14110 	if (ptr == NULL) {
14111 		return (ISC_R_UNEXPECTEDEND);
14112 	}
14113 
14114 	/* Find out what we are to do. */
14115 	ptr = next_token(lex, text);
14116 	if (ptr == NULL) {
14117 		return (ISC_R_UNEXPECTEDEND);
14118 	}
14119 
14120 	if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) {
14121 		cleanup = true;
14122 		ptr = next_token(lex, text);
14123 	}
14124 
14125 	CHECK(zone_from_args(server, lex, ptr, &zone, zonename, text, false));
14126 	if (zone == NULL) {
14127 		result = ISC_R_UNEXPECTEDEND;
14128 		goto cleanup;
14129 	}
14130 
14131 	INSIST(zonename != NULL);
14132 
14133 	/* Is this a policy zone? */
14134 	if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
14135 		TCHECK(putstr(text, "zone '"));
14136 		TCHECK(putstr(text, zonename));
14137 		TCHECK(putstr(text,
14138 			      "' cannot be deleted: response-policy zone."));
14139 		result = ISC_R_FAILURE;
14140 		goto cleanup;
14141 	}
14142 
14143 	view = dns_zone_getview(zone);
14144 	if (dns_zone_gettype(zone) == dns_zone_redirect) {
14145 		dns_zone_detach(&view->redirect);
14146 	} else {
14147 		CHECK(dns_zt_unmount(view->zonetable, zone));
14148 	}
14149 
14150 	/* Send cleanup event */
14151 	dz = isc_mem_get(named_g_mctx, sizeof(*dz));
14152 
14153 	dz->cleanup = cleanup;
14154 	dz->zone = NULL;
14155 	dns_zone_attach(zone, &dz->zone);
14156 	dzevent = isc_event_allocate(named_g_mctx, server, NAMED_EVENT_DELZONE,
14157 				     rmzone, dz, sizeof(isc_event_t));
14158 
14159 	dns_zone_gettask(zone, &task);
14160 	isc_task_send(task, &dzevent);
14161 	dz = NULL;
14162 
14163 	/* Inform user about cleaning up stub/slave zone files */
14164 	dns_zone_getraw(zone, &raw);
14165 	mayberaw = (raw != NULL) ? raw : zone;
14166 
14167 	added = dns_zone_getadded(zone);
14168 	if (!added) {
14169 		TCHECK(putstr(text, "zone '"));
14170 		TCHECK(putstr(text, zonename));
14171 		TCHECK(putstr(text, "' is no longer active and will be "
14172 				    "deleted.\n"));
14173 		TCHECK(putstr(text, "To keep it from returning "));
14174 		TCHECK(putstr(text, "when the server is restarted, it\n"));
14175 		TCHECK(putstr(text, "must also be removed from named.conf."));
14176 	} else if (cleanup) {
14177 		TCHECK(putstr(text, "zone '"));
14178 		TCHECK(putstr(text, zonename));
14179 		TCHECK(putstr(text, "' and associated files will be deleted."));
14180 	} else if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
14181 		   dns_zone_gettype(mayberaw) == dns_zone_mirror ||
14182 		   dns_zone_gettype(mayberaw) == dns_zone_stub)
14183 	{
14184 		bool first;
14185 		const char *file;
14186 
14187 		TCHECK(putstr(text, "zone '"));
14188 		TCHECK(putstr(text, zonename));
14189 		TCHECK(putstr(text, "' will be deleted."));
14190 
14191 		file = dns_zone_getfile(mayberaw);
14192 		first = inuse(file, true, text);
14193 
14194 		file = dns_zone_getjournal(mayberaw);
14195 		first = inuse(file, first, text);
14196 
14197 		if (zone != mayberaw) {
14198 			file = dns_zone_getfile(zone);
14199 			first = inuse(file, first, text);
14200 
14201 			file = dns_zone_getjournal(zone);
14202 			(void)inuse(file, first, text);
14203 		}
14204 	}
14205 
14206 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14207 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14208 		      "zone %s scheduled for removal via delzone", zonename);
14209 
14210 	/* Removing a zone counts as reconfiguration */
14211 	CHECK(isc_time_now(&named_g_configtime));
14212 
14213 	result = ISC_R_SUCCESS;
14214 
14215 cleanup:
14216 	if (isc_buffer_usedlength(*text) > 0) {
14217 		(void)putnull(text);
14218 	}
14219 	if (raw != NULL) {
14220 		dns_zone_detach(&raw);
14221 	}
14222 	if (zone != NULL) {
14223 		dns_zone_detach(&zone);
14224 	}
14225 
14226 	return (result);
14227 }
14228 
14229 static const cfg_obj_t *
find_name_in_list_from_map(const cfg_obj_t * config,const char * map_key_for_list,const char * name,bool redirect)14230 find_name_in_list_from_map(const cfg_obj_t *config,
14231 			   const char *map_key_for_list, const char *name,
14232 			   bool redirect) {
14233 	const cfg_obj_t *list = NULL;
14234 	const cfg_listelt_t *element;
14235 	const cfg_obj_t *obj = NULL;
14236 	dns_fixedname_t fixed1, fixed2;
14237 	dns_name_t *name1 = NULL, *name2 = NULL;
14238 	isc_result_t result;
14239 
14240 	if (strcmp(map_key_for_list, "zone") == 0) {
14241 		name1 = dns_fixedname_initname(&fixed1);
14242 		name2 = dns_fixedname_initname(&fixed2);
14243 		result = dns_name_fromstring(name1, name, 0, NULL);
14244 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
14245 	}
14246 
14247 	cfg_map_get(config, map_key_for_list, &list);
14248 	for (element = cfg_list_first(list); element != NULL;
14249 	     element = cfg_list_next(element))
14250 	{
14251 		const char *vname;
14252 
14253 		obj = cfg_listelt_value(element);
14254 		INSIST(obj != NULL);
14255 		vname = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
14256 		if (vname == NULL) {
14257 			obj = NULL;
14258 			continue;
14259 		}
14260 
14261 		if (name1 != NULL) {
14262 			result = dns_name_fromstring(name2, vname, 0, NULL);
14263 			if (result == ISC_R_SUCCESS &&
14264 			    dns_name_equal(name1, name2))
14265 			{
14266 				const cfg_obj_t *zoptions;
14267 				const cfg_obj_t *typeobj = NULL;
14268 				zoptions = cfg_tuple_get(obj, "options");
14269 
14270 				if (zoptions != NULL) {
14271 					cfg_map_get(zoptions, "type", &typeobj);
14272 				}
14273 				if (redirect && typeobj != NULL &&
14274 				    strcasecmp(cfg_obj_asstring(typeobj),
14275 					       "redirect") == 0)
14276 				{
14277 					break;
14278 				} else if (!redirect) {
14279 					break;
14280 				}
14281 			}
14282 		} else if (strcasecmp(vname, name) == 0) {
14283 			break;
14284 		}
14285 
14286 		obj = NULL;
14287 	}
14288 
14289 	return (obj);
14290 }
14291 
14292 static void
emitzone(void * arg,const char * buf,int len)14293 emitzone(void *arg, const char *buf, int len) {
14294 	ns_dzarg_t *dzarg = arg;
14295 	isc_result_t result;
14296 
14297 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
14298 	result = putmem(dzarg->text, buf, len);
14299 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
14300 		dzarg->result = result;
14301 	}
14302 }
14303 
14304 /*
14305  * Act on a "showzone" command from the command channel.
14306  */
14307 isc_result_t
named_server_showzone(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14308 named_server_showzone(named_server_t *server, isc_lex_t *lex,
14309 		      isc_buffer_t **text) {
14310 	isc_result_t result;
14311 	const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
14312 	char zonename[DNS_NAME_FORMATSIZE];
14313 	const cfg_obj_t *map;
14314 	dns_view_t *view = NULL;
14315 	dns_zone_t *zone = NULL;
14316 	ns_cfgctx_t *cfg = NULL;
14317 #ifdef HAVE_LMDB
14318 	cfg_obj_t *nzconfig = NULL;
14319 #endif /* HAVE_LMDB */
14320 	bool added, redirect;
14321 	ns_dzarg_t dzarg;
14322 
14323 	REQUIRE(text != NULL);
14324 
14325 	/* Parse parameters */
14326 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
14327 	if (zone == NULL) {
14328 		result = ISC_R_UNEXPECTEDEND;
14329 		goto cleanup;
14330 	}
14331 
14332 	redirect = dns_zone_gettype(zone) == dns_zone_redirect;
14333 	added = dns_zone_getadded(zone);
14334 	view = dns_zone_getview(zone);
14335 	dns_zone_detach(&zone);
14336 
14337 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14338 	if (cfg == NULL) {
14339 		result = ISC_R_FAILURE;
14340 		goto cleanup;
14341 	}
14342 
14343 	if (!added) {
14344 		/* Find the view statement */
14345 		vconfig = find_name_in_list_from_map(cfg->config, "view",
14346 						     view->name, false);
14347 
14348 		/* Find the zone statement */
14349 		if (vconfig != NULL) {
14350 			map = cfg_tuple_get(vconfig, "options");
14351 		} else {
14352 			map = cfg->config;
14353 		}
14354 
14355 		zconfig = find_name_in_list_from_map(map, "zone", zonename,
14356 						     redirect);
14357 	}
14358 
14359 #ifndef HAVE_LMDB
14360 	if (zconfig == NULL && cfg->nzf_config != NULL) {
14361 		zconfig = find_name_in_list_from_map(cfg->nzf_config, "zone",
14362 						     zonename, redirect);
14363 	}
14364 #else  /* HAVE_LMDB */
14365 	if (zconfig == NULL) {
14366 		const cfg_obj_t *zlist = NULL;
14367 		CHECK(get_newzone_config(view, zonename, &nzconfig));
14368 		CHECK(cfg_map_get(nzconfig, "zone", &zlist));
14369 		if (!cfg_obj_islist(zlist)) {
14370 			CHECK(ISC_R_FAILURE);
14371 		}
14372 
14373 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
14374 	}
14375 #endif /* HAVE_LMDB */
14376 
14377 	if (zconfig == NULL) {
14378 		CHECK(ISC_R_NOTFOUND);
14379 	}
14380 
14381 	CHECK(putstr(text, "zone "));
14382 	dzarg.magic = DZARG_MAGIC;
14383 	dzarg.text = text;
14384 	dzarg.result = ISC_R_SUCCESS;
14385 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
14386 	CHECK(dzarg.result);
14387 
14388 	CHECK(putstr(text, ";"));
14389 
14390 	result = ISC_R_SUCCESS;
14391 
14392 cleanup:
14393 #ifdef HAVE_LMDB
14394 	if (nzconfig != NULL) {
14395 		cfg_obj_destroy(named_g_addparser, &nzconfig);
14396 	}
14397 #endif /* HAVE_LMDB */
14398 	if (isc_buffer_usedlength(*text) > 0) {
14399 		(void)putnull(text);
14400 	}
14401 
14402 	return (result);
14403 }
14404 
14405 static void
newzone_cfgctx_destroy(void ** cfgp)14406 newzone_cfgctx_destroy(void **cfgp) {
14407 	ns_cfgctx_t *cfg;
14408 
14409 	REQUIRE(cfgp != NULL && *cfgp != NULL);
14410 
14411 	cfg = *cfgp;
14412 
14413 	if (cfg->conf_parser != NULL) {
14414 		if (cfg->config != NULL) {
14415 			cfg_obj_destroy(cfg->conf_parser, &cfg->config);
14416 		}
14417 		if (cfg->vconfig != NULL) {
14418 			cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
14419 		}
14420 		cfg_parser_destroy(&cfg->conf_parser);
14421 	}
14422 	if (cfg->add_parser != NULL) {
14423 		if (cfg->nzf_config != NULL) {
14424 			cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
14425 		}
14426 		cfg_parser_destroy(&cfg->add_parser);
14427 	}
14428 
14429 	if (cfg->actx != NULL) {
14430 		cfg_aclconfctx_detach(&cfg->actx);
14431 	}
14432 
14433 	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
14434 	*cfgp = NULL;
14435 }
14436 
14437 isc_result_t
named_server_signing(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14438 named_server_signing(named_server_t *server, isc_lex_t *lex,
14439 		     isc_buffer_t **text) {
14440 	isc_result_t result = ISC_R_SUCCESS;
14441 	dns_zone_t *zone = NULL;
14442 	dns_name_t *origin;
14443 	dns_db_t *db = NULL;
14444 	dns_dbnode_t *node = NULL;
14445 	dns_dbversion_t *version = NULL;
14446 	dns_rdatatype_t privatetype;
14447 	dns_rdataset_t privset;
14448 	bool first = true;
14449 	bool list = false, clear = false;
14450 	bool chain = false;
14451 	bool setserial = false;
14452 	bool resalt = false;
14453 	uint32_t serial = 0;
14454 	char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
14455 	unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
14456 	unsigned char salt[255];
14457 	const char *ptr;
14458 	size_t n;
14459 
14460 	REQUIRE(text != NULL);
14461 
14462 	dns_rdataset_init(&privset);
14463 
14464 	/* Skip the command name. */
14465 	ptr = next_token(lex, text);
14466 	if (ptr == NULL) {
14467 		return (ISC_R_UNEXPECTEDEND);
14468 	}
14469 
14470 	/* Find out what we are to do. */
14471 	ptr = next_token(lex, text);
14472 	if (ptr == NULL) {
14473 		return (ISC_R_UNEXPECTEDEND);
14474 	}
14475 
14476 	if (strcasecmp(ptr, "-list") == 0) {
14477 		list = true;
14478 	} else if ((strcasecmp(ptr, "-clear") == 0) ||
14479 		   (strcasecmp(ptr, "-clean") == 0))
14480 	{
14481 		clear = true;
14482 		ptr = next_token(lex, text);
14483 		if (ptr == NULL) {
14484 			return (ISC_R_UNEXPECTEDEND);
14485 		}
14486 		strlcpy(keystr, ptr, sizeof(keystr));
14487 	} else if (strcasecmp(ptr, "-nsec3param") == 0) {
14488 		char hashbuf[64], flagbuf[64], iterbuf[64];
14489 		char nbuf[256];
14490 
14491 		chain = true;
14492 		ptr = next_token(lex, text);
14493 		if (ptr == NULL) {
14494 			return (ISC_R_UNEXPECTEDEND);
14495 		}
14496 
14497 		if (strcasecmp(ptr, "none") == 0) {
14498 			hash = 0;
14499 		} else {
14500 			strlcpy(hashbuf, ptr, sizeof(hashbuf));
14501 
14502 			ptr = next_token(lex, text);
14503 			if (ptr == NULL) {
14504 				return (ISC_R_UNEXPECTEDEND);
14505 			}
14506 			strlcpy(flagbuf, ptr, sizeof(flagbuf));
14507 
14508 			ptr = next_token(lex, text);
14509 			if (ptr == NULL) {
14510 				return (ISC_R_UNEXPECTEDEND);
14511 			}
14512 			strlcpy(iterbuf, ptr, sizeof(iterbuf));
14513 			n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", hashbuf,
14514 				     flagbuf, iterbuf);
14515 			if (n == sizeof(nbuf)) {
14516 				return (ISC_R_NOSPACE);
14517 			}
14518 			n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
14519 			if (n != 3U) {
14520 				return (ISC_R_BADNUMBER);
14521 			}
14522 
14523 			if (hash > 0xffU || flags > 0xffU ||
14524 			    iter > dns_nsec3_maxiterations())
14525 			{
14526 				return (ISC_R_RANGE);
14527 			}
14528 
14529 			ptr = next_token(lex, text);
14530 			if (ptr == NULL) {
14531 				return (ISC_R_UNEXPECTEDEND);
14532 			} else if (strcasecmp(ptr, "auto") == 0) {
14533 				/* Auto-generate a random salt.
14534 				 * XXXMUKS: This currently uses the
14535 				 * minimum recommended length by RFC
14536 				 * 5155 (64 bits). It should be made
14537 				 * configurable.
14538 				 */
14539 				saltlen = 8;
14540 				resalt = true;
14541 			} else if (strcmp(ptr, "-") != 0) {
14542 				isc_buffer_t buf;
14543 
14544 				isc_buffer_init(&buf, salt, sizeof(salt));
14545 				CHECK(isc_hex_decodestring(ptr, &buf));
14546 				saltlen = isc_buffer_usedlength(&buf);
14547 			}
14548 		}
14549 	} else if (strcasecmp(ptr, "-serial") == 0) {
14550 		ptr = next_token(lex, text);
14551 		if (ptr == NULL) {
14552 			return (ISC_R_UNEXPECTEDEND);
14553 		}
14554 		CHECK(isc_parse_uint32(&serial, ptr, 10));
14555 		setserial = true;
14556 	} else {
14557 		CHECK(DNS_R_SYNTAX);
14558 	}
14559 
14560 	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
14561 	if (zone == NULL) {
14562 		CHECK(ISC_R_UNEXPECTEDEND);
14563 	}
14564 
14565 	if (dns_zone_getkasp(zone) != NULL) {
14566 		(void)putstr(text, "zone uses dnssec-policy, use rndc dnssec "
14567 				   "command instead");
14568 		(void)putnull(text);
14569 		goto cleanup;
14570 	}
14571 
14572 	if (clear) {
14573 		CHECK(dns_zone_keydone(zone, keystr));
14574 		(void)putstr(text, "request queued");
14575 		(void)putnull(text);
14576 	} else if (chain) {
14577 		CHECK(dns_zone_setnsec3param(
14578 			zone, (uint8_t)hash, (uint8_t)flags, iter,
14579 			(uint8_t)saltlen, salt, true, resalt));
14580 		(void)putstr(text, "nsec3param request queued");
14581 		(void)putnull(text);
14582 	} else if (setserial) {
14583 		CHECK(dns_zone_setserial(zone, serial));
14584 		(void)putstr(text, "serial request queued");
14585 		(void)putnull(text);
14586 	} else if (list) {
14587 		privatetype = dns_zone_getprivatetype(zone);
14588 		origin = dns_zone_getorigin(zone);
14589 		CHECK(dns_zone_getdb(zone, &db));
14590 		CHECK(dns_db_findnode(db, origin, false, &node));
14591 		dns_db_currentversion(db, &version);
14592 
14593 		result = dns_db_findrdataset(db, node, version, privatetype,
14594 					     dns_rdatatype_none, 0, &privset,
14595 					     NULL);
14596 		if (result == ISC_R_NOTFOUND) {
14597 			(void)putstr(text, "No signing records found");
14598 			(void)putnull(text);
14599 			result = ISC_R_SUCCESS;
14600 			goto cleanup;
14601 		}
14602 
14603 		for (result = dns_rdataset_first(&privset);
14604 		     result == ISC_R_SUCCESS;
14605 		     result = dns_rdataset_next(&privset))
14606 		{
14607 			dns_rdata_t priv = DNS_RDATA_INIT;
14608 			/*
14609 			 * In theory, the output buffer could hold a full RDATA
14610 			 * record which is 16-bit and then some text around
14611 			 * it
14612 			 */
14613 			char output[UINT16_MAX + BUFSIZ];
14614 			isc_buffer_t buf;
14615 
14616 			dns_rdataset_current(&privset, &priv);
14617 
14618 			isc_buffer_init(&buf, output, sizeof(output));
14619 			CHECK(dns_private_totext(&priv, &buf));
14620 			if (!first) {
14621 				CHECK(putstr(text, "\n"));
14622 			}
14623 			CHECK(putstr(text, output));
14624 			first = false;
14625 		}
14626 		if (!first) {
14627 			CHECK(putnull(text));
14628 		}
14629 
14630 		if (result == ISC_R_NOMORE) {
14631 			result = ISC_R_SUCCESS;
14632 		}
14633 	}
14634 
14635 cleanup:
14636 	if (dns_rdataset_isassociated(&privset)) {
14637 		dns_rdataset_disassociate(&privset);
14638 	}
14639 	if (node != NULL) {
14640 		dns_db_detachnode(db, &node);
14641 	}
14642 	if (version != NULL) {
14643 		dns_db_closeversion(db, &version, false);
14644 	}
14645 	if (db != NULL) {
14646 		dns_db_detach(&db);
14647 	}
14648 	if (zone != NULL) {
14649 		dns_zone_detach(&zone);
14650 	}
14651 
14652 	return (result);
14653 }
14654 
14655 static bool
argcheck(char * cmd,const char * full)14656 argcheck(char *cmd, const char *full) {
14657 	size_t l;
14658 
14659 	if (cmd == NULL || cmd[0] != '-') {
14660 		return (false);
14661 	}
14662 
14663 	cmd++;
14664 	l = strlen(cmd);
14665 	if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
14666 		return (false);
14667 	}
14668 
14669 	return (true);
14670 }
14671 
14672 isc_result_t
named_server_dnssec(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14673 named_server_dnssec(named_server_t *server, isc_lex_t *lex,
14674 		    isc_buffer_t **text) {
14675 	isc_result_t result = ISC_R_SUCCESS;
14676 	dns_zone_t *zone = NULL;
14677 	dns_kasp_t *kasp = NULL;
14678 	dns_dnsseckeylist_t keys;
14679 	dns_dnsseckey_t *key;
14680 	char *ptr, *zonetext = NULL;
14681 	const char *msg = NULL;
14682 	/* variables for -checkds */
14683 	bool checkds = false, dspublish = false;
14684 	/* variables for -rollover */
14685 	bool rollover = false;
14686 	/* variables for -key */
14687 	bool use_keyid = false;
14688 	dns_keytag_t keyid = 0;
14689 	uint8_t algorithm = 0;
14690 	/* variables for -status */
14691 	bool status = false;
14692 	char output[4096];
14693 	isc_stdtime_t now, when;
14694 	isc_time_t timenow, timewhen;
14695 	const char *dir;
14696 	dns_db_t *db = NULL;
14697 	dns_dbversion_t *version = NULL;
14698 
14699 	REQUIRE(text != NULL);
14700 
14701 	/* Skip the command name. */
14702 	ptr = next_token(lex, text);
14703 	if (ptr == NULL) {
14704 		return (ISC_R_UNEXPECTEDEND);
14705 	}
14706 
14707 	/* Find out what we are to do. */
14708 	ptr = next_token(lex, text);
14709 	if (ptr == NULL) {
14710 		return (ISC_R_UNEXPECTEDEND);
14711 	}
14712 
14713 	/* Initialize current time and key list. */
14714 	TIME_NOW(&timenow);
14715 	now = isc_time_seconds(&timenow);
14716 	when = now;
14717 
14718 	ISC_LIST_INIT(keys);
14719 
14720 	if (strcasecmp(ptr, "-status") == 0) {
14721 		status = true;
14722 	} else if (strcasecmp(ptr, "-rollover") == 0) {
14723 		rollover = true;
14724 	} else if (strcasecmp(ptr, "-checkds") == 0) {
14725 		checkds = true;
14726 	} else {
14727 		CHECK(DNS_R_SYNTAX);
14728 	}
14729 
14730 	if (rollover || checkds) {
14731 		/* Check for options */
14732 		for (;;) {
14733 			ptr = next_token(lex, text);
14734 			if (ptr == NULL) {
14735 				msg = "Bad format";
14736 				CHECK(ISC_R_UNEXPECTEDEND);
14737 			} else if (argcheck(ptr, "alg")) {
14738 				isc_consttextregion_t alg;
14739 				ptr = next_token(lex, text);
14740 				if (ptr == NULL) {
14741 					msg = "No key algorithm specified";
14742 					CHECK(ISC_R_UNEXPECTEDEND);
14743 				}
14744 				alg.base = ptr;
14745 				alg.length = strlen(alg.base);
14746 				result = dns_secalg_fromtext(
14747 					&algorithm, (isc_textregion_t *)&alg);
14748 				if (result != ISC_R_SUCCESS) {
14749 					msg = "Bad algorithm";
14750 					CHECK(DNS_R_SYNTAX);
14751 				}
14752 				continue;
14753 			} else if (argcheck(ptr, "key")) {
14754 				uint16_t id;
14755 				ptr = next_token(lex, text);
14756 				if (ptr == NULL) {
14757 					msg = "No key identifier specified";
14758 					CHECK(ISC_R_UNEXPECTEDEND);
14759 				}
14760 				CHECK(isc_parse_uint16(&id, ptr, 10));
14761 				keyid = (dns_keytag_t)id;
14762 				use_keyid = true;
14763 				continue;
14764 			} else if (argcheck(ptr, "when")) {
14765 				uint32_t tw;
14766 				ptr = next_token(lex, text);
14767 				if (ptr == NULL) {
14768 					msg = "No time specified";
14769 					CHECK(ISC_R_UNEXPECTEDEND);
14770 				}
14771 				CHECK(dns_time32_fromtext(ptr, &tw));
14772 				when = (isc_stdtime_t)tw;
14773 				continue;
14774 			} else if (ptr[0] == '-') {
14775 				msg = "Unknown option";
14776 				CHECK(DNS_R_SYNTAX);
14777 			} else if (checkds) {
14778 				/*
14779 				 * No arguments provided, so we must be
14780 				 * parsing "published|withdrawn".
14781 				 */
14782 				if (strcasecmp(ptr, "published") == 0) {
14783 					dspublish = true;
14784 				} else if (strcasecmp(ptr, "withdrawn") != 0) {
14785 					CHECK(DNS_R_SYNTAX);
14786 				}
14787 			} else if (rollover) {
14788 				/*
14789 				 * No arguments provided, so we must be
14790 				 * parsing the zone.
14791 				 */
14792 				zonetext = ptr;
14793 			}
14794 			break;
14795 		}
14796 
14797 		if (rollover && !use_keyid) {
14798 			msg = "Key id is required when scheduling rollover";
14799 			CHECK(DNS_R_SYNTAX);
14800 		}
14801 
14802 		if (algorithm > 0 && !use_keyid) {
14803 			msg = "Key id is required when setting algorithm";
14804 			CHECK(DNS_R_SYNTAX);
14805 		}
14806 	}
14807 
14808 	/* Get zone. */
14809 	CHECK(zone_from_args(server, lex, zonetext, &zone, NULL, text, false));
14810 	if (zone == NULL) {
14811 		msg = "Zone not found";
14812 		CHECK(ISC_R_UNEXPECTEDEND);
14813 	}
14814 
14815 	/* Trailing garbage? */
14816 	ptr = next_token(lex, text);
14817 	if (ptr != NULL) {
14818 		msg = "Too many arguments";
14819 		CHECK(DNS_R_SYNTAX);
14820 	}
14821 
14822 	/* Get dnssec-policy. */
14823 	kasp = dns_zone_getkasp(zone);
14824 	if (kasp == NULL) {
14825 		msg = "Zone does not have dnssec-policy";
14826 		goto cleanup;
14827 	}
14828 
14829 	/* Get DNSSEC keys. */
14830 	dir = dns_zone_getkeydirectory(zone);
14831 	CHECK(dns_zone_getdb(zone, &db));
14832 	dns_db_currentversion(db, &version);
14833 	LOCK(&kasp->lock);
14834 	result = dns_zone_getdnsseckeys(zone, db, version, now, &keys);
14835 	UNLOCK(&kasp->lock);
14836 	if (result != ISC_R_SUCCESS) {
14837 		if (result != ISC_R_NOTFOUND) {
14838 			goto cleanup;
14839 		}
14840 	}
14841 
14842 	if (status) {
14843 		/*
14844 		 * Output the DNSSEC status of the key and signing policy.
14845 		 */
14846 		LOCK(&kasp->lock);
14847 		dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
14848 		UNLOCK(&kasp->lock);
14849 		CHECK(putstr(text, output));
14850 	} else if (checkds) {
14851 		/*
14852 		 * Mark DS record has been seen, so it may move to the
14853 		 * rumoured state.
14854 		 */
14855 		char whenbuf[80];
14856 		isc_time_set(&timewhen, when, 0);
14857 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
14858 		isc_result_t ret;
14859 
14860 		LOCK(&kasp->lock);
14861 		if (use_keyid) {
14862 			result = dns_keymgr_checkds_id(kasp, &keys, dir, now,
14863 						       when, dspublish, keyid,
14864 						       (unsigned int)algorithm);
14865 		} else {
14866 			result = dns_keymgr_checkds(kasp, &keys, dir, now, when,
14867 						    dspublish);
14868 		}
14869 		UNLOCK(&kasp->lock);
14870 
14871 		switch (result) {
14872 		case ISC_R_SUCCESS:
14873 			/*
14874 			 * Rekey after checkds command because the next key
14875 			 * event may have changed.
14876 			 */
14877 			dns_zone_rekey(zone, false);
14878 
14879 			if (use_keyid) {
14880 				char tagbuf[6];
14881 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
14882 				CHECK(putstr(text, "KSK "));
14883 				CHECK(putstr(text, tagbuf));
14884 				CHECK(putstr(text, ": "));
14885 			}
14886 			CHECK(putstr(text, "Marked DS as "));
14887 			if (dspublish) {
14888 				CHECK(putstr(text, "published "));
14889 			} else {
14890 				CHECK(putstr(text, "withdrawn "));
14891 			}
14892 			CHECK(putstr(text, "since "));
14893 			CHECK(putstr(text, whenbuf));
14894 			break;
14895 		case DNS_R_TOOMANYKEYS:
14896 			CHECK(putstr(text,
14897 				     "Error: multiple possible keys found, "
14898 				     "retry command with -key id"));
14899 			break;
14900 		default:
14901 			ret = result;
14902 			CHECK(putstr(text,
14903 				     "Error executing checkds command: "));
14904 			CHECK(putstr(text, isc_result_totext(ret)));
14905 			break;
14906 		}
14907 	} else if (rollover) {
14908 		/*
14909 		 * Manually rollover a key.
14910 		 */
14911 		char whenbuf[80];
14912 		isc_time_set(&timewhen, when, 0);
14913 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
14914 		isc_result_t ret;
14915 
14916 		LOCK(&kasp->lock);
14917 		result = dns_keymgr_rollover(kasp, &keys, dir, now, when, keyid,
14918 					     (unsigned int)algorithm);
14919 		UNLOCK(&kasp->lock);
14920 
14921 		switch (result) {
14922 		case ISC_R_SUCCESS:
14923 			/*
14924 			 * Rekey after rollover command because the next key
14925 			 * event may have changed.
14926 			 */
14927 			dns_zone_rekey(zone, false);
14928 
14929 			if (use_keyid) {
14930 				char tagbuf[6];
14931 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
14932 				CHECK(putstr(text, "Key "));
14933 				CHECK(putstr(text, tagbuf));
14934 				CHECK(putstr(text, ": "));
14935 			}
14936 			CHECK(putstr(text, "Rollover scheduled on "));
14937 			CHECK(putstr(text, whenbuf));
14938 			break;
14939 		case DNS_R_TOOMANYKEYS:
14940 			CHECK(putstr(text,
14941 				     "Error: multiple possible keys found, "
14942 				     "retry command with -alg algorithm"));
14943 			break;
14944 		default:
14945 			ret = result;
14946 			CHECK(putstr(text,
14947 				     "Error executing rollover command: "));
14948 			CHECK(putstr(text, isc_result_totext(ret)));
14949 			break;
14950 		}
14951 	}
14952 	CHECK(putnull(text));
14953 
14954 cleanup:
14955 	if (msg != NULL) {
14956 		(void)putstr(text, msg);
14957 		(void)putnull(text);
14958 	}
14959 
14960 	if (version != NULL) {
14961 		dns_db_closeversion(db, &version, false);
14962 	}
14963 	if (db != NULL) {
14964 		dns_db_detach(&db);
14965 	}
14966 
14967 	while (!ISC_LIST_EMPTY(keys)) {
14968 		key = ISC_LIST_HEAD(keys);
14969 		ISC_LIST_UNLINK(keys, key, link);
14970 		dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
14971 	}
14972 
14973 	if (zone != NULL) {
14974 		dns_zone_detach(&zone);
14975 	}
14976 
14977 	return (result);
14978 }
14979 
14980 static isc_result_t
putmem(isc_buffer_t ** b,const char * str,size_t len)14981 putmem(isc_buffer_t **b, const char *str, size_t len) {
14982 	isc_result_t result;
14983 
14984 	result = isc_buffer_reserve(b, (unsigned int)len);
14985 	if (result != ISC_R_SUCCESS) {
14986 		return (ISC_R_NOSPACE);
14987 	}
14988 
14989 	isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
14990 	return (ISC_R_SUCCESS);
14991 }
14992 
14993 static isc_result_t
putstr(isc_buffer_t ** b,const char * str)14994 putstr(isc_buffer_t **b, const char *str) {
14995 	return (putmem(b, str, strlen(str)));
14996 }
14997 
14998 static isc_result_t
putuint8(isc_buffer_t ** b,uint8_t val)14999 putuint8(isc_buffer_t **b, uint8_t val) {
15000 	isc_result_t result;
15001 
15002 	result = isc_buffer_reserve(b, 1);
15003 	if (result != ISC_R_SUCCESS) {
15004 		return (ISC_R_NOSPACE);
15005 	}
15006 
15007 	isc_buffer_putuint8(*b, val);
15008 	return (ISC_R_SUCCESS);
15009 }
15010 
15011 static isc_result_t
putnull(isc_buffer_t ** b)15012 putnull(isc_buffer_t **b) {
15013 	return (putuint8(b, 0));
15014 }
15015 
15016 isc_result_t
named_server_zonestatus(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)15017 named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
15018 			isc_buffer_t **text) {
15019 	isc_result_t result = ISC_R_SUCCESS;
15020 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
15021 	const char *type, *file;
15022 	char zonename[DNS_NAME_FORMATSIZE];
15023 	uint32_t serial, signed_serial, nodes;
15024 	char serbuf[16], sserbuf[16], nodebuf[16];
15025 	char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2];
15026 	char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15027 	char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15028 	char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15029 	char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15030 	char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15031 	isc_time_t loadtime, expiretime, refreshtime;
15032 	isc_time_t refreshkeytime, resigntime;
15033 	dns_zonetype_t zonetype;
15034 	bool dynamic = false, frozen = false;
15035 	bool hasraw = false;
15036 	bool secure, maintain, allow;
15037 	dns_db_t *db = NULL, *rawdb = NULL;
15038 	char **incfiles = NULL;
15039 	int nfiles = 0;
15040 
15041 	REQUIRE(text != NULL);
15042 
15043 	isc_time_settoepoch(&loadtime);
15044 	isc_time_settoepoch(&refreshtime);
15045 	isc_time_settoepoch(&expiretime);
15046 	isc_time_settoepoch(&refreshkeytime);
15047 	isc_time_settoepoch(&resigntime);
15048 
15049 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
15050 	if (zone == NULL) {
15051 		result = ISC_R_UNEXPECTEDEND;
15052 		goto cleanup;
15053 	}
15054 
15055 	/* Inline signing? */
15056 	CHECK(dns_zone_getdb(zone, &db));
15057 	dns_zone_getraw(zone, &raw);
15058 	hasraw = (raw != NULL);
15059 	if (hasraw) {
15060 		mayberaw = raw;
15061 		zonetype = dns_zone_gettype(raw);
15062 		CHECK(dns_zone_getdb(raw, &rawdb));
15063 	} else {
15064 		mayberaw = zone;
15065 		zonetype = dns_zone_gettype(zone);
15066 	}
15067 
15068 	type = dns_zonetype_name(zonetype);
15069 
15070 	/* Serial number */
15071 	result = dns_zone_getserial(mayberaw, &serial);
15072 
15073 	/* This is to mirror old behavior with dns_zone_getserial */
15074 	if (result != ISC_R_SUCCESS) {
15075 		serial = 0;
15076 	}
15077 
15078 	snprintf(serbuf, sizeof(serbuf), "%u", serial);
15079 	if (hasraw) {
15080 		result = dns_zone_getserial(zone, &signed_serial);
15081 		if (result != ISC_R_SUCCESS) {
15082 			serial = 0;
15083 		}
15084 		snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial);
15085 	}
15086 
15087 	/* Database node count */
15088 	nodes = dns_db_nodecount(hasraw ? rawdb : db);
15089 	snprintf(nodebuf, sizeof(nodebuf), "%u", nodes);
15090 
15091 	/* Security */
15092 	secure = dns_db_issecure(db);
15093 	allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
15094 	maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
15095 
15096 	/* Master files */
15097 	file = dns_zone_getfile(mayberaw);
15098 	nfiles = dns_zone_getincludes(mayberaw, &incfiles);
15099 
15100 	/* Load time */
15101 	dns_zone_getloadtime(zone, &loadtime);
15102 	isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
15103 
15104 	/* Refresh/expire times */
15105 	if (zonetype == dns_zone_secondary || zonetype == dns_zone_mirror ||
15106 	    zonetype == dns_zone_stub || zonetype == dns_zone_redirect)
15107 	{
15108 		dns_zone_getexpiretime(mayberaw, &expiretime);
15109 		isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
15110 		dns_zone_getrefreshtime(mayberaw, &refreshtime);
15111 		isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
15112 	}
15113 
15114 	/* Key refresh time */
15115 	if (zonetype == dns_zone_primary ||
15116 	    (zonetype == dns_zone_secondary && hasraw))
15117 	{
15118 		dns_zone_getrefreshkeytime(zone, &refreshkeytime);
15119 		isc_time_formathttptimestamp(&refreshkeytime, kbuf,
15120 					     sizeof(kbuf));
15121 	}
15122 
15123 	/* Dynamic? */
15124 	if (zonetype == dns_zone_primary) {
15125 		dynamic = dns_zone_isdynamic(mayberaw, true);
15126 		frozen = dynamic && !dns_zone_isdynamic(mayberaw, false);
15127 	}
15128 
15129 	/* Next resign event */
15130 	if (secure &&
15131 	    (zonetype == dns_zone_primary ||
15132 	     (zonetype == dns_zone_secondary && hasraw)) &&
15133 	    ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0))
15134 	{
15135 		dns_name_t *name;
15136 		dns_fixedname_t fixed;
15137 		dns_rdataset_t next;
15138 
15139 		dns_rdataset_init(&next);
15140 		name = dns_fixedname_initname(&fixed);
15141 
15142 		result = dns_db_getsigningtime(db, &next, name);
15143 		if (result == ISC_R_SUCCESS) {
15144 			isc_stdtime_t timenow;
15145 			char namebuf[DNS_NAME_FORMATSIZE];
15146 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
15147 
15148 			isc_stdtime_get(&timenow);
15149 			dns_name_format(name, namebuf, sizeof(namebuf));
15150 			dns_rdatatype_format(next.covers, typebuf,
15151 					     sizeof(typebuf));
15152 			snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf,
15153 				 typebuf);
15154 			isc_time_set(
15155 				&resigntime,
15156 				next.resign -
15157 					dns_zone_getsigresigninginterval(zone),
15158 				0);
15159 			isc_time_formathttptimestamp(&resigntime, rtbuf,
15160 						     sizeof(rtbuf));
15161 			dns_rdataset_disassociate(&next);
15162 		}
15163 	}
15164 
15165 	/* Create text */
15166 	CHECK(putstr(text, "name: "));
15167 	CHECK(putstr(text, zonename));
15168 
15169 	CHECK(putstr(text, "\ntype: "));
15170 	CHECK(putstr(text, type));
15171 
15172 	if (file != NULL) {
15173 		int i;
15174 		CHECK(putstr(text, "\nfiles: "));
15175 		CHECK(putstr(text, file));
15176 		for (i = 0; i < nfiles; i++) {
15177 			CHECK(putstr(text, ", "));
15178 			if (incfiles[i] != NULL) {
15179 				CHECK(putstr(text, incfiles[i]));
15180 			}
15181 		}
15182 	}
15183 
15184 	CHECK(putstr(text, "\nserial: "));
15185 	CHECK(putstr(text, serbuf));
15186 	if (hasraw) {
15187 		CHECK(putstr(text, "\nsigned serial: "));
15188 		CHECK(putstr(text, sserbuf));
15189 	}
15190 
15191 	CHECK(putstr(text, "\nnodes: "));
15192 	CHECK(putstr(text, nodebuf));
15193 
15194 	if (!isc_time_isepoch(&loadtime)) {
15195 		CHECK(putstr(text, "\nlast loaded: "));
15196 		CHECK(putstr(text, lbuf));
15197 	}
15198 
15199 	if (!isc_time_isepoch(&refreshtime)) {
15200 		CHECK(putstr(text, "\nnext refresh: "));
15201 		CHECK(putstr(text, rbuf));
15202 	}
15203 
15204 	if (!isc_time_isepoch(&expiretime)) {
15205 		CHECK(putstr(text, "\nexpires: "));
15206 		CHECK(putstr(text, xbuf));
15207 	}
15208 
15209 	if (secure) {
15210 		CHECK(putstr(text, "\nsecure: yes"));
15211 		if (hasraw) {
15212 			CHECK(putstr(text, "\ninline signing: yes"));
15213 		} else {
15214 			CHECK(putstr(text, "\ninline signing: no"));
15215 		}
15216 	} else {
15217 		CHECK(putstr(text, "\nsecure: no"));
15218 	}
15219 
15220 	if (maintain) {
15221 		CHECK(putstr(text, "\nkey maintenance: automatic"));
15222 		if (!isc_time_isepoch(&refreshkeytime)) {
15223 			CHECK(putstr(text, "\nnext key event: "));
15224 			CHECK(putstr(text, kbuf));
15225 		}
15226 	} else if (allow) {
15227 		CHECK(putstr(text, "\nkey maintenance: on command"));
15228 	} else if (secure || hasraw) {
15229 		CHECK(putstr(text, "\nkey maintenance: none"));
15230 	}
15231 
15232 	if (!isc_time_isepoch(&resigntime)) {
15233 		CHECK(putstr(text, "\nnext resign node: "));
15234 		CHECK(putstr(text, resignbuf));
15235 		CHECK(putstr(text, "\nnext resign time: "));
15236 		CHECK(putstr(text, rtbuf));
15237 	}
15238 
15239 	if (dynamic) {
15240 		CHECK(putstr(text, "\ndynamic: yes"));
15241 		if (frozen) {
15242 			CHECK(putstr(text, "\nfrozen: yes"));
15243 		} else {
15244 			CHECK(putstr(text, "\nfrozen: no"));
15245 		}
15246 	} else {
15247 		CHECK(putstr(text, "\ndynamic: no"));
15248 	}
15249 
15250 	CHECK(putstr(text, "\nreconfigurable via modzone: "));
15251 	CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
15252 
15253 cleanup:
15254 	/* Indicate truncated output if possible. */
15255 	if (result == ISC_R_NOSPACE) {
15256 		(void)putstr(text, "\n...");
15257 	}
15258 	if ((result == ISC_R_SUCCESS || result == ISC_R_NOSPACE)) {
15259 		(void)putnull(text);
15260 	}
15261 
15262 	if (db != NULL) {
15263 		dns_db_detach(&db);
15264 	}
15265 	if (rawdb != NULL) {
15266 		dns_db_detach(&rawdb);
15267 	}
15268 	if (incfiles != NULL && mayberaw != NULL) {
15269 		int i;
15270 		isc_mem_t *mctx = dns_zone_getmctx(mayberaw);
15271 
15272 		for (i = 0; i < nfiles; i++) {
15273 			if (incfiles[i] != NULL) {
15274 				isc_mem_free(mctx, incfiles[i]);
15275 			}
15276 		}
15277 		isc_mem_free(mctx, incfiles);
15278 	}
15279 	if (raw != NULL) {
15280 		dns_zone_detach(&raw);
15281 	}
15282 	if (zone != NULL) {
15283 		dns_zone_detach(&zone);
15284 	}
15285 	return (result);
15286 }
15287 
15288 isc_result_t
named_server_nta(named_server_t * server,isc_lex_t * lex,bool readonly,isc_buffer_t ** text)15289 named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
15290 		 isc_buffer_t **text) {
15291 	dns_view_t *view;
15292 	dns_ntatable_t *ntatable = NULL;
15293 	isc_result_t result = ISC_R_SUCCESS;
15294 	char *ptr, *nametext = NULL, *viewname;
15295 	char namebuf[DNS_NAME_FORMATSIZE];
15296 	char viewbuf[DNS_NAME_FORMATSIZE];
15297 	isc_stdtime_t now, when;
15298 	isc_time_t t;
15299 	char tbuf[64];
15300 	const char *msg = NULL;
15301 	bool dump = false, force = false;
15302 	dns_fixedname_t fn;
15303 	const dns_name_t *ntaname;
15304 	dns_name_t *fname;
15305 	dns_ttl_t ntattl;
15306 	bool ttlset = false, excl = false, viewfound = false;
15307 	dns_rdataclass_t rdclass = dns_rdataclass_in;
15308 	bool first = true;
15309 
15310 	REQUIRE(text != NULL);
15311 
15312 	UNUSED(force);
15313 
15314 	fname = dns_fixedname_initname(&fn);
15315 
15316 	/* Skip the command name. */
15317 	ptr = next_token(lex, text);
15318 	if (ptr == NULL) {
15319 		return (ISC_R_UNEXPECTEDEND);
15320 	}
15321 
15322 	for (;;) {
15323 		/* Check for options */
15324 		ptr = next_token(lex, text);
15325 		if (ptr == NULL) {
15326 			return (ISC_R_UNEXPECTEDEND);
15327 		}
15328 
15329 		if (strcmp(ptr, "--") == 0) {
15330 			break;
15331 		} else if (argcheck(ptr, "dump")) {
15332 			dump = true;
15333 		} else if (argcheck(ptr, "remove")) {
15334 			ntattl = 0;
15335 			ttlset = true;
15336 		} else if (argcheck(ptr, "force")) {
15337 			force = true;
15338 			continue;
15339 		} else if (argcheck(ptr, "lifetime")) {
15340 			isc_textregion_t tr;
15341 
15342 			ptr = next_token(lex, text);
15343 			if (ptr == NULL) {
15344 				msg = "No lifetime specified";
15345 				CHECK(ISC_R_UNEXPECTEDEND);
15346 			}
15347 
15348 			tr.base = ptr;
15349 			tr.length = strlen(ptr);
15350 			result = dns_ttl_fromtext(&tr, &ntattl);
15351 			if (result != ISC_R_SUCCESS) {
15352 				msg = "could not parse NTA lifetime";
15353 				CHECK(result);
15354 			}
15355 
15356 			if (ntattl > 604800) {
15357 				msg = "NTA lifetime cannot exceed one week";
15358 				CHECK(ISC_R_RANGE);
15359 			}
15360 
15361 			ttlset = true;
15362 			continue;
15363 		} else if (argcheck(ptr, "class")) {
15364 			isc_textregion_t tr;
15365 
15366 			ptr = next_token(lex, text);
15367 			if (ptr == NULL) {
15368 				msg = "No class specified";
15369 				CHECK(ISC_R_UNEXPECTEDEND);
15370 			}
15371 
15372 			tr.base = ptr;
15373 			tr.length = strlen(ptr);
15374 			CHECK(dns_rdataclass_fromtext(&rdclass, &tr));
15375 			continue;
15376 		} else if (ptr[0] == '-') {
15377 			msg = "Unknown option";
15378 			CHECK(DNS_R_SYNTAX);
15379 		} else {
15380 			nametext = ptr;
15381 		}
15382 
15383 		break;
15384 	}
15385 
15386 	/*
15387 	 * If -dump was specified, list NTA's and return
15388 	 */
15389 	if (dump) {
15390 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15391 		     view = ISC_LIST_NEXT(view, link))
15392 		{
15393 			if (ntatable != NULL) {
15394 				dns_ntatable_detach(&ntatable);
15395 			}
15396 			result = dns_view_getntatable(view, &ntatable);
15397 			if (result == ISC_R_NOTFOUND) {
15398 				continue;
15399 			}
15400 
15401 			CHECK(dns_ntatable_totext(ntatable, view->name, text));
15402 		}
15403 		CHECK(putnull(text));
15404 
15405 		goto cleanup;
15406 	}
15407 
15408 	if (readonly) {
15409 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15410 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
15411 			      "rejecting restricted control channel "
15412 			      "NTA command");
15413 		CHECK(ISC_R_FAILURE);
15414 	}
15415 
15416 	/* Get the NTA name if not found above. */
15417 	if (nametext == NULL) {
15418 		nametext = next_token(lex, text);
15419 	}
15420 	if (nametext == NULL) {
15421 		return (ISC_R_UNEXPECTEDEND);
15422 	}
15423 
15424 	/* Copy nametext as it'll be overwritten by next_token() */
15425 	strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE);
15426 
15427 	if (strcmp(namebuf, ".") == 0) {
15428 		ntaname = dns_rootname;
15429 	} else {
15430 		isc_buffer_t b;
15431 		isc_buffer_init(&b, namebuf, strlen(namebuf));
15432 		isc_buffer_add(&b, strlen(namebuf));
15433 		CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL));
15434 		ntaname = fname;
15435 	}
15436 
15437 	/* Look for the view name. */
15438 	viewname = next_token(lex, text);
15439 	if (viewname != NULL) {
15440 		strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE);
15441 		viewname = viewbuf;
15442 	}
15443 
15444 	if (next_token(lex, text) != NULL) {
15445 		CHECK(DNS_R_SYNTAX);
15446 	}
15447 
15448 	isc_stdtime_get(&now);
15449 
15450 	result = isc_task_beginexclusive(server->task);
15451 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
15452 	excl = true;
15453 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15454 	     view = ISC_LIST_NEXT(view, link))
15455 	{
15456 		if (viewname != NULL && strcmp(view->name, viewname) != 0) {
15457 			continue;
15458 		}
15459 		viewfound = true;
15460 
15461 		if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) {
15462 			continue;
15463 		}
15464 
15465 		if (view->nta_lifetime == 0) {
15466 			continue;
15467 		}
15468 
15469 		if (!ttlset) {
15470 			ntattl = view->nta_lifetime;
15471 		}
15472 
15473 		if (ntatable != NULL) {
15474 			dns_ntatable_detach(&ntatable);
15475 		}
15476 
15477 		result = dns_view_getntatable(view, &ntatable);
15478 		if (result == ISC_R_NOTFOUND) {
15479 			result = ISC_R_SUCCESS;
15480 			continue;
15481 		}
15482 
15483 		result = dns_view_flushnode(view, ntaname, true);
15484 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15485 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15486 			      "flush tree '%s' in cache view '%s': %s", namebuf,
15487 			      view->name, isc_result_totext(result));
15488 
15489 		if (ntattl != 0) {
15490 			CHECK(dns_ntatable_add(ntatable, ntaname, force, now,
15491 					       ntattl));
15492 
15493 			when = now + ntattl;
15494 			isc_time_set(&t, when, 0);
15495 			isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
15496 
15497 			if (!first) {
15498 				CHECK(putstr(text, "\n"));
15499 			}
15500 			first = false;
15501 
15502 			CHECK(putstr(text, "Negative trust anchor added: "));
15503 			CHECK(putstr(text, namebuf));
15504 			CHECK(putstr(text, "/"));
15505 			CHECK(putstr(text, view->name));
15506 			CHECK(putstr(text, ", expires "));
15507 			CHECK(putstr(text, tbuf));
15508 
15509 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15510 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15511 				      "added NTA '%s' (%d sec) in view '%s'",
15512 				      namebuf, ntattl, view->name);
15513 		} else {
15514 			bool wasremoved;
15515 
15516 			result = dns_ntatable_delete(ntatable, ntaname);
15517 			if (result == ISC_R_SUCCESS) {
15518 				wasremoved = true;
15519 			} else if (result == ISC_R_NOTFOUND) {
15520 				wasremoved = false;
15521 			} else {
15522 				goto cleanup;
15523 			}
15524 
15525 			if (!first) {
15526 				CHECK(putstr(text, "\n"));
15527 			}
15528 			first = false;
15529 
15530 			CHECK(putstr(text, "Negative trust anchor "));
15531 			CHECK(putstr(text,
15532 				     wasremoved ? "removed: " : "not found: "));
15533 			CHECK(putstr(text, namebuf));
15534 			CHECK(putstr(text, "/"));
15535 			CHECK(putstr(text, view->name));
15536 
15537 			if (wasremoved) {
15538 				isc_log_write(
15539 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15540 					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15541 					"removed NTA '%s' in view %s", namebuf,
15542 					view->name);
15543 			}
15544 		}
15545 
15546 		result = dns_view_saventa(view);
15547 		if (result != ISC_R_SUCCESS) {
15548 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15549 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15550 				      "error writing NTA file "
15551 				      "for view '%s': %s",
15552 				      view->name, isc_result_totext(result));
15553 		}
15554 	}
15555 
15556 	if (!viewfound) {
15557 		msg = "No such view";
15558 		CHECK(ISC_R_NOTFOUND);
15559 	}
15560 
15561 	(void)putnull(text);
15562 
15563 cleanup:
15564 	if (msg != NULL) {
15565 		(void)putstr(text, msg);
15566 		(void)putnull(text);
15567 	}
15568 
15569 	if (excl) {
15570 		isc_task_endexclusive(server->task);
15571 	}
15572 	if (ntatable != NULL) {
15573 		dns_ntatable_detach(&ntatable);
15574 	}
15575 	return (result);
15576 }
15577 
15578 isc_result_t
named_server_saventa(named_server_t * server)15579 named_server_saventa(named_server_t *server) {
15580 	dns_view_t *view;
15581 
15582 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15583 	     view = ISC_LIST_NEXT(view, link))
15584 	{
15585 		isc_result_t result = dns_view_saventa(view);
15586 
15587 		if (result != ISC_R_SUCCESS) {
15588 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15589 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15590 				      "error writing NTA file "
15591 				      "for view '%s': %s",
15592 				      view->name, isc_result_totext(result));
15593 		}
15594 	}
15595 
15596 	return (ISC_R_SUCCESS);
15597 }
15598 
15599 isc_result_t
named_server_loadnta(named_server_t * server)15600 named_server_loadnta(named_server_t *server) {
15601 	dns_view_t *view;
15602 
15603 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15604 	     view = ISC_LIST_NEXT(view, link))
15605 	{
15606 		isc_result_t result = dns_view_loadnta(view);
15607 
15608 		if ((result != ISC_R_SUCCESS) &&
15609 		    (result != ISC_R_FILENOTFOUND) &&
15610 		    (result != ISC_R_NOTFOUND))
15611 		{
15612 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15613 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15614 				      "error loading NTA file "
15615 				      "for view '%s': %s",
15616 				      view->name, isc_result_totext(result));
15617 		}
15618 	}
15619 
15620 	return (ISC_R_SUCCESS);
15621 }
15622 
15623 static isc_result_t
mkey_refresh(dns_view_t * view,isc_buffer_t ** text)15624 mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
15625 	isc_result_t result;
15626 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
15627 
15628 	snprintf(msg, sizeof(msg), "refreshing managed keys for '%s'",
15629 		 view->name);
15630 	CHECK(putstr(text, msg));
15631 	CHECK(dns_zone_synckeyzone(view->managed_keys));
15632 
15633 cleanup:
15634 	return (result);
15635 }
15636 
15637 static isc_result_t
mkey_destroy(named_server_t * server,dns_view_t * view,isc_buffer_t ** text)15638 mkey_destroy(named_server_t *server, dns_view_t *view, isc_buffer_t **text) {
15639 	isc_result_t result;
15640 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
15641 	bool exclusive = false;
15642 	const char *file = NULL;
15643 	dns_db_t *dbp = NULL;
15644 	dns_zone_t *mkzone = NULL;
15645 	bool removed_a_file = false;
15646 
15647 	if (view->managed_keys == NULL) {
15648 		CHECK(ISC_R_NOTFOUND);
15649 	}
15650 
15651 	snprintf(msg, sizeof(msg), "destroying managed-keys database for '%s'",
15652 		 view->name);
15653 	CHECK(putstr(text, msg));
15654 
15655 	result = isc_task_beginexclusive(server->task);
15656 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
15657 	exclusive = true;
15658 
15659 	/* Remove and clean up managed keys zone from view */
15660 	mkzone = view->managed_keys;
15661 	view->managed_keys = NULL;
15662 	(void)dns_zone_flush(mkzone);
15663 
15664 	/* Unload zone database */
15665 	if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) {
15666 		dns_db_detach(&dbp);
15667 		dns_zone_unload(mkzone);
15668 	}
15669 
15670 	/* Delete files */
15671 	file = dns_zone_getfile(mkzone);
15672 	result = isc_file_remove(file);
15673 	if (result == ISC_R_SUCCESS) {
15674 		removed_a_file = true;
15675 	} else {
15676 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15677 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
15678 			      "file %s not removed: %s", file,
15679 			      isc_result_totext(result));
15680 	}
15681 
15682 	file = dns_zone_getjournal(mkzone);
15683 	result = isc_file_remove(file);
15684 	if (result == ISC_R_SUCCESS) {
15685 		removed_a_file = true;
15686 	} else {
15687 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15688 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
15689 			      "file %s not removed: %s", file,
15690 			      isc_result_totext(result));
15691 	}
15692 
15693 	if (!removed_a_file) {
15694 		CHECK(putstr(text, "error: no files could be removed"));
15695 		CHECK(ISC_R_FAILURE);
15696 	}
15697 
15698 	dns_zone_detach(&mkzone);
15699 	result = ISC_R_SUCCESS;
15700 
15701 cleanup:
15702 	if (exclusive) {
15703 		isc_task_endexclusive(server->task);
15704 	}
15705 	return (result);
15706 }
15707 
15708 static isc_result_t
mkey_dumpzone(dns_view_t * view,isc_buffer_t ** text)15709 mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
15710 	isc_result_t result;
15711 	dns_db_t *db = NULL;
15712 	dns_dbversion_t *ver = NULL;
15713 	dns_rriterator_t rrit;
15714 	isc_stdtime_t now;
15715 	dns_name_t *prevname = NULL;
15716 
15717 	isc_stdtime_get(&now);
15718 
15719 	CHECK(dns_zone_getdb(view->managed_keys, &db));
15720 	dns_db_currentversion(db, &ver);
15721 	dns_rriterator_init(&rrit, db, ver, 0);
15722 	for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS;
15723 	     result = dns_rriterator_nextrrset(&rrit))
15724 	{
15725 		char buf[DNS_NAME_FORMATSIZE + 500];
15726 		dns_name_t *name = NULL;
15727 		dns_rdataset_t *kdset = NULL;
15728 		dns_rdata_t rdata = DNS_RDATA_INIT;
15729 		dns_rdata_keydata_t kd;
15730 		uint32_t ttl;
15731 
15732 		dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
15733 		if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
15734 		    !dns_rdataset_isassociated(kdset))
15735 		{
15736 			continue;
15737 		}
15738 
15739 		if (name != prevname) {
15740 			char nbuf[DNS_NAME_FORMATSIZE];
15741 			dns_name_format(name, nbuf, sizeof(nbuf));
15742 			snprintf(buf, sizeof(buf), "\n\n    name: %s", nbuf);
15743 			CHECK(putstr(text, buf));
15744 		}
15745 
15746 		for (result = dns_rdataset_first(kdset);
15747 		     result == ISC_R_SUCCESS; result = dns_rdataset_next(kdset))
15748 		{
15749 			char alg[DNS_SECALG_FORMATSIZE];
15750 			char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15751 			dns_keytag_t keyid;
15752 			isc_region_t r;
15753 			isc_time_t t;
15754 			bool revoked;
15755 
15756 			dns_rdata_reset(&rdata);
15757 			dns_rdataset_current(kdset, &rdata);
15758 			result = dns_rdata_tostruct(&rdata, &kd, NULL);
15759 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
15760 
15761 			dns_rdata_toregion(&rdata, &r);
15762 			isc_region_consume(&r, 12);
15763 			keyid = dst_region_computeid(&r);
15764 
15765 			snprintf(buf, sizeof(buf), "\n    keyid: %u", keyid);
15766 			CHECK(putstr(text, buf));
15767 
15768 			dns_secalg_format(kd.algorithm, alg, sizeof(alg));
15769 			snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
15770 			CHECK(putstr(text, buf));
15771 
15772 			revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
15773 			snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
15774 				 revoked ? " REVOKE" : "",
15775 				 ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP"
15776 								     : "",
15777 				 (kd.flags == 0) ? " (none)" : "");
15778 			CHECK(putstr(text, buf));
15779 
15780 			isc_time_set(&t, kd.refresh, 0);
15781 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
15782 			snprintf(buf, sizeof(buf), "\n\tnext refresh: %s",
15783 				 tbuf);
15784 			CHECK(putstr(text, buf));
15785 
15786 			if (kd.removehd != 0) {
15787 				isc_time_set(&t, kd.removehd, 0);
15788 				isc_time_formathttptimestamp(&t, tbuf,
15789 							     sizeof(tbuf));
15790 				snprintf(buf, sizeof(buf), "\n\tremove at: %s",
15791 					 tbuf);
15792 				CHECK(putstr(text, buf));
15793 			}
15794 
15795 			isc_time_set(&t, kd.addhd, 0);
15796 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
15797 			if (kd.addhd == 0) {
15798 				snprintf(buf, sizeof(buf), "\n\tno trust");
15799 			} else if (revoked) {
15800 				snprintf(buf, sizeof(buf), "\n\ttrust revoked");
15801 			} else if (kd.addhd <= now) {
15802 				snprintf(buf, sizeof(buf),
15803 					 "\n\ttrusted since: %s", tbuf);
15804 			} else if (kd.addhd > now) {
15805 				snprintf(buf, sizeof(buf),
15806 					 "\n\ttrust pending: %s", tbuf);
15807 			}
15808 			CHECK(putstr(text, buf));
15809 		}
15810 	}
15811 
15812 	if (result == ISC_R_NOMORE) {
15813 		result = ISC_R_SUCCESS;
15814 	}
15815 
15816 cleanup:
15817 	if (ver != NULL) {
15818 		dns_rriterator_destroy(&rrit);
15819 		dns_db_closeversion(db, &ver, false);
15820 	}
15821 	if (db != NULL) {
15822 		dns_db_detach(&db);
15823 	}
15824 
15825 	return (result);
15826 }
15827 
15828 static isc_result_t
mkey_status(dns_view_t * view,isc_buffer_t ** text)15829 mkey_status(dns_view_t *view, isc_buffer_t **text) {
15830 	isc_result_t result;
15831 	char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
15832 	isc_time_t t;
15833 
15834 	CHECK(putstr(text, "view: "));
15835 	CHECK(putstr(text, view->name));
15836 
15837 	CHECK(putstr(text, "\nnext scheduled event: "));
15838 
15839 	dns_zone_getrefreshkeytime(view->managed_keys, &t);
15840 	if (isc_time_isepoch(&t)) {
15841 		CHECK(putstr(text, "never"));
15842 	} else {
15843 		isc_time_formathttptimestamp(&t, msg, sizeof(msg));
15844 		CHECK(putstr(text, msg));
15845 	}
15846 
15847 	CHECK(mkey_dumpzone(view, text));
15848 
15849 cleanup:
15850 	return (result);
15851 }
15852 
15853 isc_result_t
named_server_mkeys(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)15854 named_server_mkeys(named_server_t *server, isc_lex_t *lex,
15855 		   isc_buffer_t **text) {
15856 	char *cmd, *classtxt, *viewtxt = NULL;
15857 	isc_result_t result = ISC_R_SUCCESS;
15858 	dns_view_t *view = NULL;
15859 	dns_rdataclass_t rdclass;
15860 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
15861 	enum { NONE, STATUS, REFRESH, SYNC, DESTROY } opt = NONE;
15862 	bool found = false;
15863 	bool first = true;
15864 
15865 	REQUIRE(text != NULL);
15866 
15867 	/* Skip rndc command name */
15868 	cmd = next_token(lex, text);
15869 	if (cmd == NULL) {
15870 		return (ISC_R_UNEXPECTEDEND);
15871 	}
15872 
15873 	/* Get managed-keys subcommand */
15874 	cmd = next_token(lex, text);
15875 	if (cmd == NULL) {
15876 		return (ISC_R_UNEXPECTEDEND);
15877 	}
15878 
15879 	if (strcasecmp(cmd, "status") == 0) {
15880 		opt = STATUS;
15881 	} else if (strcasecmp(cmd, "refresh") == 0) {
15882 		opt = REFRESH;
15883 	} else if (strcasecmp(cmd, "sync") == 0) {
15884 		opt = SYNC;
15885 	} else if (strcasecmp(cmd, "destroy") == 0) {
15886 		opt = DESTROY;
15887 	} else {
15888 		snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
15889 		(void)putstr(text, msg);
15890 		result = ISC_R_UNEXPECTED;
15891 		goto cleanup;
15892 	}
15893 
15894 	/* Look for the optional class name. */
15895 	classtxt = next_token(lex, text);
15896 	if (classtxt != NULL) {
15897 		isc_textregion_t r;
15898 		r.base = classtxt;
15899 		r.length = strlen(classtxt);
15900 		result = dns_rdataclass_fromtext(&rdclass, &r);
15901 		if (result != ISC_R_SUCCESS) {
15902 			snprintf(msg, sizeof(msg), "unknown class '%s'",
15903 				 classtxt);
15904 			(void)putstr(text, msg);
15905 			goto cleanup;
15906 		}
15907 		viewtxt = next_token(lex, text);
15908 	}
15909 
15910 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15911 	     view = ISC_LIST_NEXT(view, link))
15912 	{
15913 		if (viewtxt != NULL && (rdclass != view->rdclass ||
15914 					strcmp(view->name, viewtxt) != 0))
15915 		{
15916 			continue;
15917 		}
15918 
15919 		if (view->managed_keys == NULL) {
15920 			if (viewtxt != NULL) {
15921 				snprintf(msg, sizeof(msg),
15922 					 "view '%s': no managed keys", viewtxt);
15923 				CHECK(putstr(text, msg));
15924 				goto cleanup;
15925 			} else {
15926 				continue;
15927 			}
15928 		}
15929 
15930 		found = true;
15931 
15932 		switch (opt) {
15933 		case REFRESH:
15934 			if (!first) {
15935 				CHECK(putstr(text, "\n"));
15936 			}
15937 			CHECK(mkey_refresh(view, text));
15938 			break;
15939 		case STATUS:
15940 			if (!first) {
15941 				CHECK(putstr(text, "\n\n"));
15942 			}
15943 			CHECK(mkey_status(view, text));
15944 			break;
15945 		case SYNC:
15946 			CHECK(dns_zone_flush(view->managed_keys));
15947 			break;
15948 		case DESTROY:
15949 			if (!first) {
15950 				CHECK(putstr(text, "\n"));
15951 			}
15952 			CHECK(mkey_destroy(server, view, text));
15953 			break;
15954 		default:
15955 			UNREACHABLE();
15956 		}
15957 
15958 		if (viewtxt != NULL) {
15959 			break;
15960 		}
15961 		first = false;
15962 	}
15963 
15964 	if (!found) {
15965 		CHECK(putstr(text, "no views with managed keys"));
15966 	}
15967 
15968 cleanup:
15969 	if (isc_buffer_usedlength(*text) > 0) {
15970 		(void)putnull(text);
15971 	}
15972 
15973 	return (result);
15974 }
15975 
15976 isc_result_t
named_server_dnstap(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)15977 named_server_dnstap(named_server_t *server, isc_lex_t *lex,
15978 		    isc_buffer_t **text) {
15979 #ifdef HAVE_DNSTAP
15980 	char *ptr;
15981 	isc_result_t result;
15982 	bool reopen = false;
15983 	int backups = 0;
15984 
15985 	REQUIRE(text != NULL);
15986 
15987 	if (server->dtenv == NULL) {
15988 		return (ISC_R_NOTFOUND);
15989 	}
15990 
15991 	/* Check the command name. */
15992 	ptr = next_token(lex, text);
15993 	if (ptr == NULL) {
15994 		return (ISC_R_UNEXPECTEDEND);
15995 	}
15996 
15997 	/* "dnstap-reopen" was used in 9.11.0b1 */
15998 	if (strcasecmp(ptr, "dnstap-reopen") == 0) {
15999 		reopen = true;
16000 	} else {
16001 		ptr = next_token(lex, text);
16002 		if (ptr == NULL) {
16003 			return (ISC_R_UNEXPECTEDEND);
16004 		}
16005 	}
16006 
16007 	if (reopen || strcasecmp(ptr, "-reopen") == 0) {
16008 		backups = ISC_LOG_ROLLNEVER;
16009 	} else if ((strcasecmp(ptr, "-roll") == 0)) {
16010 		unsigned int n;
16011 		ptr = next_token(lex, text);
16012 		if (ptr != NULL) {
16013 			unsigned int u;
16014 			n = sscanf(ptr, "%u", &u);
16015 			if (n != 1U || u > INT_MAX) {
16016 				return (ISC_R_BADNUMBER);
16017 			}
16018 			backups = u;
16019 		} else {
16020 			backups = ISC_LOG_ROLLINFINITE;
16021 		}
16022 	} else {
16023 		return (DNS_R_SYNTAX);
16024 	}
16025 
16026 	result = dns_dt_reopen(server->dtenv, backups);
16027 	return (result);
16028 #else  /* ifdef HAVE_DNSTAP */
16029 	UNUSED(server);
16030 	UNUSED(lex);
16031 	UNUSED(text);
16032 	return (ISC_R_NOTIMPLEMENTED);
16033 #endif /* ifdef HAVE_DNSTAP */
16034 }
16035 
16036 isc_result_t
named_server_tcptimeouts(isc_lex_t * lex,isc_buffer_t ** text)16037 named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) {
16038 	char *ptr;
16039 	isc_result_t result = ISC_R_SUCCESS;
16040 	uint32_t initial, idle, keepalive, advertised;
16041 	char msg[128];
16042 
16043 	/* Skip the command name. */
16044 	ptr = next_token(lex, text);
16045 	if (ptr == NULL) {
16046 		return (ISC_R_UNEXPECTEDEND);
16047 	}
16048 
16049 	isc_nm_gettimeouts(named_g_nm, &initial, &idle, &keepalive,
16050 			   &advertised);
16051 
16052 	/* Look for optional arguments. */
16053 	ptr = next_token(lex, NULL);
16054 	if (ptr != NULL) {
16055 		CHECK(isc_parse_uint32(&initial, ptr, 10));
16056 		initial *= 100;
16057 		if (initial > MAX_INITIAL_TIMEOUT) {
16058 			CHECK(ISC_R_RANGE);
16059 		}
16060 		if (initial < MIN_INITIAL_TIMEOUT) {
16061 			CHECK(ISC_R_RANGE);
16062 		}
16063 
16064 		ptr = next_token(lex, text);
16065 		if (ptr == NULL) {
16066 			return (ISC_R_UNEXPECTEDEND);
16067 		}
16068 		CHECK(isc_parse_uint32(&idle, ptr, 10));
16069 		idle *= 100;
16070 		if (idle > MAX_IDLE_TIMEOUT) {
16071 			CHECK(ISC_R_RANGE);
16072 		}
16073 		if (idle < MIN_IDLE_TIMEOUT) {
16074 			CHECK(ISC_R_RANGE);
16075 		}
16076 
16077 		ptr = next_token(lex, text);
16078 		if (ptr == NULL) {
16079 			return (ISC_R_UNEXPECTEDEND);
16080 		}
16081 		CHECK(isc_parse_uint32(&keepalive, ptr, 10));
16082 		keepalive *= 100;
16083 		if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
16084 			CHECK(ISC_R_RANGE);
16085 		}
16086 		if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
16087 			CHECK(ISC_R_RANGE);
16088 		}
16089 
16090 		ptr = next_token(lex, text);
16091 		if (ptr == NULL) {
16092 			return (ISC_R_UNEXPECTEDEND);
16093 		}
16094 		CHECK(isc_parse_uint32(&advertised, ptr, 10));
16095 		advertised *= 100;
16096 		if (advertised > MAX_ADVERTISED_TIMEOUT) {
16097 			CHECK(ISC_R_RANGE);
16098 		}
16099 
16100 		result = isc_task_beginexclusive(named_g_server->task);
16101 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
16102 
16103 		isc_nm_settimeouts(named_g_nm, initial, idle, keepalive,
16104 				   advertised);
16105 
16106 		isc_task_endexclusive(named_g_server->task);
16107 	}
16108 
16109 	snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100);
16110 	CHECK(putstr(text, msg));
16111 	snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100);
16112 	CHECK(putstr(text, msg));
16113 	snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n",
16114 		 keepalive / 100);
16115 	CHECK(putstr(text, msg));
16116 	snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u",
16117 		 advertised / 100);
16118 	CHECK(putstr(text, msg));
16119 
16120 cleanup:
16121 	if (isc_buffer_usedlength(*text) > 0) {
16122 		(void)putnull(text);
16123 	}
16124 
16125 	return (result);
16126 }
16127 
16128 isc_result_t
named_server_servestale(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)16129 named_server_servestale(named_server_t *server, isc_lex_t *lex,
16130 			isc_buffer_t **text) {
16131 	char *ptr, *classtxt, *viewtxt = NULL;
16132 	char msg[128];
16133 	dns_rdataclass_t rdclass = dns_rdataclass_in;
16134 	dns_view_t *view;
16135 	bool found = false;
16136 	dns_stale_answer_t staleanswersok = dns_stale_answer_conf;
16137 	bool wantstatus = false;
16138 	isc_result_t result = ISC_R_SUCCESS;
16139 	bool exclusive = false;
16140 
16141 	REQUIRE(text != NULL);
16142 
16143 	/* Skip the command name. */
16144 	ptr = next_token(lex, text);
16145 	if (ptr == NULL) {
16146 		return (ISC_R_UNEXPECTEDEND);
16147 	}
16148 
16149 	ptr = next_token(lex, NULL);
16150 	if (ptr == NULL) {
16151 		return (ISC_R_UNEXPECTEDEND);
16152 	}
16153 
16154 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
16155 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
16156 	{
16157 		staleanswersok = dns_stale_answer_yes;
16158 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
16159 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
16160 	{
16161 		staleanswersok = dns_stale_answer_no;
16162 	} else if (strcasecmp(ptr, "reset") == 0) {
16163 		staleanswersok = dns_stale_answer_conf;
16164 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
16165 		wantstatus = true;
16166 	} else {
16167 		return (DNS_R_SYNTAX);
16168 	}
16169 
16170 	/* Look for the optional class name. */
16171 	classtxt = next_token(lex, text);
16172 	if (classtxt != NULL) {
16173 		isc_textregion_t r;
16174 
16175 		/* Look for the optional view name. */
16176 		viewtxt = next_token(lex, text);
16177 
16178 		/*
16179 		 * If 'classtext' is not a valid class then it us a view name.
16180 		 */
16181 		r.base = classtxt;
16182 		r.length = strlen(classtxt);
16183 		result = dns_rdataclass_fromtext(&rdclass, &r);
16184 		if (result != ISC_R_SUCCESS) {
16185 			if (viewtxt != NULL) {
16186 				snprintf(msg, sizeof(msg), "unknown class '%s'",
16187 					 classtxt);
16188 				(void)putstr(text, msg);
16189 				goto cleanup;
16190 			}
16191 
16192 			viewtxt = classtxt;
16193 			classtxt = NULL;
16194 		}
16195 	}
16196 
16197 	result = isc_task_beginexclusive(server->task);
16198 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
16199 	exclusive = true;
16200 
16201 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16202 	     view = ISC_LIST_NEXT(view, link))
16203 	{
16204 		dns_ttl_t stale_ttl = 0;
16205 		uint32_t stale_refresh = 0;
16206 		dns_db_t *db = NULL;
16207 
16208 		if (classtxt != NULL && rdclass != view->rdclass) {
16209 			continue;
16210 		}
16211 
16212 		if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0) {
16213 			continue;
16214 		}
16215 
16216 		if (!wantstatus) {
16217 			view->staleanswersok = staleanswersok;
16218 			found = true;
16219 			continue;
16220 		}
16221 
16222 		db = NULL;
16223 		dns_db_attach(view->cachedb, &db);
16224 		(void)dns_db_getservestalettl(db, &stale_ttl);
16225 		(void)dns_db_getservestalerefresh(db, &stale_refresh);
16226 		dns_db_detach(&db);
16227 		if (found) {
16228 			CHECK(putstr(text, "\n"));
16229 		}
16230 		CHECK(putstr(text, view->name));
16231 		CHECK(putstr(text, ": "));
16232 		switch (view->staleanswersok) {
16233 		case dns_stale_answer_yes:
16234 			if (stale_ttl > 0) {
16235 				CHECK(putstr(text, "on (rndc)"));
16236 			} else {
16237 				CHECK(putstr(text, "off (not-cached)"));
16238 			}
16239 			break;
16240 		case dns_stale_answer_no:
16241 			CHECK(putstr(text, "off (rndc)"));
16242 			break;
16243 		case dns_stale_answer_conf:
16244 			if (view->staleanswersenable && stale_ttl > 0) {
16245 				CHECK(putstr(text, "on"));
16246 			} else if (view->staleanswersenable) {
16247 				CHECK(putstr(text, "off (not-cached)"));
16248 			} else {
16249 				CHECK(putstr(text, "off"));
16250 			}
16251 			break;
16252 		}
16253 		if (stale_ttl > 0) {
16254 			snprintf(msg, sizeof(msg),
16255 				 " (stale-answer-ttl=%u max-stale-ttl=%u "
16256 				 "stale-refresh-time=%u)",
16257 				 view->staleanswerttl, stale_ttl,
16258 				 stale_refresh);
16259 			CHECK(putstr(text, msg));
16260 		}
16261 		found = true;
16262 	}
16263 
16264 	if (!found) {
16265 		result = ISC_R_NOTFOUND;
16266 	}
16267 
16268 cleanup:
16269 	if (exclusive) {
16270 		isc_task_endexclusive(named_g_server->task);
16271 	}
16272 
16273 	if (isc_buffer_usedlength(*text) > 0) {
16274 		(void)putnull(text);
16275 	}
16276 
16277 	return (result);
16278 }
16279