1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 /*! \file */
13 
14 #include <ctype.h>
15 #include <inttypes.h>
16 #include <limits.h>
17 #include <stdbool.h>
18 #include <stdlib.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 
23 #ifdef HAVE_DNSTAP
24 #include <fstrm.h>
25 #endif
26 
27 #include <isc/aes.h>
28 #include <isc/app.h>
29 #include <isc/attributes.h>
30 #include <isc/base64.h>
31 #include <isc/commandline.h>
32 #include <isc/dir.h>
33 #include <isc/file.h>
34 #include <isc/hash.h>
35 #include <isc/hex.h>
36 #include <isc/hmac.h>
37 #include <isc/httpd.h>
38 #include <isc/lex.h>
39 #include <isc/meminfo.h>
40 #include <isc/nonce.h>
41 #include <isc/parseint.h>
42 #include <isc/portset.h>
43 #include <isc/print.h>
44 #include <isc/refcount.h>
45 #include <isc/resource.h>
46 #include <isc/result.h>
47 #include <isc/siphash.h>
48 #include <isc/socket.h>
49 #include <isc/stat.h>
50 #include <isc/stats.h>
51 #include <isc/stdio.h>
52 #include <isc/string.h>
53 #include <isc/task.h>
54 #include <isc/timer.h>
55 #include <isc/util.h>
56 
57 #include <dns/adb.h>
58 #include <dns/badcache.h>
59 #include <dns/cache.h>
60 #include <dns/catz.h>
61 #include <dns/db.h>
62 #include <dns/dispatch.h>
63 #include <dns/dlz.h>
64 #include <dns/dns64.h>
65 #include <dns/dnsrps.h>
66 #include <dns/dnssec.h>
67 #include <dns/dyndb.h>
68 #include <dns/events.h>
69 #include <dns/fixedname.h>
70 #include <dns/forward.h>
71 #include <dns/geoip.h>
72 #include <dns/journal.h>
73 #include <dns/kasp.h>
74 #include <dns/keymgr.h>
75 #include <dns/keytable.h>
76 #include <dns/keyvalues.h>
77 #include <dns/master.h>
78 #include <dns/masterdump.h>
79 #include <dns/nsec3.h>
80 #include <dns/nta.h>
81 #include <dns/order.h>
82 #include <dns/peer.h>
83 #include <dns/private.h>
84 #include <dns/rbt.h>
85 #include <dns/rdataclass.h>
86 #include <dns/rdatalist.h>
87 #include <dns/rdataset.h>
88 #include <dns/rdatastruct.h>
89 #include <dns/resolver.h>
90 #include <dns/rootns.h>
91 #include <dns/rriterator.h>
92 #include <dns/secalg.h>
93 #include <dns/soa.h>
94 #include <dns/stats.h>
95 #include <dns/time.h>
96 #include <dns/tkey.h>
97 #include <dns/tsig.h>
98 #include <dns/ttl.h>
99 #include <dns/view.h>
100 #include <dns/zone.h>
101 #include <dns/zt.h>
102 
103 #include <dst/dst.h>
104 
105 #include <isccfg/grammar.h>
106 #include <isccfg/kaspconf.h>
107 #include <isccfg/namedconf.h>
108 
109 #include <ns/client.h>
110 #include <ns/hooks.h>
111 #include <ns/interfacemgr.h>
112 #include <ns/listenlist.h>
113 
114 #include <bind9/check.h>
115 
116 #include <named/config.h>
117 #include <named/control.h>
118 #if defined(HAVE_GEOIP2)
119 #include <named/geoip.h>
120 #endif /* HAVE_GEOIP2 */
121 #include <named/log.h>
122 #include <named/logconf.h>
123 #include <named/main.h>
124 #include <named/os.h>
125 #include <named/server.h>
126 #include <named/statschannel.h>
127 #include <named/tkeyconf.h>
128 #include <named/transportconf.h>
129 #include <named/tsigconf.h>
130 #include <named/zoneconf.h>
131 #ifdef HAVE_LIBSCF
132 #include <stdlib.h>
133 
134 #include <named/smf_globals.h>
135 #endif /* ifdef HAVE_LIBSCF */
136 
137 #ifdef HAVE_LMDB
138 #include <lmdb.h>
139 #define count_newzones	   count_newzones_db
140 #define configure_newzones configure_newzones_db
141 #define dumpzone	   dumpzone_db
142 #else /* HAVE_LMDB */
143 #define count_newzones	   count_newzones_file
144 #define configure_newzones configure_newzones_file
145 #define dumpzone	   dumpzone_file
146 #endif /* HAVE_LMDB */
147 
148 #ifndef SIZE_MAX
149 #define SIZE_MAX ((size_t)-1)
150 #endif /* ifndef SIZE_MAX */
151 
152 #ifndef SIZE_AS_PERCENT
153 #define SIZE_AS_PERCENT ((size_t)-2)
154 #endif /* ifndef SIZE_AS_PERCENT */
155 
156 #ifndef ARRAYSIZE
157 #define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
158 #endif
159 
160 #ifdef TUNE_LARGE
161 #define RESOLVER_NTASKS_PERCPU 32
162 #else
163 #define RESOLVER_NTASKS_PERCPU 8
164 #endif /* TUNE_LARGE */
165 
166 /* RFC7828 defines timeout as 16-bit value specified in units of 100
167  * milliseconds, so the maximum and minimum advertised and keepalive
168  * timeouts are capped by the data type (it's ~109 minutes)
169  */
170 #define MIN_INITIAL_TIMEOUT    UINT32_C(2500)	/* 2.5 seconds */
171 #define MAX_INITIAL_TIMEOUT    UINT32_C(120000) /* 2 minutes */
172 #define MIN_IDLE_TIMEOUT       UINT32_C(100)	/* 0.1 seconds */
173 #define MAX_IDLE_TIMEOUT       UINT32_C(120000) /* 2 minutes */
174 #define MIN_KEEPALIVE_TIMEOUT  UINT32_C(100)	/* 0.1 seconds */
175 #define MAX_KEEPALIVE_TIMEOUT  UINT32_C(UINT16_MAX * 100)
176 #define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */
177 #define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100)
178 
179 /*%
180  * Check an operation for failure.  Assumes that the function
181  * using it has a 'result' variable and a 'cleanup' label.
182  */
183 #define CHECK(op)                            \
184 	do {                                 \
185 		result = (op);               \
186 		if (result != ISC_R_SUCCESS) \
187 			goto cleanup;        \
188 	} while (0)
189 
190 #define TCHECK(op)                               \
191 	do {                                     \
192 		tresult = (op);                  \
193 		if (tresult != ISC_R_SUCCESS) {  \
194 			isc_buffer_clear(*text); \
195 			goto cleanup;            \
196 		}                                \
197 	} while (0)
198 
199 #define CHECKM(op, msg)                                                        \
200 	do {                                                                   \
201 		result = (op);                                                 \
202 		if (result != ISC_R_SUCCESS) {                                 \
203 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
204 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
205 				      "%s: %s", msg,                           \
206 				      isc_result_totext(result));              \
207 			goto cleanup;                                          \
208 		}                                                              \
209 	} while (0)
210 
211 #define CHECKMF(op, msg, file)                                                 \
212 	do {                                                                   \
213 		result = (op);                                                 \
214 		if (result != ISC_R_SUCCESS) {                                 \
215 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
216 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,   \
217 				      "%s '%s': %s", msg, file,                \
218 				      isc_result_totext(result));              \
219 			goto cleanup;                                          \
220 		}                                                              \
221 	} while (0)
222 
223 #define CHECKFATAL(op, msg)                         \
224 	do {                                        \
225 		result = (op);                      \
226 		if (result != ISC_R_SUCCESS)        \
227 			fatal(server, msg, result); \
228 	} while (0)
229 
230 /*%
231  * Maximum ADB size for views that share a cache.  Use this limit to suppress
232  * the total of memory footprint, which should be the main reason for sharing
233  * a cache.  Only effective when a finite max-cache-size is specified.
234  * This is currently defined to be 8MB.
235  */
236 #define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
237 
238 struct named_dispatch {
239 	isc_sockaddr_t addr;
240 	unsigned int dispatchgen;
241 	dns_dispatch_t *dispatch;
242 	ISC_LINK(struct named_dispatch) link;
243 };
244 
245 struct named_cache {
246 	dns_cache_t *cache;
247 	dns_view_t *primaryview;
248 	bool needflush;
249 	bool adbsizeadjusted;
250 	dns_rdataclass_t rdclass;
251 	ISC_LINK(named_cache_t) link;
252 };
253 
254 struct dumpcontext {
255 	isc_mem_t *mctx;
256 	bool dumpcache;
257 	bool dumpzones;
258 	bool dumpadb;
259 	bool dumpbad;
260 	bool dumpexpired;
261 	bool dumpfail;
262 	FILE *fp;
263 	ISC_LIST(struct viewlistentry) viewlist;
264 	struct viewlistentry *view;
265 	struct zonelistentry *zone;
266 	dns_dumpctx_t *mdctx;
267 	dns_db_t *db;
268 	dns_db_t *cache;
269 	isc_task_t *task;
270 	dns_dbversion_t *version;
271 };
272 
273 struct viewlistentry {
274 	dns_view_t *view;
275 	ISC_LINK(struct viewlistentry) link;
276 	ISC_LIST(struct zonelistentry) zonelist;
277 };
278 
279 struct zonelistentry {
280 	dns_zone_t *zone;
281 	ISC_LINK(struct zonelistentry) link;
282 };
283 
284 /*%
285  * Configuration context to retain for each view that allows
286  * new zones to be added at runtime.
287  */
288 typedef struct ns_cfgctx {
289 	isc_mem_t *mctx;
290 	cfg_parser_t *conf_parser;
291 	cfg_parser_t *add_parser;
292 	cfg_obj_t *config;
293 	cfg_obj_t *vconfig;
294 	cfg_obj_t *nzf_config;
295 	cfg_aclconfctx_t *actx;
296 } ns_cfgctx_t;
297 
298 /*%
299  * A function to write out added-zone configuration to the new_zone_file
300  * specified in 'view'. Maybe called by delete_zoneconf().
301  */
302 typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
303 
304 /*%
305  * Holds state information for the initial zone loading process.
306  * Uses the isc_refcount structure to count the number of views
307  * with pending zone loads, dereferencing as each view finishes.
308  */
309 typedef struct {
310 	named_server_t *server;
311 	bool reconfig;
312 	isc_refcount_t refs;
313 } ns_zoneload_t;
314 
315 typedef struct {
316 	named_server_t *server;
317 } catz_cb_data_t;
318 
319 typedef struct catz_chgzone_event {
320 	ISC_EVENT_COMMON(struct catz_chgzone_event);
321 	dns_catz_entry_t *entry;
322 	dns_catz_zone_t *origin;
323 	dns_view_t *view;
324 	catz_cb_data_t *cbd;
325 	bool mod;
326 } catz_chgzone_event_t;
327 
328 typedef struct {
329 	unsigned int magic;
330 #define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
331 	isc_buffer_t **text;
332 	isc_result_t result;
333 } ns_dzarg_t;
334 
335 /*
336  * These zones should not leak onto the Internet.
337  */
338 const char *empty_zones[] = {
339 	/* RFC 1918 */
340 	"10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
341 	"18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
342 	"21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
343 	"24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
344 	"27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
345 	"30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
346 
347 	/* RFC 6598 */
348 	"64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
349 	"67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
350 	"70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
351 	"73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
352 	"76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
353 	"79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
354 	"82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
355 	"85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
356 	"88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
357 	"91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
358 	"94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
359 	"97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
360 	"100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA", "102.100.IN-ADDR.ARPA",
361 	"103.100.IN-ADDR.ARPA", "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
362 	"106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA", "108.100.IN-ADDR.ARPA",
363 	"109.100.IN-ADDR.ARPA", "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
364 	"112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA", "114.100.IN-ADDR.ARPA",
365 	"115.100.IN-ADDR.ARPA", "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
366 	"118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA", "120.100.IN-ADDR.ARPA",
367 	"121.100.IN-ADDR.ARPA", "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
368 	"124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA", "126.100.IN-ADDR.ARPA",
369 	"127.100.IN-ADDR.ARPA",
370 
371 	/* RFC 5735 and RFC 5737 */
372 	"0.IN-ADDR.ARPA",		/* THIS NETWORK */
373 	"127.IN-ADDR.ARPA",		/* LOOPBACK */
374 	"254.169.IN-ADDR.ARPA",		/* LINK LOCAL */
375 	"2.0.192.IN-ADDR.ARPA",		/* TEST NET */
376 	"100.51.198.IN-ADDR.ARPA",	/* TEST NET 2 */
377 	"113.0.203.IN-ADDR.ARPA",	/* TEST NET 3 */
378 	"255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
379 
380 	/* Local IPv6 Unicast Addresses */
381 	"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6."
382 	"ARPA",
383 	"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6."
384 	"ARPA",
385 	/* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
386 	"D.F.IP6.ARPA", "8.E.F.IP6.ARPA", /* LINK LOCAL */
387 	"9.E.F.IP6.ARPA",		  /* LINK LOCAL */
388 	"A.E.F.IP6.ARPA",		  /* LINK LOCAL */
389 	"B.E.F.IP6.ARPA",		  /* LINK LOCAL */
390 
391 	/* Example Prefix, RFC 3849. */
392 	"8.B.D.0.1.0.0.2.IP6.ARPA",
393 
394 	/* RFC 7534 */
395 	"EMPTY.AS112.ARPA",
396 
397 	/* RFC 8375 */
398 	"HOME.ARPA",
399 
400 	NULL
401 };
402 
403 ISC_NORETURN static void
404 fatal(named_server_t *server, const char *msg, isc_result_t result);
405 
406 static void
407 named_server_reload(isc_task_t *task, isc_event_t *event);
408 
409 #ifdef HAVE_LIBNGHTTP2
410 static isc_result_t
411 listenelt_http(const cfg_obj_t *http, bool tls,
412 	       const ns_listen_tls_params_t *tls_params, in_port_t port,
413 	       isc_mem_t *mctx, ns_listenelt_t **target);
414 #endif
415 
416 static isc_result_t
417 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
418 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
419 		     ns_listenelt_t **target);
420 
421 static isc_result_t
422 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
423 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
424 		      ns_listenlist_t **target);
425 
426 static isc_result_t
427 configure_forward(const cfg_obj_t *config, dns_view_t *view,
428 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
429 		  const cfg_obj_t *forwardtype);
430 
431 static isc_result_t
432 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
433 		     const cfg_obj_t *alternates);
434 
435 static isc_result_t
436 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
437 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
438 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
439 	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
440 	       bool modify);
441 
442 static isc_result_t
443 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
444 		   isc_mem_t *mctx, cfg_aclconfctx_t *actx);
445 
446 static isc_result_t
447 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
448 
449 static void
450 end_reserved_dispatches(named_server_t *server, bool all);
451 
452 static void
453 newzone_cfgctx_destroy(void **cfgp);
454 
455 static inline isc_result_t
456 putstr(isc_buffer_t **b, const char *str);
457 
458 static isc_result_t
459 putmem(isc_buffer_t **b, const char *str, size_t len);
460 
461 static isc_result_t
462 putuint8(isc_buffer_t **b, uint8_t val);
463 
464 static inline isc_result_t
465 putnull(isc_buffer_t **b);
466 
467 static int
468 count_zones(const cfg_obj_t *conf);
469 
470 #ifdef HAVE_LMDB
471 static isc_result_t
472 migrate_nzf(dns_view_t *view);
473 
474 static isc_result_t
475 nzd_writable(dns_view_t *view);
476 
477 static isc_result_t
478 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
479 
480 static isc_result_t
481 nzd_env_reopen(dns_view_t *view);
482 
483 static void
484 nzd_env_close(dns_view_t *view);
485 
486 static isc_result_t
487 nzd_close(MDB_txn **txnp, bool commit);
488 
489 static isc_result_t
490 nzd_count(dns_view_t *view, int *countp);
491 #else  /* ifdef HAVE_LMDB */
492 static isc_result_t
493 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
494 #endif /* ifdef HAVE_LMDB */
495 
496 /*%
497  * Configure a single view ACL at '*aclp'.  Get its configuration from
498  * 'vconfig' (for per-view configuration) and maybe from 'config'
499  */
500 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)501 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
502 		   const cfg_obj_t *gconfig, const char *aclname,
503 		   const char *acltuplename, cfg_aclconfctx_t *actx,
504 		   isc_mem_t *mctx, dns_acl_t **aclp) {
505 	isc_result_t result;
506 	const cfg_obj_t *maps[4];
507 	const cfg_obj_t *aclobj = NULL;
508 	int i = 0;
509 
510 	if (*aclp != NULL) {
511 		dns_acl_detach(aclp);
512 	}
513 	if (vconfig != NULL) {
514 		maps[i++] = cfg_tuple_get(vconfig, "options");
515 	}
516 	if (config != NULL) {
517 		const cfg_obj_t *options = NULL;
518 		(void)cfg_map_get(config, "options", &options);
519 		if (options != NULL) {
520 			maps[i++] = options;
521 		}
522 	}
523 	if (gconfig != NULL) {
524 		const cfg_obj_t *options = NULL;
525 		(void)cfg_map_get(gconfig, "options", &options);
526 		if (options != NULL) {
527 			maps[i++] = options;
528 		}
529 	}
530 	maps[i] = NULL;
531 
532 	(void)named_config_get(maps, aclname, &aclobj);
533 	if (aclobj == NULL) {
534 		/*
535 		 * No value available.	*aclp == NULL.
536 		 */
537 		return (ISC_R_SUCCESS);
538 	}
539 
540 	if (acltuplename != NULL) {
541 		/*
542 		 * If the ACL is given in an optional tuple, retrieve it.
543 		 * The parser should have ensured that a valid object be
544 		 * returned.
545 		 */
546 		aclobj = cfg_tuple_get(aclobj, acltuplename);
547 	}
548 
549 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
550 				    aclp);
551 
552 	return (result);
553 }
554 
555 /*%
556  * Configure a sortlist at '*aclp'.  Essentially the same as
557  * configure_view_acl() except it calls cfg_acl_fromconfig with a
558  * nest_level value of 2.
559  */
560 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)561 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
562 			cfg_aclconfctx_t *actx, isc_mem_t *mctx,
563 			dns_acl_t **aclp) {
564 	isc_result_t result;
565 	const cfg_obj_t *maps[3];
566 	const cfg_obj_t *aclobj = NULL;
567 	int i = 0;
568 
569 	if (*aclp != NULL) {
570 		dns_acl_detach(aclp);
571 	}
572 	if (vconfig != NULL) {
573 		maps[i++] = cfg_tuple_get(vconfig, "options");
574 	}
575 	if (config != NULL) {
576 		const cfg_obj_t *options = NULL;
577 		(void)cfg_map_get(config, "options", &options);
578 		if (options != NULL) {
579 			maps[i++] = options;
580 		}
581 	}
582 	maps[i] = NULL;
583 
584 	(void)named_config_get(maps, "sortlist", &aclobj);
585 	if (aclobj == NULL) {
586 		return (ISC_R_SUCCESS);
587 	}
588 
589 	/*
590 	 * Use a nest level of 3 for the "top level" of the sortlist;
591 	 * this means each entry in the top three levels will be stored
592 	 * as lists of separate, nested ACLs, rather than merged together
593 	 * into IP tables as is usually done with ACLs.
594 	 */
595 	result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
596 				    aclp);
597 
598 	return (result);
599 }
600 
601 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)602 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
603 			 const char *confname, const char *conftuplename,
604 			 isc_mem_t *mctx, dns_rbt_t **rbtp) {
605 	isc_result_t result;
606 	const cfg_obj_t *maps[3];
607 	const cfg_obj_t *obj = NULL;
608 	const cfg_listelt_t *element;
609 	int i = 0;
610 	dns_fixedname_t fixed;
611 	dns_name_t *name;
612 	isc_buffer_t b;
613 	const char *str;
614 	const cfg_obj_t *nameobj;
615 
616 	if (*rbtp != NULL) {
617 		dns_rbt_destroy(rbtp);
618 	}
619 	if (vconfig != NULL) {
620 		maps[i++] = cfg_tuple_get(vconfig, "options");
621 	}
622 	if (config != NULL) {
623 		const cfg_obj_t *options = NULL;
624 		(void)cfg_map_get(config, "options", &options);
625 		if (options != NULL) {
626 			maps[i++] = options;
627 		}
628 	}
629 	maps[i] = NULL;
630 
631 	(void)named_config_get(maps, confname, &obj);
632 	if (obj == NULL) {
633 		/*
634 		 * No value available.	*rbtp == NULL.
635 		 */
636 		return (ISC_R_SUCCESS);
637 	}
638 
639 	if (conftuplename != NULL) {
640 		obj = cfg_tuple_get(obj, conftuplename);
641 		if (cfg_obj_isvoid(obj)) {
642 			return (ISC_R_SUCCESS);
643 		}
644 	}
645 
646 	result = dns_rbt_create(mctx, NULL, NULL, rbtp);
647 	if (result != ISC_R_SUCCESS) {
648 		return (result);
649 	}
650 
651 	name = dns_fixedname_initname(&fixed);
652 	for (element = cfg_list_first(obj); element != NULL;
653 	     element = cfg_list_next(element))
654 	{
655 		nameobj = cfg_listelt_value(element);
656 		str = cfg_obj_asstring(nameobj);
657 		isc_buffer_constinit(&b, str, strlen(str));
658 		isc_buffer_add(&b, strlen(str));
659 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
660 		/*
661 		 * We don't need the node data, but need to set dummy data to
662 		 * avoid a partial match with an empty node.  For example, if
663 		 * we have foo.example.com and bar.example.com, we'd get a match
664 		 * for baz.example.com, which is not the expected result.
665 		 * We simply use (void *)1 as the dummy data.
666 		 */
667 		result = dns_rbt_addname(*rbtp, name, (void *)1);
668 		if (result != ISC_R_SUCCESS) {
669 			cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
670 				    "failed to add %s for %s: %s", str,
671 				    confname, isc_result_totext(result));
672 			goto cleanup;
673 		}
674 	}
675 
676 	return (result);
677 
678 cleanup:
679 	dns_rbt_destroy(rbtp);
680 	return (result);
681 }
682 
683 static isc_result_t
ta_fromconfig(const cfg_obj_t * key,bool * initialp,const char ** namestrp,unsigned char * digest,dns_rdata_ds_t * ds)684 ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
685 	      unsigned char *digest, dns_rdata_ds_t *ds) {
686 	isc_result_t result;
687 	dns_rdata_dnskey_t keystruct;
688 	dns_rdata_t rdata = DNS_RDATA_INIT;
689 	uint32_t rdata1, rdata2, rdata3;
690 	const char *datastr = NULL, *namestr = NULL;
691 	unsigned char data[4096];
692 	isc_buffer_t databuf;
693 	unsigned char rrdata[4096];
694 	isc_buffer_t rrdatabuf;
695 	isc_region_t r;
696 	dns_fixedname_t fname;
697 	dns_name_t *name = NULL;
698 	isc_buffer_t namebuf;
699 	const char *atstr = NULL;
700 	enum {
701 		INIT_DNSKEY,
702 		STATIC_DNSKEY,
703 		INIT_DS,
704 		STATIC_DS,
705 		TRUSTED
706 	} anchortype;
707 
708 	REQUIRE(namestrp != NULL && *namestrp == NULL);
709 	REQUIRE(ds != NULL);
710 
711 	/* if DNSKEY, flags; if DS, key tag */
712 	rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
713 
714 	/* if DNSKEY, protocol; if DS, algorithm */
715 	rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
716 
717 	/* if DNSKEY, algorithm; if DS, digest type */
718 	rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3"));
719 
720 	namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
721 	*namestrp = namestr;
722 
723 	name = dns_fixedname_initname(&fname);
724 	isc_buffer_constinit(&namebuf, namestr, strlen(namestr));
725 	isc_buffer_add(&namebuf, strlen(namestr));
726 	CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL));
727 
728 	if (*initialp) {
729 		atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
730 
731 		if (strcasecmp(atstr, "static-key") == 0) {
732 			*initialp = false;
733 			anchortype = STATIC_DNSKEY;
734 		} else if (strcasecmp(atstr, "static-ds") == 0) {
735 			*initialp = false;
736 			anchortype = STATIC_DS;
737 		} else if (strcasecmp(atstr, "initial-key") == 0) {
738 			anchortype = INIT_DNSKEY;
739 		} else if (strcasecmp(atstr, "initial-ds") == 0) {
740 			anchortype = INIT_DS;
741 		} else {
742 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
743 				    "key '%s': "
744 				    "invalid initialization method '%s'",
745 				    namestr, atstr);
746 			result = ISC_R_FAILURE;
747 			goto cleanup;
748 		}
749 	} else {
750 		anchortype = TRUSTED;
751 	}
752 
753 	isc_buffer_init(&databuf, data, sizeof(data));
754 	isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
755 
756 	*ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
757 				.common.rdtype = dns_rdatatype_ds };
758 
759 	ISC_LINK_INIT(&ds->common, link);
760 
761 	switch (anchortype) {
762 	case INIT_DNSKEY:
763 	case STATIC_DNSKEY:
764 	case TRUSTED:
765 		/*
766 		 * This function should never be reached for view
767 		 * class other than IN
768 		 */
769 		keystruct.common.rdclass = dns_rdataclass_in;
770 		keystruct.common.rdtype = dns_rdatatype_dnskey;
771 
772 		/*
773 		 * The key data in keystruct is not dynamically allocated.
774 		 */
775 		keystruct.mctx = NULL;
776 
777 		ISC_LINK_INIT(&keystruct.common, link);
778 
779 		if (rdata1 > 0xffff) {
780 			CHECKM(ISC_R_RANGE, "key flags");
781 		}
782 		if (rdata1 & DNS_KEYFLAG_REVOKE) {
783 			CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
784 		}
785 		if (rdata2 > 0xff) {
786 			CHECKM(ISC_R_RANGE, "key protocol");
787 		}
788 		if (rdata3 > 0xff) {
789 			CHECKM(ISC_R_RANGE, "key algorithm");
790 		}
791 
792 		keystruct.flags = (uint16_t)rdata1;
793 		keystruct.protocol = (uint8_t)rdata2;
794 		keystruct.algorithm = (uint8_t)rdata3;
795 
796 		if (!dst_algorithm_supported(keystruct.algorithm)) {
797 			CHECK(DST_R_UNSUPPORTEDALG);
798 		}
799 
800 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
801 		CHECK(isc_base64_decodestring(datastr, &databuf));
802 		isc_buffer_usedregion(&databuf, &r);
803 		keystruct.datalen = r.length;
804 		keystruct.data = r.base;
805 
806 		CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
807 					   keystruct.common.rdtype, &keystruct,
808 					   &rrdatabuf));
809 		CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
810 					  digest, ds));
811 		break;
812 
813 	case INIT_DS:
814 	case STATIC_DS:
815 		if (rdata1 > 0xffff) {
816 			CHECKM(ISC_R_RANGE, "key tag");
817 		}
818 		if (rdata2 > 0xff) {
819 			CHECKM(ISC_R_RANGE, "key algorithm");
820 		}
821 		if (rdata3 > 0xff) {
822 			CHECKM(ISC_R_RANGE, "digest type");
823 		}
824 
825 		ds->key_tag = (uint16_t)rdata1;
826 		ds->algorithm = (uint8_t)rdata2;
827 		ds->digest_type = (uint8_t)rdata3;
828 
829 		datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
830 		CHECK(isc_hex_decodestring(datastr, &databuf));
831 		isc_buffer_usedregion(&databuf, &r);
832 
833 		switch (ds->digest_type) {
834 		case DNS_DSDIGEST_SHA1:
835 			if (r.length != ISC_SHA1_DIGESTLENGTH) {
836 				CHECK(ISC_R_UNEXPECTEDEND);
837 			}
838 			break;
839 		case DNS_DSDIGEST_SHA256:
840 			if (r.length != ISC_SHA256_DIGESTLENGTH) {
841 				CHECK(ISC_R_UNEXPECTEDEND);
842 			}
843 			break;
844 		case DNS_DSDIGEST_SHA384:
845 			if (r.length != ISC_SHA384_DIGESTLENGTH) {
846 				CHECK(ISC_R_UNEXPECTEDEND);
847 			}
848 			break;
849 		default:
850 			cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
851 				    "key '%s': "
852 				    "unknown ds digest type %u",
853 				    namestr, ds->digest_type);
854 			result = ISC_R_FAILURE;
855 			goto cleanup;
856 			break;
857 		}
858 
859 		ds->length = r.length;
860 		ds->digest = digest;
861 		memmove(ds->digest, r.base, r.length);
862 
863 		break;
864 
865 	default:
866 		INSIST(0);
867 		ISC_UNREACHABLE();
868 	}
869 
870 	return (ISC_R_SUCCESS);
871 
872 cleanup:
873 	return (result);
874 }
875 
876 /*%
877  * Parse 'key' in the context of view configuration 'vconfig'.  If successful,
878  * add the key to 'secroots' if both of the following conditions are true:
879  *
880  *   - 'keyname_match' is NULL or it matches the owner name of 'key',
881  *   - support for the algorithm used by 'key' is not disabled by 'resolver'
882  *     for the owner name of 'key'.
883  *
884  * 'managed' is true for managed keys and false for trusted keys.  'mctx' is
885  * the memory context to use for allocating memory.
886  */
887 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)888 process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
889 	    const dns_name_t *keyname_match, dns_resolver_t *resolver,
890 	    bool managed) {
891 	dns_fixedname_t fkeyname;
892 	dns_name_t *keyname = NULL;
893 	const char *namestr = NULL;
894 	dns_rdata_ds_t ds;
895 	isc_result_t result;
896 	bool initializing = managed;
897 	unsigned char digest[ISC_MAX_MD_SIZE];
898 	isc_buffer_t b;
899 
900 	result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
901 
902 	switch (result) {
903 	case ISC_R_SUCCESS:
904 		/*
905 		 * Trust anchor was parsed correctly.
906 		 */
907 		isc_buffer_constinit(&b, namestr, strlen(namestr));
908 		isc_buffer_add(&b, strlen(namestr));
909 		keyname = dns_fixedname_initname(&fkeyname);
910 		result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
911 		if (result != ISC_R_SUCCESS) {
912 			return (result);
913 		}
914 		break;
915 	case DST_R_UNSUPPORTEDALG:
916 	case DST_R_BADKEYTYPE:
917 		/*
918 		 * Key was parsed correctly, but it cannot be used; this is not
919 		 * a fatal error - log a warning about this key being ignored,
920 		 * but do not prevent any further ones from being processed.
921 		 */
922 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
923 			    "ignoring %s for '%s': %s",
924 			    initializing ? "initial-key" : "static-key",
925 			    namestr, isc_result_totext(result));
926 		return (ISC_R_SUCCESS);
927 	case DST_R_NOCRYPTO:
928 		/*
929 		 * Crypto support is not available.
930 		 */
931 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
932 			    "ignoring %s for '%s': no crypto support",
933 			    initializing ? "initial-key" : "static-key",
934 			    namestr);
935 		return (result);
936 	default:
937 		/*
938 		 * Something unexpected happened; we have no choice but to
939 		 * indicate an error so that the configuration loading process
940 		 * is interrupted.
941 		 */
942 		cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
943 			    "configuring %s for '%s': %s",
944 			    initializing ? "initial-key" : "static-key",
945 			    namestr, isc_result_totext(result));
946 		return (ISC_R_FAILURE);
947 	}
948 
949 	/*
950 	 * If the caller requested to only load keys for a specific name and
951 	 * the owner name of this key does not match the requested name, do not
952 	 * load it.
953 	 */
954 	if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) {
955 		goto done;
956 	}
957 
958 	/*
959 	 * Ensure that 'resolver' allows using the algorithm of this key for
960 	 * its owner name.  If it does not, do not load the key and log a
961 	 * warning, but do not prevent further keys from being processed.
962 	 */
963 	if (!dns_resolver_algorithm_supported(resolver, keyname, ds.algorithm))
964 	{
965 		cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
966 			    "ignoring %s for '%s': algorithm is disabled",
967 			    initializing ? "initial-key" : "static-key",
968 			    namestr);
969 		goto done;
970 	}
971 
972 	/*
973 	 * Add the key to 'secroots'.  Keys from a "trust-anchors" or
974 	 * "managed-keys" statement may be either static or initializing
975 	 * keys. If it's not initializing, we don't want to treat it as
976 	 * managed, so we use 'initializing' twice here, for both the
977 	 * 'managed' and 'initializing' arguments to dns_keytable_add().
978 	 */
979 	result = dns_keytable_add(secroots, initializing, initializing, keyname,
980 				  &ds);
981 
982 done:
983 	return (result);
984 }
985 
986 /*
987  * Load keys from configuration into key table. If 'keyname' is specified,
988  * only load keys matching that name. If 'managed' is true, load the key as
989  * an initializing key.
990  */
991 static isc_result_t
load_view_keys(const cfg_obj_t * keys,dns_view_t * view,bool managed,const dns_name_t * keyname)992 load_view_keys(const cfg_obj_t *keys, dns_view_t *view, bool managed,
993 	       const dns_name_t *keyname) {
994 	const cfg_listelt_t *elt, *elt2;
995 	const cfg_obj_t *keylist;
996 	isc_result_t result;
997 	dns_keytable_t *secroots = NULL;
998 
999 	CHECK(dns_view_getsecroots(view, &secroots));
1000 
1001 	for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt))
1002 	{
1003 		keylist = cfg_listelt_value(elt);
1004 
1005 		for (elt2 = cfg_list_first(keylist); elt2 != NULL;
1006 		     elt2 = cfg_list_next(elt2)) {
1007 			CHECK(process_key(cfg_listelt_value(elt2), secroots,
1008 					  keyname, view->resolver, managed));
1009 		}
1010 	}
1011 
1012 cleanup:
1013 	if (secroots != NULL) {
1014 		dns_keytable_detach(&secroots);
1015 	}
1016 	if (result == DST_R_NOCRYPTO) {
1017 		result = ISC_R_SUCCESS;
1018 	}
1019 	return (result);
1020 }
1021 
1022 /*%
1023  * Check whether a key has been successfully loaded.
1024  */
1025 static bool
keyloaded(dns_view_t * view,const dns_name_t * name)1026 keyloaded(dns_view_t *view, const dns_name_t *name) {
1027 	isc_result_t result;
1028 	dns_keytable_t *secroots = NULL;
1029 	dns_keynode_t *keynode = NULL;
1030 
1031 	result = dns_view_getsecroots(view, &secroots);
1032 	if (result != ISC_R_SUCCESS) {
1033 		return (false);
1034 	}
1035 
1036 	result = dns_keytable_find(secroots, name, &keynode);
1037 
1038 	if (keynode != NULL) {
1039 		dns_keytable_detachkeynode(secroots, &keynode);
1040 	}
1041 	if (secroots != NULL) {
1042 		dns_keytable_detach(&secroots);
1043 	}
1044 
1045 	return (result == ISC_R_SUCCESS);
1046 }
1047 
1048 /*%
1049  * Configure DNSSEC keys for a view.
1050  *
1051  * The per-view configuration values and the server-global defaults are read
1052  * from 'vconfig' and 'config'.
1053  */
1054 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)1055 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
1056 			  const cfg_obj_t *config, const cfg_obj_t *bindkeys,
1057 			  bool auto_root, isc_mem_t *mctx) {
1058 	isc_result_t result = ISC_R_SUCCESS;
1059 	const cfg_obj_t *view_keys = NULL;
1060 	const cfg_obj_t *global_keys = NULL;
1061 	const cfg_obj_t *view_managed_keys = NULL;
1062 	const cfg_obj_t *view_trust_anchors = NULL;
1063 	const cfg_obj_t *global_managed_keys = NULL;
1064 	const cfg_obj_t *global_trust_anchors = NULL;
1065 	const cfg_obj_t *maps[4];
1066 	const cfg_obj_t *voptions = NULL;
1067 	const cfg_obj_t *options = NULL;
1068 	const cfg_obj_t *obj = NULL;
1069 	const char *directory;
1070 	int i = 0;
1071 
1072 	/* We don't need trust anchors for the _bind view */
1073 	if (strcmp(view->name, "_bind") == 0 &&
1074 	    view->rdclass == dns_rdataclass_chaos) {
1075 		return (ISC_R_SUCCESS);
1076 	}
1077 
1078 	if (vconfig != NULL) {
1079 		voptions = cfg_tuple_get(vconfig, "options");
1080 		if (voptions != NULL) {
1081 			(void)cfg_map_get(voptions, "trusted-keys", &view_keys);
1082 
1083 			/* managed-keys and trust-anchors are synonyms. */
1084 			(void)cfg_map_get(voptions, "managed-keys",
1085 					  &view_managed_keys);
1086 			(void)cfg_map_get(voptions, "trust-anchors",
1087 					  &view_trust_anchors);
1088 
1089 			maps[i++] = voptions;
1090 		}
1091 	}
1092 
1093 	if (config != NULL) {
1094 		(void)cfg_map_get(config, "trusted-keys", &global_keys);
1095 
1096 		/* managed-keys and trust-anchors are synonyms. */
1097 		(void)cfg_map_get(config, "managed-keys", &global_managed_keys);
1098 		(void)cfg_map_get(config, "trust-anchors",
1099 				  &global_trust_anchors);
1100 
1101 		(void)cfg_map_get(config, "options", &options);
1102 		if (options != NULL) {
1103 			maps[i++] = options;
1104 		}
1105 	}
1106 
1107 	maps[i++] = named_g_defaults;
1108 	maps[i] = NULL;
1109 
1110 	result = dns_view_initsecroots(view, mctx);
1111 	if (result != ISC_R_SUCCESS) {
1112 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1113 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1114 			      "couldn't create keytable");
1115 		return (ISC_R_UNEXPECTED);
1116 	}
1117 
1118 	result = dns_view_initntatable(view, named_g_taskmgr, named_g_timermgr);
1119 	if (result != ISC_R_SUCCESS) {
1120 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1121 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1122 			      "couldn't create NTA table");
1123 		return (ISC_R_UNEXPECTED);
1124 	}
1125 
1126 	if (auto_root && view->rdclass == dns_rdataclass_in) {
1127 		const cfg_obj_t *builtin_keys = NULL;
1128 
1129 		/*
1130 		 * If bind.keys exists and is populated, it overrides
1131 		 * the trust-anchors clause hard-coded in named_g_config.
1132 		 */
1133 		if (bindkeys != NULL) {
1134 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1135 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1136 				      "obtaining root key for view %s "
1137 				      "from '%s'",
1138 				      view->name, named_g_server->bindkeysfile);
1139 
1140 			(void)cfg_map_get(bindkeys, "trust-anchors",
1141 					  &builtin_keys);
1142 
1143 			if (builtin_keys == NULL) {
1144 				isc_log_write(
1145 					named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1146 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
1147 					"dnssec-validation auto: "
1148 					"WARNING: root zone key "
1149 					"not found");
1150 			}
1151 		}
1152 
1153 		if (builtin_keys == NULL) {
1154 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1155 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1156 				      "using built-in root key for view %s",
1157 				      view->name);
1158 
1159 			(void)cfg_map_get(named_g_config, "trust-anchors",
1160 					  &builtin_keys);
1161 		}
1162 
1163 		if (builtin_keys != NULL) {
1164 			CHECK(load_view_keys(builtin_keys, view, true,
1165 					     dns_rootname));
1166 		}
1167 
1168 		if (!keyloaded(view, dns_rootname)) {
1169 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1170 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1171 				      "root key not loaded");
1172 			result = ISC_R_FAILURE;
1173 			goto cleanup;
1174 		}
1175 	}
1176 
1177 	if (view->rdclass == dns_rdataclass_in) {
1178 		CHECK(load_view_keys(view_keys, view, false, NULL));
1179 		CHECK(load_view_keys(view_trust_anchors, view, true, NULL));
1180 		CHECK(load_view_keys(view_managed_keys, view, true, NULL));
1181 
1182 		CHECK(load_view_keys(global_keys, view, false, NULL));
1183 		CHECK(load_view_keys(global_trust_anchors, view, true, NULL));
1184 		CHECK(load_view_keys(global_managed_keys, view, true, NULL));
1185 	}
1186 
1187 	/*
1188 	 * Add key zone for managed keys.
1189 	 */
1190 	obj = NULL;
1191 	(void)named_config_get(maps, "managed-keys-directory", &obj);
1192 	directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
1193 	if (directory != NULL) {
1194 		result = isc_file_isdirectory(directory);
1195 	}
1196 	if (result != ISC_R_SUCCESS) {
1197 		isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1198 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1199 			      "invalid managed-keys-directory %s: %s",
1200 			      directory, isc_result_totext(result));
1201 		goto cleanup;
1202 	} else if (directory != NULL) {
1203 		if (!isc_file_isdirwritable(directory)) {
1204 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1205 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1206 				      "managed-keys-directory '%s' "
1207 				      "is not writable",
1208 				      directory);
1209 			result = ISC_R_NOPERM;
1210 			goto cleanup;
1211 		}
1212 	}
1213 
1214 	CHECK(add_keydata_zone(view, directory, named_g_mctx));
1215 
1216 cleanup:
1217 	return (result);
1218 }
1219 
1220 static isc_result_t
mustbesecure(const cfg_obj_t * mbs,dns_resolver_t * resolver)1221 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
1222 	const cfg_listelt_t *element;
1223 	const cfg_obj_t *obj;
1224 	const char *str;
1225 	dns_fixedname_t fixed;
1226 	dns_name_t *name;
1227 	bool value;
1228 	isc_result_t result;
1229 	isc_buffer_t b;
1230 
1231 	name = dns_fixedname_initname(&fixed);
1232 	for (element = cfg_list_first(mbs); element != NULL;
1233 	     element = cfg_list_next(element))
1234 	{
1235 		obj = cfg_listelt_value(element);
1236 		str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
1237 		isc_buffer_constinit(&b, str, strlen(str));
1238 		isc_buffer_add(&b, strlen(str));
1239 		CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1240 		value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
1241 		CHECK(dns_resolver_setmustbesecure(resolver, name, value));
1242 	}
1243 
1244 	result = ISC_R_SUCCESS;
1245 
1246 cleanup:
1247 	return (result);
1248 }
1249 
1250 /*%
1251  * Get a dispatch appropriate for the resolver of a given view.
1252  */
1253 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)1254 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
1255 			      dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
1256 			      bool is_firstview) {
1257 	isc_result_t result = ISC_R_FAILURE;
1258 	dns_dispatch_t *disp = NULL;
1259 	isc_sockaddr_t sa;
1260 	const cfg_obj_t *obj = NULL;
1261 	isc_dscp_t dscp = -1;
1262 
1263 	switch (af) {
1264 	case AF_INET:
1265 		result = named_config_get(maps, "query-source", &obj);
1266 		INSIST(result == ISC_R_SUCCESS);
1267 		break;
1268 	case AF_INET6:
1269 		result = named_config_get(maps, "query-source-v6", &obj);
1270 		INSIST(result == ISC_R_SUCCESS);
1271 		break;
1272 	default:
1273 		INSIST(0);
1274 		ISC_UNREACHABLE();
1275 	}
1276 
1277 	sa = *(cfg_obj_assockaddr(obj));
1278 	INSIST(isc_sockaddr_pf(&sa) == af);
1279 
1280 	dscp = cfg_obj_getdscp(obj);
1281 	if (dscp != -1 && dscpp != NULL) {
1282 		*dscpp = dscp;
1283 	}
1284 
1285 	/*
1286 	 * If we don't support this address family, we're done!
1287 	 */
1288 	switch (af) {
1289 	case AF_INET:
1290 		result = isc_net_probeipv4();
1291 		break;
1292 	case AF_INET6:
1293 		result = isc_net_probeipv6();
1294 		break;
1295 	default:
1296 		INSIST(0);
1297 		ISC_UNREACHABLE();
1298 	}
1299 	if (result != ISC_R_SUCCESS) {
1300 		return (ISC_R_SUCCESS);
1301 	}
1302 
1303 	/*
1304 	 * Try to find a dispatcher that we can share.
1305 	 */
1306 	if (isc_sockaddr_getport(&sa) != 0) {
1307 		INSIST(obj != NULL);
1308 		if (is_firstview) {
1309 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
1310 				    "using specific query-source port "
1311 				    "suppresses port randomization and can be "
1312 				    "insecure.");
1313 		}
1314 	}
1315 
1316 	result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, &disp);
1317 	if (result != ISC_R_SUCCESS) {
1318 		isc_sockaddr_t any;
1319 		char buf[ISC_SOCKADDR_FORMATSIZE];
1320 
1321 		switch (af) {
1322 		case AF_INET:
1323 			isc_sockaddr_any(&any);
1324 			break;
1325 		case AF_INET6:
1326 			isc_sockaddr_any6(&any);
1327 			break;
1328 		}
1329 		if (isc_sockaddr_equal(&sa, &any)) {
1330 			return (ISC_R_SUCCESS);
1331 		}
1332 		isc_sockaddr_format(&sa, buf, sizeof(buf));
1333 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1334 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1335 			      "could not get query source dispatcher (%s)",
1336 			      buf);
1337 		return (result);
1338 	}
1339 
1340 	*dispatchp = disp;
1341 
1342 	return (ISC_R_SUCCESS);
1343 }
1344 
1345 static isc_result_t
configure_order(dns_order_t * order,const cfg_obj_t * ent)1346 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1347 	dns_rdataclass_t rdclass;
1348 	dns_rdatatype_t rdtype;
1349 	const cfg_obj_t *obj;
1350 	dns_fixedname_t fixed;
1351 	unsigned int mode = 0;
1352 	const char *str;
1353 	isc_buffer_t b;
1354 	isc_result_t result;
1355 	bool addroot;
1356 
1357 	result = named_config_getclass(cfg_tuple_get(ent, "class"),
1358 				       dns_rdataclass_any, &rdclass);
1359 	if (result != ISC_R_SUCCESS) {
1360 		return (result);
1361 	}
1362 
1363 	result = named_config_gettype(cfg_tuple_get(ent, "type"),
1364 				      dns_rdatatype_any, &rdtype);
1365 	if (result != ISC_R_SUCCESS) {
1366 		return (result);
1367 	}
1368 
1369 	obj = cfg_tuple_get(ent, "name");
1370 	if (cfg_obj_isstring(obj)) {
1371 		str = cfg_obj_asstring(obj);
1372 	} else {
1373 		str = "*";
1374 	}
1375 	addroot = (strcmp(str, "*") == 0);
1376 	isc_buffer_constinit(&b, str, strlen(str));
1377 	isc_buffer_add(&b, strlen(str));
1378 	dns_fixedname_init(&fixed);
1379 	result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, dns_rootname,
1380 				   0, NULL);
1381 	if (result != ISC_R_SUCCESS) {
1382 		return (result);
1383 	}
1384 
1385 	obj = cfg_tuple_get(ent, "ordering");
1386 	INSIST(cfg_obj_isstring(obj));
1387 	str = cfg_obj_asstring(obj);
1388 	if (!strcasecmp(str, "fixed")) {
1389 #if DNS_RDATASET_FIXED
1390 		mode = DNS_RDATASETATTR_FIXEDORDER;
1391 #else  /* if DNS_RDATASET_FIXED */
1392 		mode = DNS_RDATASETATTR_CYCLIC;
1393 #endif /* DNS_RDATASET_FIXED */
1394 	} else if (!strcasecmp(str, "random")) {
1395 		mode = DNS_RDATASETATTR_RANDOMIZE;
1396 	} else if (!strcasecmp(str, "cyclic")) {
1397 		mode = DNS_RDATASETATTR_CYCLIC;
1398 	} else if (!strcasecmp(str, "none")) {
1399 		mode = DNS_RDATASETATTR_NONE;
1400 	} else {
1401 		INSIST(0);
1402 		ISC_UNREACHABLE();
1403 	}
1404 
1405 	/*
1406 	 * "*" should match everything including the root (BIND 8 compat).
1407 	 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1408 	 * explicit entry for "." when the name is "*".
1409 	 */
1410 	if (addroot) {
1411 		result = dns_order_add(order, dns_rootname, rdtype, rdclass,
1412 				       mode);
1413 		if (result != ISC_R_SUCCESS) {
1414 			return (result);
1415 		}
1416 	}
1417 
1418 	return (dns_order_add(order, dns_fixedname_name(&fixed), rdtype,
1419 			      rdclass, mode));
1420 }
1421 
1422 static isc_result_t
configure_peer(const cfg_obj_t * cpeer,isc_mem_t * mctx,dns_peer_t ** peerp)1423 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1424 	isc_netaddr_t na;
1425 	dns_peer_t *peer;
1426 	const cfg_obj_t *obj;
1427 	const char *str;
1428 	isc_result_t result;
1429 	unsigned int prefixlen;
1430 
1431 	cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1432 
1433 	peer = NULL;
1434 	result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1435 	if (result != ISC_R_SUCCESS) {
1436 		return (result);
1437 	}
1438 
1439 	obj = NULL;
1440 	(void)cfg_map_get(cpeer, "bogus", &obj);
1441 	if (obj != NULL) {
1442 		CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1443 	}
1444 
1445 	obj = NULL;
1446 	(void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1447 	if (obj != NULL) {
1448 		CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1449 	}
1450 
1451 	obj = NULL;
1452 	(void)cfg_map_get(cpeer, "request-expire", &obj);
1453 	if (obj != NULL) {
1454 		CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
1455 	}
1456 
1457 	obj = NULL;
1458 	(void)cfg_map_get(cpeer, "request-ixfr", &obj);
1459 	if (obj != NULL) {
1460 		CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1461 	}
1462 
1463 	obj = NULL;
1464 	(void)cfg_map_get(cpeer, "request-nsid", &obj);
1465 	if (obj != NULL) {
1466 		CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1467 	}
1468 
1469 	obj = NULL;
1470 	(void)cfg_map_get(cpeer, "send-cookie", &obj);
1471 	if (obj != NULL) {
1472 		CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj)));
1473 	}
1474 
1475 	obj = NULL;
1476 	(void)cfg_map_get(cpeer, "edns", &obj);
1477 	if (obj != NULL) {
1478 		CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1479 	}
1480 
1481 	obj = NULL;
1482 	(void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1483 	if (obj != NULL) {
1484 		uint32_t udpsize = cfg_obj_asuint32(obj);
1485 		if (udpsize < 512U) {
1486 			udpsize = 512U;
1487 		}
1488 		if (udpsize > 4096U) {
1489 			udpsize = 4096U;
1490 		}
1491 		CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize));
1492 	}
1493 
1494 	obj = NULL;
1495 	(void)cfg_map_get(cpeer, "edns-version", &obj);
1496 	if (obj != NULL) {
1497 		uint32_t ednsversion = cfg_obj_asuint32(obj);
1498 		if (ednsversion > 255U) {
1499 			ednsversion = 255U;
1500 		}
1501 		CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion));
1502 	}
1503 
1504 	obj = NULL;
1505 	(void)cfg_map_get(cpeer, "max-udp-size", &obj);
1506 	if (obj != NULL) {
1507 		uint32_t udpsize = cfg_obj_asuint32(obj);
1508 		if (udpsize < 512U) {
1509 			udpsize = 512U;
1510 		}
1511 		if (udpsize > 4096U) {
1512 			udpsize = 4096U;
1513 		}
1514 		CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize));
1515 	}
1516 
1517 	obj = NULL;
1518 	(void)cfg_map_get(cpeer, "padding", &obj);
1519 	if (obj != NULL) {
1520 		uint32_t padding = cfg_obj_asuint32(obj);
1521 		if (padding > 512U) {
1522 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
1523 				    "server padding value cannot "
1524 				    "exceed 512: lowering");
1525 			padding = 512U;
1526 		}
1527 		CHECK(dns_peer_setpadding(peer, (uint16_t)padding));
1528 	}
1529 
1530 	obj = NULL;
1531 	(void)cfg_map_get(cpeer, "tcp-only", &obj);
1532 	if (obj != NULL) {
1533 		CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
1534 	}
1535 
1536 	obj = NULL;
1537 	(void)cfg_map_get(cpeer, "tcp-keepalive", &obj);
1538 	if (obj != NULL) {
1539 		CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj)));
1540 	}
1541 
1542 	obj = NULL;
1543 	(void)cfg_map_get(cpeer, "transfers", &obj);
1544 	if (obj != NULL) {
1545 		CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1546 	}
1547 
1548 	obj = NULL;
1549 	(void)cfg_map_get(cpeer, "transfer-format", &obj);
1550 	if (obj != NULL) {
1551 		str = cfg_obj_asstring(obj);
1552 		if (strcasecmp(str, "many-answers") == 0) {
1553 			CHECK(dns_peer_settransferformat(peer,
1554 							 dns_many_answers));
1555 		} else if (strcasecmp(str, "one-answer") == 0) {
1556 			CHECK(dns_peer_settransferformat(peer, dns_one_answer));
1557 		} else {
1558 			INSIST(0);
1559 			ISC_UNREACHABLE();
1560 		}
1561 	}
1562 
1563 	obj = NULL;
1564 	(void)cfg_map_get(cpeer, "keys", &obj);
1565 	if (obj != NULL) {
1566 		result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1567 		if (result != ISC_R_SUCCESS) {
1568 			goto cleanup;
1569 		}
1570 	}
1571 
1572 	obj = NULL;
1573 	if (na.family == AF_INET) {
1574 		(void)cfg_map_get(cpeer, "transfer-source", &obj);
1575 	} else {
1576 		(void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1577 	}
1578 	if (obj != NULL) {
1579 		result = dns_peer_settransfersource(peer,
1580 						    cfg_obj_assockaddr(obj));
1581 		if (result != ISC_R_SUCCESS) {
1582 			goto cleanup;
1583 		}
1584 		result = dns_peer_settransferdscp(peer, cfg_obj_getdscp(obj));
1585 		if (result != ISC_R_SUCCESS) {
1586 			goto cleanup;
1587 		}
1588 		named_add_reserved_dispatch(named_g_server,
1589 					    cfg_obj_assockaddr(obj));
1590 	}
1591 
1592 	obj = NULL;
1593 	if (na.family == AF_INET) {
1594 		(void)cfg_map_get(cpeer, "notify-source", &obj);
1595 	} else {
1596 		(void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1597 	}
1598 	if (obj != NULL) {
1599 		result = dns_peer_setnotifysource(peer,
1600 						  cfg_obj_assockaddr(obj));
1601 		if (result != ISC_R_SUCCESS) {
1602 			goto cleanup;
1603 		}
1604 		result = dns_peer_setnotifydscp(peer, cfg_obj_getdscp(obj));
1605 		if (result != ISC_R_SUCCESS) {
1606 			goto cleanup;
1607 		}
1608 		named_add_reserved_dispatch(named_g_server,
1609 					    cfg_obj_assockaddr(obj));
1610 	}
1611 
1612 	obj = NULL;
1613 	if (na.family == AF_INET) {
1614 		(void)cfg_map_get(cpeer, "query-source", &obj);
1615 	} else {
1616 		(void)cfg_map_get(cpeer, "query-source-v6", &obj);
1617 	}
1618 	if (obj != NULL) {
1619 		result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj));
1620 		if (result != ISC_R_SUCCESS) {
1621 			goto cleanup;
1622 		}
1623 		result = dns_peer_setquerydscp(peer, cfg_obj_getdscp(obj));
1624 		if (result != ISC_R_SUCCESS) {
1625 			goto cleanup;
1626 		}
1627 		named_add_reserved_dispatch(named_g_server,
1628 					    cfg_obj_assockaddr(obj));
1629 	}
1630 
1631 	*peerp = peer;
1632 	return (ISC_R_SUCCESS);
1633 
1634 cleanup:
1635 	dns_peer_detach(&peer);
1636 	return (result);
1637 }
1638 
1639 static isc_result_t
configure_dyndb(const cfg_obj_t * dyndb,isc_mem_t * mctx,const dns_dyndbctx_t * dctx)1640 configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
1641 		const dns_dyndbctx_t *dctx) {
1642 	isc_result_t result = ISC_R_SUCCESS;
1643 	const cfg_obj_t *obj;
1644 	const char *name, *library;
1645 
1646 	/* Get the name of the dyndb instance and the library path . */
1647 	name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name"));
1648 	library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library"));
1649 
1650 	obj = cfg_tuple_get(dyndb, "parameters");
1651 	if (obj != NULL) {
1652 		result = dns_dyndb_load(library, name, cfg_obj_asstring(obj),
1653 					cfg_obj_file(obj), cfg_obj_line(obj),
1654 					mctx, dctx);
1655 	}
1656 
1657 	if (result != ISC_R_SUCCESS) {
1658 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1659 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1660 			      "dynamic database '%s' configuration failed: %s",
1661 			      name, isc_result_totext(result));
1662 	}
1663 	return (result);
1664 }
1665 
1666 static isc_result_t
disable_algorithms(const cfg_obj_t * disabled,dns_resolver_t * resolver)1667 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1668 	isc_result_t result;
1669 	const cfg_obj_t *algorithms;
1670 	const cfg_listelt_t *element;
1671 	const char *str;
1672 	dns_fixedname_t fixed;
1673 	dns_name_t *name;
1674 	isc_buffer_t b;
1675 
1676 	name = dns_fixedname_initname(&fixed);
1677 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1678 	isc_buffer_constinit(&b, str, strlen(str));
1679 	isc_buffer_add(&b, strlen(str));
1680 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1681 
1682 	algorithms = cfg_tuple_get(disabled, "algorithms");
1683 	for (element = cfg_list_first(algorithms); element != NULL;
1684 	     element = cfg_list_next(element))
1685 	{
1686 		isc_textregion_t r;
1687 		dns_secalg_t alg;
1688 
1689 		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1690 		r.length = strlen(r.base);
1691 
1692 		result = dns_secalg_fromtext(&alg, &r);
1693 		if (result != ISC_R_SUCCESS) {
1694 			uint8_t ui;
1695 			result = isc_parse_uint8(&ui, r.base, 10);
1696 			alg = ui;
1697 		}
1698 		if (result != ISC_R_SUCCESS) {
1699 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1700 				    ISC_LOG_ERROR, "invalid algorithm");
1701 			CHECK(result);
1702 		}
1703 		CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1704 	}
1705 cleanup:
1706 	return (result);
1707 }
1708 
1709 static isc_result_t
disable_ds_digests(const cfg_obj_t * disabled,dns_resolver_t * resolver)1710 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1711 	isc_result_t result;
1712 	const cfg_obj_t *digests;
1713 	const cfg_listelt_t *element;
1714 	const char *str;
1715 	dns_fixedname_t fixed;
1716 	dns_name_t *name;
1717 	isc_buffer_t b;
1718 
1719 	name = dns_fixedname_initname(&fixed);
1720 	str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1721 	isc_buffer_constinit(&b, str, strlen(str));
1722 	isc_buffer_add(&b, strlen(str));
1723 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1724 
1725 	digests = cfg_tuple_get(disabled, "digests");
1726 	for (element = cfg_list_first(digests); element != NULL;
1727 	     element = cfg_list_next(element))
1728 	{
1729 		isc_textregion_t r;
1730 		dns_dsdigest_t digest;
1731 
1732 		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1733 		r.length = strlen(r.base);
1734 
1735 		/* disable_ds_digests handles numeric values. */
1736 		result = dns_dsdigest_fromtext(&digest, &r);
1737 		if (result != ISC_R_SUCCESS) {
1738 			cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1739 				    ISC_LOG_ERROR, "invalid algorithm");
1740 			CHECK(result);
1741 		}
1742 		CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
1743 	}
1744 cleanup:
1745 	return (result);
1746 }
1747 
1748 static bool
on_disable_list(const cfg_obj_t * disablelist,dns_name_t * zonename)1749 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1750 	const cfg_listelt_t *element;
1751 	dns_fixedname_t fixed;
1752 	dns_name_t *name;
1753 	isc_result_t result;
1754 	const cfg_obj_t *value;
1755 	const char *str;
1756 	isc_buffer_t b;
1757 
1758 	name = dns_fixedname_initname(&fixed);
1759 
1760 	for (element = cfg_list_first(disablelist); element != NULL;
1761 	     element = cfg_list_next(element))
1762 	{
1763 		value = cfg_listelt_value(element);
1764 		str = cfg_obj_asstring(value);
1765 		isc_buffer_constinit(&b, str, strlen(str));
1766 		isc_buffer_add(&b, strlen(str));
1767 		result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
1768 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1769 		if (dns_name_equal(name, zonename)) {
1770 			return (true);
1771 		}
1772 	}
1773 	return (false);
1774 }
1775 
1776 static isc_result_t
check_dbtype(dns_zone_t * zone,unsigned int dbtypec,const char ** dbargv,isc_mem_t * mctx)1777 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
1778 	     isc_mem_t *mctx) {
1779 	char **argv = NULL;
1780 	unsigned int i;
1781 	isc_result_t result = ISC_R_SUCCESS;
1782 
1783 	CHECK(dns_zone_getdbtype(zone, &argv, mctx));
1784 
1785 	/*
1786 	 * Check that all the arguments match.
1787 	 */
1788 	for (i = 0; i < dbtypec; i++) {
1789 		if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
1790 			CHECK(ISC_R_FAILURE);
1791 
1792 			/*
1793 			 * Check that there are not extra arguments.
1794 			 */
1795 		}
1796 	}
1797 
1798 	/*
1799 	 * Check that there are not extra arguments.
1800 	 */
1801 	if (i == dbtypec && argv[i] != NULL) {
1802 		result = ISC_R_FAILURE;
1803 	}
1804 
1805 cleanup:
1806 	isc_mem_free(mctx, argv);
1807 	return (result);
1808 }
1809 
1810 static isc_result_t
setquerystats(dns_zone_t * zone,isc_mem_t * mctx,dns_zonestat_level_t level)1811 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
1812 	isc_result_t result;
1813 	isc_stats_t *zoneqrystats;
1814 
1815 	dns_zone_setstatlevel(zone, level);
1816 
1817 	zoneqrystats = NULL;
1818 	if (level == dns_zonestat_full) {
1819 		result = isc_stats_create(mctx, &zoneqrystats,
1820 					  ns_statscounter_max);
1821 		if (result != ISC_R_SUCCESS) {
1822 			return (result);
1823 		}
1824 	}
1825 	dns_zone_setrequeststats(zone, zoneqrystats);
1826 	if (zoneqrystats != NULL) {
1827 		isc_stats_detach(&zoneqrystats);
1828 	}
1829 
1830 	return (ISC_R_SUCCESS);
1831 }
1832 
1833 static named_cache_t *
cachelist_find(named_cachelist_t * cachelist,const char * cachename,dns_rdataclass_t rdclass)1834 cachelist_find(named_cachelist_t *cachelist, const char *cachename,
1835 	       dns_rdataclass_t rdclass) {
1836 	named_cache_t *nsc;
1837 
1838 	for (nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
1839 	     nsc = ISC_LIST_NEXT(nsc, link))
1840 	{
1841 		if (nsc->rdclass == rdclass &&
1842 		    strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1843 		{
1844 			return (nsc);
1845 		}
1846 	}
1847 
1848 	return (NULL);
1849 }
1850 
1851 static bool
cache_reusable(dns_view_t * originview,dns_view_t * view,bool new_zero_no_soattl)1852 cache_reusable(dns_view_t *originview, dns_view_t *view,
1853 	       bool new_zero_no_soattl) {
1854 	if (originview->rdclass != view->rdclass ||
1855 	    originview->checknames != view->checknames ||
1856 	    dns_resolver_getzeronosoattl(originview->resolver) !=
1857 		    new_zero_no_soattl ||
1858 	    originview->acceptexpired != view->acceptexpired ||
1859 	    originview->enablevalidation != view->enablevalidation ||
1860 	    originview->maxcachettl != view->maxcachettl ||
1861 	    originview->maxncachettl != view->maxncachettl)
1862 	{
1863 		return (false);
1864 	}
1865 
1866 	return (true);
1867 }
1868 
1869 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)1870 cache_sharable(dns_view_t *originview, dns_view_t *view,
1871 	       bool new_zero_no_soattl, uint64_t new_max_cache_size,
1872 	       uint32_t new_stale_ttl, uint32_t new_stale_refresh_time) {
1873 	/*
1874 	 * If the cache cannot even reused for the same view, it cannot be
1875 	 * shared with other views.
1876 	 */
1877 	if (!cache_reusable(originview, view, new_zero_no_soattl)) {
1878 		return (false);
1879 	}
1880 
1881 	/*
1882 	 * Check other cache related parameters that must be consistent among
1883 	 * the sharing views.
1884 	 */
1885 	if (dns_cache_getservestalettl(originview->cache) != new_stale_ttl ||
1886 	    dns_cache_getservestalerefresh(originview->cache) !=
1887 		    new_stale_refresh_time ||
1888 	    dns_cache_getcachesize(originview->cache) != new_max_cache_size)
1889 	{
1890 		return (false);
1891 	}
1892 
1893 	return (true);
1894 }
1895 
1896 /*
1897  * Callback from DLZ configure when the driver sets up a writeable zone
1898  */
1899 static isc_result_t
dlzconfigure_callback(dns_view_t * view,dns_dlzdb_t * dlzdb,dns_zone_t * zone)1900 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
1901 	dns_name_t *origin = dns_zone_getorigin(zone);
1902 	dns_rdataclass_t zclass = view->rdclass;
1903 	isc_result_t result;
1904 
1905 	result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
1906 	if (result != ISC_R_SUCCESS) {
1907 		return (result);
1908 	}
1909 	dns_zone_setstats(zone, named_g_server->zonestats);
1910 
1911 	return (named_zone_configure_writeable_dlz(dlzdb, zone, zclass,
1912 						   origin));
1913 }
1914 
1915 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)1916 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1917 	      unsigned int prefixlen, const char *server, const char *contact) {
1918 	char reverse[48 + sizeof("ip6.arpa.")] = { 0 };
1919 	char buf[sizeof("x.x.")];
1920 	const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1921 	const char *sep = ": view ";
1922 	const char *viewname = view->name;
1923 	const unsigned char *s6;
1924 	dns_fixedname_t fixed;
1925 	dns_name_t *name;
1926 	dns_zone_t *zone = NULL;
1927 	int dns64_dbtypec = 4;
1928 	isc_buffer_t b;
1929 	isc_result_t result;
1930 
1931 	REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1932 		prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1933 
1934 	if (!strcmp(viewname, "_default")) {
1935 		sep = "";
1936 		viewname = "";
1937 	}
1938 
1939 	/*
1940 	 * Construct the reverse name of the zone.
1941 	 */
1942 	s6 = na->type.in6.s6_addr;
1943 	while (prefixlen > 0) {
1944 		prefixlen -= 8;
1945 		snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen / 8] & 0xf,
1946 			 (s6[prefixlen / 8] >> 4) & 0xf);
1947 		strlcat(reverse, buf, sizeof(reverse));
1948 	}
1949 	strlcat(reverse, "ip6.arpa.", sizeof(reverse));
1950 
1951 	/*
1952 	 * Create the actual zone.
1953 	 */
1954 	if (server != NULL) {
1955 		dns64_dbtype[2] = server;
1956 	}
1957 	if (contact != NULL) {
1958 		dns64_dbtype[3] = contact;
1959 	}
1960 	name = dns_fixedname_initname(&fixed);
1961 	isc_buffer_constinit(&b, reverse, strlen(reverse));
1962 	isc_buffer_add(&b, strlen(reverse));
1963 	CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1964 	CHECK(dns_zone_create(&zone, mctx));
1965 	CHECK(dns_zone_setorigin(zone, name));
1966 	dns_zone_setview(zone, view);
1967 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
1968 	dns_zone_setclass(zone, view->rdclass);
1969 	dns_zone_settype(zone, dns_zone_primary);
1970 	dns_zone_setstats(zone, named_g_server->zonestats);
1971 	dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype);
1972 	if (view->queryacl != NULL) {
1973 		dns_zone_setqueryacl(zone, view->queryacl);
1974 	}
1975 	if (view->queryonacl != NULL) {
1976 		dns_zone_setqueryonacl(zone, view->queryonacl);
1977 	}
1978 	dns_zone_setdialup(zone, dns_dialuptype_no);
1979 	dns_zone_setnotifytype(zone, dns_notifytype_no);
1980 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
1981 	CHECK(setquerystats(zone, mctx, dns_zonestat_none)); /* XXXMPA */
1982 	CHECK(dns_view_addzone(view, zone));
1983 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1984 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1985 		      "dns64 reverse zone%s%s: %s", sep, viewname, reverse);
1986 
1987 cleanup:
1988 	if (zone != NULL) {
1989 		dns_zone_detach(&zone);
1990 	}
1991 	return (result);
1992 }
1993 
1994 #ifdef USE_DNSRPS
1995 typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
1996 struct conf_dnsrps_ctx {
1997 	isc_result_t result;
1998 	char *cstr;
1999 	size_t cstr_size;
2000 	isc_mem_t *mctx;
2001 };
2002 
2003 /*
2004  * Add to the DNSRPS configuration string.
2005  */
2006 static bool
conf_dnsrps_sadd(conf_dnsrps_ctx_t * ctx,const char * p,...)2007 conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
2008 	size_t new_len, cur_len, new_cstr_size;
2009 	char *new_cstr;
2010 	va_list args;
2011 
2012 	if (ctx->cstr == NULL) {
2013 		ctx->cstr = isc_mem_get(ctx->mctx, 256);
2014 		ctx->cstr[0] = '\0';
2015 		ctx->cstr_size = 256;
2016 	}
2017 
2018 	cur_len = strlen(ctx->cstr);
2019 	va_start(args, p);
2020 	new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p,
2021 			    args) +
2022 		  1;
2023 	va_end(args);
2024 
2025 	if (cur_len + new_len <= ctx->cstr_size) {
2026 		return (true);
2027 	}
2028 
2029 	new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256;
2030 	new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
2031 
2032 	memmove(new_cstr, ctx->cstr, cur_len);
2033 	isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
2034 	ctx->cstr_size = new_cstr_size;
2035 	ctx->cstr = new_cstr;
2036 
2037 	/* cannot use args twice after a single va_start()on some systems */
2038 	va_start(args, p);
2039 	vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
2040 	va_end(args);
2041 	return (true);
2042 }
2043 
2044 /*
2045  * Get an DNSRPS configuration value using the global and view options
2046  * for the default.  Return false upon failure.
2047  */
2048 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)2049 conf_dnsrps_get(const cfg_obj_t **sub_obj, const cfg_obj_t **maps,
2050 		const cfg_obj_t *obj, const char *name,
2051 		conf_dnsrps_ctx_t *ctx) {
2052 	if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
2053 		*sub_obj = NULL;
2054 		return (false);
2055 	}
2056 
2057 	*sub_obj = cfg_tuple_get(obj, name);
2058 	if (cfg_obj_isvoid(*sub_obj)) {
2059 		*sub_obj = NULL;
2060 		if (maps != NULL &&
2061 		    ISC_R_SUCCESS != named_config_get(maps, name, sub_obj)) {
2062 			*sub_obj = NULL;
2063 		}
2064 	}
2065 	return (true);
2066 }
2067 
2068 /*
2069  * Handle a DNSRPS boolean configuration value with the global and view
2070  * options providing the default.
2071  */
2072 static void
conf_dnsrps_yes_no(const cfg_obj_t * obj,const char * name,conf_dnsrps_ctx_t * ctx)2073 conf_dnsrps_yes_no(const cfg_obj_t *obj, const char *name,
2074 		   conf_dnsrps_ctx_t *ctx) {
2075 	const cfg_obj_t *sub_obj;
2076 
2077 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2078 		return;
2079 	}
2080 	if (sub_obj == NULL) {
2081 		return;
2082 	}
2083 	if (ctx == NULL) {
2084 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2085 			    "\"%s\" without \"dnsrps-enable yes\"", name);
2086 		return;
2087 	}
2088 
2089 	conf_dnsrps_sadd(ctx, " %s %s", name,
2090 			 cfg_obj_asboolean(sub_obj) ? "yes" : "no");
2091 }
2092 
2093 static void
conf_dnsrps_num(const cfg_obj_t * obj,const char * name,conf_dnsrps_ctx_t * ctx)2094 conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
2095 		conf_dnsrps_ctx_t *ctx) {
2096 	const cfg_obj_t *sub_obj;
2097 
2098 	if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2099 		return;
2100 	}
2101 	if (sub_obj == NULL) {
2102 		return;
2103 	}
2104 	if (ctx == NULL) {
2105 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2106 			    "\"%s\" without \"dnsrps-enable yes\"", name);
2107 		return;
2108 	}
2109 
2110 	if (cfg_obj_isduration(sub_obj)) {
2111 		conf_dnsrps_sadd(ctx, " %s %d", name,
2112 				 cfg_obj_asduration(sub_obj));
2113 	} else {
2114 		conf_dnsrps_sadd(ctx, " %s %d", name,
2115 				 cfg_obj_asuint32(sub_obj));
2116 	}
2117 }
2118 
2119 /*
2120  * Convert the parsed RPZ configuration statement to a string for
2121  * dns_rpz_new_zones().
2122  */
2123 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)2124 conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps, bool nsip_enabled,
2125 	    bool nsdname_enabled, dns_rpz_zbits_t *nsip_on,
2126 	    dns_rpz_zbits_t *nsdname_on, char **rps_cstr, size_t *rps_cstr_size,
2127 	    const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element) {
2128 	conf_dnsrps_ctx_t ctx;
2129 	const cfg_obj_t *zone_obj, *obj;
2130 	dns_rpz_num_t rpz_num;
2131 	bool on;
2132 	const char *s;
2133 
2134 	memset(&ctx, 0, sizeof(ctx));
2135 	ctx.result = ISC_R_SUCCESS;
2136 	ctx.mctx = view->mctx;
2137 
2138 	for (rpz_num = 0; zone_element != NULL && ctx.result == ISC_R_SUCCESS;
2139 	     ++rpz_num)
2140 	{
2141 		zone_obj = cfg_listelt_value(zone_element);
2142 
2143 		s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
2144 		conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
2145 
2146 		obj = cfg_tuple_get(zone_obj, "policy");
2147 		if (!cfg_obj_isvoid(obj)) {
2148 			s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2149 			conf_dnsrps_sadd(&ctx, " policy %s", s);
2150 			if (strcasecmp(s, "cname") == 0) {
2151 				s = cfg_obj_asstring(
2152 					cfg_tuple_get(obj, "cname"));
2153 				conf_dnsrps_sadd(&ctx, " %s", s);
2154 			}
2155 		}
2156 
2157 		conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
2158 		conf_dnsrps_yes_no(zone_obj, "log", &ctx);
2159 		conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
2160 		obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2161 		if (!cfg_obj_isvoid(obj)) {
2162 			if (cfg_obj_asboolean(obj)) {
2163 				*nsip_on |= DNS_RPZ_ZBIT(rpz_num);
2164 			} else {
2165 				*nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
2166 			}
2167 		}
2168 		on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2169 		if (nsip_enabled != on) {
2170 			conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes "
2171 						  : " nsip-enable no ");
2172 		}
2173 		obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2174 		if (!cfg_obj_isvoid(obj)) {
2175 			if (cfg_obj_asboolean(obj)) {
2176 				*nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
2177 			} else {
2178 				*nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
2179 			}
2180 		}
2181 		on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2182 		if (nsdname_enabled != on) {
2183 			conf_dnsrps_sadd(&ctx, on ? " nsdname-enable yes "
2184 						  : " nsdname-enable no ");
2185 		}
2186 		conf_dnsrps_sadd(&ctx, ";\n");
2187 		zone_element = cfg_list_next(zone_element);
2188 	}
2189 
2190 	conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
2191 	conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
2192 	conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
2193 	conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
2194 	conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
2195 	if (!nsip_enabled) {
2196 		conf_dnsrps_sadd(&ctx, " nsip-enable no ");
2197 	}
2198 	if (!nsdname_enabled) {
2199 		conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
2200 	}
2201 
2202 	/*
2203 	 * Get the general dnsrpzd parameters from the response-policy
2204 	 * statement in the view and the general options.
2205 	 */
2206 	if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
2207 	    obj != NULL) {
2208 		conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
2209 	}
2210 
2211 	if (ctx.result == ISC_R_SUCCESS) {
2212 		*rps_cstr = ctx.cstr;
2213 		*rps_cstr_size = ctx.cstr_size;
2214 	} else {
2215 		if (ctx.cstr != NULL) {
2216 			isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
2217 		}
2218 		*rps_cstr = NULL;
2219 		*rps_cstr_size = 0;
2220 	}
2221 	return (ctx.result);
2222 }
2223 #endif /* ifdef USE_DNSRPS */
2224 
2225 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)2226 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2227 		   const char *str, const char *msg) {
2228 	isc_result_t result;
2229 
2230 	result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx);
2231 	if (result != ISC_R_SUCCESS) {
2232 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2233 			    "invalid %s '%s'", msg, str);
2234 	}
2235 	return (result);
2236 }
2237 
2238 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)2239 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2240 		    const char *str, const dns_name_t *origin) {
2241 	isc_result_t result;
2242 
2243 	result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE,
2244 				      view->mctx);
2245 	if (result != ISC_R_SUCCESS) {
2246 		cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2247 			    "invalid zone '%s'", str);
2248 	}
2249 	return (result);
2250 }
2251 
2252 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)2253 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
2254 		   bool recursive_only_default, bool add_soa_default,
2255 		   dns_ttl_t ttl_default, uint32_t minupdateinterval_default,
2256 		   const dns_rpz_zone_t *old, bool *old_rpz_okp) {
2257 	const cfg_obj_t *rpz_obj, *obj;
2258 	const char *str;
2259 	dns_rpz_zone_t *zone = NULL;
2260 	isc_result_t result;
2261 	dns_rpz_num_t rpz_num;
2262 
2263 	REQUIRE(old != NULL || !*old_rpz_okp);
2264 
2265 	rpz_obj = cfg_listelt_value(element);
2266 
2267 	if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
2268 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2269 			    "limit of %d response policy zones exceeded",
2270 			    DNS_RPZ_MAX_ZONES);
2271 		return (ISC_R_FAILURE);
2272 	}
2273 
2274 	result = dns_rpz_new_zone(view->rpzs, &zone);
2275 	if (result != ISC_R_SUCCESS) {
2276 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2277 			    "Error creating new RPZ zone : %s",
2278 			    isc_result_totext(result));
2279 		return (result);
2280 	}
2281 
2282 	obj = cfg_tuple_get(rpz_obj, "recursive-only");
2283 	if (cfg_obj_isvoid(obj) ? recursive_only_default
2284 				: cfg_obj_asboolean(obj)) {
2285 		view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num);
2286 	} else {
2287 		view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num);
2288 	}
2289 
2290 	obj = cfg_tuple_get(rpz_obj, "log");
2291 	if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) {
2292 		view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num);
2293 	} else {
2294 		view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num);
2295 	}
2296 
2297 	obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2298 	if (cfg_obj_isduration(obj)) {
2299 		zone->max_policy_ttl = cfg_obj_asduration(obj);
2300 	} else {
2301 		zone->max_policy_ttl = ttl_default;
2302 	}
2303 
2304 	obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2305 	if (cfg_obj_isduration(obj)) {
2306 		zone->min_update_interval = cfg_obj_asduration(obj);
2307 	} else {
2308 		zone->min_update_interval = minupdateinterval_default;
2309 	}
2310 
2311 	if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl) {
2312 		*old_rpz_okp = false;
2313 	}
2314 
2315 	str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
2316 	result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone");
2317 	if (result != ISC_R_SUCCESS) {
2318 		return (result);
2319 	}
2320 	if (dns_name_equal(&zone->origin, dns_rootname)) {
2321 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2322 			    "invalid zone name '%s'", str);
2323 		return (DNS_R_EMPTYLABEL);
2324 	}
2325 	if (!view->rpzs->p.dnsrps_enabled) {
2326 		for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1;
2327 		     ++rpz_num) {
2328 			if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
2329 					   &zone->origin)) {
2330 				cfg_obj_log(rpz_obj, named_g_lctx,
2331 					    DNS_RPZ_ERROR_LEVEL,
2332 					    "duplicate '%s'", str);
2333 				result = DNS_R_DUPLICATE;
2334 				return (result);
2335 			}
2336 		}
2337 	}
2338 	if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) {
2339 		*old_rpz_okp = false;
2340 	}
2341 
2342 	result = configure_rpz_name2(view, rpz_obj, &zone->client_ip,
2343 				     DNS_RPZ_CLIENT_IP_ZONE, &zone->origin);
2344 	if (result != ISC_R_SUCCESS) {
2345 		return (result);
2346 	}
2347 
2348 	result = configure_rpz_name2(view, rpz_obj, &zone->ip, DNS_RPZ_IP_ZONE,
2349 				     &zone->origin);
2350 	if (result != ISC_R_SUCCESS) {
2351 		return (result);
2352 	}
2353 
2354 	result = configure_rpz_name2(view, rpz_obj, &zone->nsdname,
2355 				     DNS_RPZ_NSDNAME_ZONE, &zone->origin);
2356 	if (result != ISC_R_SUCCESS) {
2357 		return (result);
2358 	}
2359 
2360 	result = configure_rpz_name2(view, rpz_obj, &zone->nsip,
2361 				     DNS_RPZ_NSIP_ZONE, &zone->origin);
2362 	if (result != ISC_R_SUCCESS) {
2363 		return (result);
2364 	}
2365 
2366 	result = configure_rpz_name(view, rpz_obj, &zone->passthru,
2367 				    DNS_RPZ_PASSTHRU_NAME, "name");
2368 	if (result != ISC_R_SUCCESS) {
2369 		return (result);
2370 	}
2371 
2372 	result = configure_rpz_name(view, rpz_obj, &zone->drop,
2373 				    DNS_RPZ_DROP_NAME, "name");
2374 	if (result != ISC_R_SUCCESS) {
2375 		return (result);
2376 	}
2377 
2378 	result = configure_rpz_name(view, rpz_obj, &zone->tcp_only,
2379 				    DNS_RPZ_TCP_ONLY_NAME, "name");
2380 	if (result != ISC_R_SUCCESS) {
2381 		return (result);
2382 	}
2383 
2384 	obj = cfg_tuple_get(rpz_obj, "policy");
2385 	if (cfg_obj_isvoid(obj)) {
2386 		zone->policy = DNS_RPZ_POLICY_GIVEN;
2387 	} else {
2388 		str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2389 		zone->policy = dns_rpz_str2policy(str);
2390 		INSIST(zone->policy != DNS_RPZ_POLICY_ERROR);
2391 		if (zone->policy == DNS_RPZ_POLICY_CNAME) {
2392 			str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
2393 			result = configure_rpz_name(view, rpz_obj, &zone->cname,
2394 						    str, "cname");
2395 			if (result != ISC_R_SUCCESS) {
2396 				return (result);
2397 			}
2398 		}
2399 	}
2400 	if (*old_rpz_okp && (zone->policy != old->policy ||
2401 			     !dns_name_equal(&old->cname, &zone->cname)))
2402 	{
2403 		*old_rpz_okp = false;
2404 	}
2405 
2406 	obj = cfg_tuple_get(rpz_obj, "add-soa");
2407 	if (cfg_obj_isvoid(obj)) {
2408 		zone->addsoa = add_soa_default;
2409 	} else {
2410 		zone->addsoa = cfg_obj_asboolean(obj);
2411 	}
2412 
2413 	return (ISC_R_SUCCESS);
2414 }
2415 
2416 static isc_result_t
configure_rpz(dns_view_t * view,const cfg_obj_t ** maps,const cfg_obj_t * rpz_obj,bool * old_rpz_okp)2417 configure_rpz(dns_view_t *view, const cfg_obj_t **maps,
2418 	      const cfg_obj_t *rpz_obj, bool *old_rpz_okp) {
2419 	bool dnsrps_enabled;
2420 	const cfg_listelt_t *zone_element;
2421 	char *rps_cstr;
2422 	size_t rps_cstr_size;
2423 	const cfg_obj_t *sub_obj;
2424 	bool recursive_only_default, add_soa_default;
2425 	bool nsip_enabled, nsdname_enabled;
2426 	dns_rpz_zbits_t nsip_on, nsdname_on;
2427 	dns_ttl_t ttl_default;
2428 	uint32_t minupdateinterval_default;
2429 	dns_rpz_zones_t *zones;
2430 	const dns_rpz_zones_t *old;
2431 	dns_view_t *pview;
2432 	const dns_rpz_zone_t *old_zone;
2433 	isc_result_t result;
2434 	int i;
2435 
2436 	*old_rpz_okp = false;
2437 
2438 	zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
2439 	if (zone_element == NULL) {
2440 		return (ISC_R_SUCCESS);
2441 	}
2442 
2443 	nsip_enabled = true;
2444 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2445 	if (!cfg_obj_isvoid(sub_obj)) {
2446 		nsip_enabled = cfg_obj_asboolean(sub_obj);
2447 	}
2448 	nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2449 
2450 	nsdname_enabled = true;
2451 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2452 	if (!cfg_obj_isvoid(sub_obj)) {
2453 		nsdname_enabled = cfg_obj_asboolean(sub_obj);
2454 	}
2455 	nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2456 
2457 	/*
2458 	 * "dnsrps-enable yes|no" can be either a global or response-policy
2459 	 * clause.
2460 	 */
2461 	dnsrps_enabled = false;
2462 	rps_cstr = NULL;
2463 	rps_cstr_size = 0;
2464 	sub_obj = NULL;
2465 	(void)named_config_get(maps, "dnsrps-enable", &sub_obj);
2466 	if (sub_obj != NULL) {
2467 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2468 	}
2469 	sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
2470 	if (!cfg_obj_isvoid(sub_obj)) {
2471 		dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2472 	}
2473 #ifndef USE_DNSRPS
2474 	if (dnsrps_enabled) {
2475 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2476 			    "\"dnsrps-enable yes\" but"
2477 			    " without `./configure --enable-dnsrps`");
2478 		return (ISC_R_FAILURE);
2479 	}
2480 #else  /* ifndef USE_DNSRPS */
2481 	if (dnsrps_enabled) {
2482 		if (librpz == NULL) {
2483 			cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2484 				    "\"dnsrps-enable yes\" but %s",
2485 				    librpz_lib_open_emsg.c);
2486 			return (ISC_R_FAILURE);
2487 		}
2488 
2489 		/*
2490 		 * Generate the DNS Response Policy Service
2491 		 * configuration string.
2492 		 */
2493 		result = conf_dnsrps(view, maps, nsip_enabled, nsdname_enabled,
2494 				     &nsip_on, &nsdname_on, &rps_cstr,
2495 				     &rps_cstr_size, rpz_obj, zone_element);
2496 		if (result != ISC_R_SUCCESS) {
2497 			return (result);
2498 		}
2499 	}
2500 #endif /* ifndef USE_DNSRPS */
2501 
2502 	result = dns_rpz_new_zones(&view->rpzs, rps_cstr, rps_cstr_size,
2503 				   view->mctx, named_g_taskmgr,
2504 				   named_g_timermgr);
2505 	if (result != ISC_R_SUCCESS) {
2506 		return (result);
2507 	}
2508 
2509 	zones = view->rpzs;
2510 
2511 	zones->p.nsip_on = nsip_on;
2512 	zones->p.nsdname_on = nsdname_on;
2513 
2514 	sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
2515 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2516 		recursive_only_default = false;
2517 	} else {
2518 		recursive_only_default = true;
2519 	}
2520 
2521 	sub_obj = cfg_tuple_get(rpz_obj, "add-soa");
2522 	if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2523 		add_soa_default = false;
2524 	} else {
2525 		add_soa_default = true;
2526 	}
2527 
2528 	sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
2529 	if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
2530 		zones->p.break_dnssec = true;
2531 	} else {
2532 		zones->p.break_dnssec = false;
2533 	}
2534 
2535 	sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2536 	if (cfg_obj_isduration(sub_obj)) {
2537 		ttl_default = cfg_obj_asduration(sub_obj);
2538 	} else {
2539 		ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
2540 	}
2541 
2542 	sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2543 	if (cfg_obj_isduration(sub_obj)) {
2544 		minupdateinterval_default = cfg_obj_asduration(sub_obj);
2545 	} else {
2546 		minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
2547 	}
2548 
2549 	sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
2550 	if (cfg_obj_isuint32(sub_obj)) {
2551 		zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
2552 	} else {
2553 		zones->p.min_ns_labels = 2;
2554 	}
2555 
2556 	sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
2557 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2558 		zones->p.qname_wait_recurse = true;
2559 	} else {
2560 		zones->p.qname_wait_recurse = false;
2561 	}
2562 
2563 	sub_obj = cfg_tuple_get(rpz_obj, "nsdname-wait-recurse");
2564 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2565 		zones->p.nsdname_wait_recurse = true;
2566 	} else {
2567 		zones->p.nsdname_wait_recurse = false;
2568 	}
2569 
2570 	sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse");
2571 	if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2572 		zones->p.nsip_wait_recurse = true;
2573 	} else {
2574 		zones->p.nsip_wait_recurse = false;
2575 	}
2576 
2577 	pview = NULL;
2578 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
2579 				   view->rdclass, &pview);
2580 	if (result == ISC_R_SUCCESS) {
2581 		old = pview->rpzs;
2582 	} else {
2583 		old = NULL;
2584 	}
2585 	if (old == NULL) {
2586 		*old_rpz_okp = false;
2587 	} else {
2588 		*old_rpz_okp = true;
2589 	}
2590 
2591 	for (i = 0; zone_element != NULL;
2592 	     ++i, zone_element = cfg_list_next(zone_element))
2593 	{
2594 		INSIST(!*old_rpz_okp || old != NULL);
2595 		if (*old_rpz_okp && i < old->p.num_zones) {
2596 			old_zone = old->zones[i];
2597 		} else {
2598 			*old_rpz_okp = false;
2599 			old_zone = NULL;
2600 		}
2601 		result = configure_rpz_zone(
2602 			view, zone_element, recursive_only_default,
2603 			add_soa_default, ttl_default, minupdateinterval_default,
2604 			old_zone, old_rpz_okp);
2605 		if (result != ISC_R_SUCCESS) {
2606 			if (pview != NULL) {
2607 				dns_view_detach(&pview);
2608 			}
2609 			return (result);
2610 		}
2611 	}
2612 
2613 	/*
2614 	 * If this is a reloading and the parameters and list of policy
2615 	 * zones are unchanged, then use the same policy data.
2616 	 * Data for individual zones that must be reloaded will be merged.
2617 	 */
2618 	if (*old_rpz_okp) {
2619 		if (old != NULL &&
2620 		    memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0) {
2621 			*old_rpz_okp = false;
2622 		} else if ((old == NULL || old->rps_cstr == NULL) !=
2623 			   (zones->rps_cstr == NULL)) {
2624 			*old_rpz_okp = false;
2625 		} else if (old != NULL && zones->rps_cstr != NULL &&
2626 			   strcmp(old->rps_cstr, zones->rps_cstr) != 0)
2627 		{
2628 			*old_rpz_okp = false;
2629 		}
2630 	}
2631 
2632 	if (*old_rpz_okp) {
2633 		dns_rpz_detach_rpzs(&view->rpzs);
2634 		dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
2635 	} else if (old != NULL && pview != NULL) {
2636 		++pview->rpzs->rpz_ver;
2637 		view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
2638 		cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
2639 			    "updated RPZ policy: version %d",
2640 			    view->rpzs->rpz_ver);
2641 	}
2642 
2643 	if (pview != NULL) {
2644 		dns_view_detach(&pview);
2645 	}
2646 
2647 	return (ISC_R_SUCCESS);
2648 }
2649 
2650 static void
catz_addmodzone_taskaction(isc_task_t * task,isc_event_t * event0)2651 catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2652 	catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2653 	isc_result_t result;
2654 	isc_buffer_t namebuf;
2655 	isc_buffer_t *confbuf;
2656 	char nameb[DNS_NAME_FORMATSIZE];
2657 	const cfg_obj_t *zlist = NULL;
2658 	cfg_obj_t *zoneconf = NULL;
2659 	cfg_obj_t *zoneobj = NULL;
2660 	ns_cfgctx_t *cfg;
2661 	dns_zone_t *zone = NULL;
2662 
2663 	cfg = (ns_cfgctx_t *)ev->view->new_zone_config;
2664 	if (cfg == NULL) {
2665 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2666 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2667 			      "catz: allow-new-zones statement missing from "
2668 			      "config; cannot add zone from the catalog");
2669 		goto cleanup;
2670 	}
2671 
2672 	isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
2673 	dns_name_totext(dns_catz_entry_getname(ev->entry), true, &namebuf);
2674 	isc_buffer_putuint8(&namebuf, 0);
2675 
2676 	/* Zone shouldn't already exist */
2677 	result = dns_zt_find(ev->view->zonetable,
2678 			     dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
2679 
2680 	if (ev->mod) {
2681 		if (result != ISC_R_SUCCESS) {
2682 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2683 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2684 				      "catz: error \"%s\" while trying to "
2685 				      "modify zone \"%s\"",
2686 				      isc_result_totext(result), nameb);
2687 			goto cleanup;
2688 		} else {
2689 			if (!dns_zone_getadded(zone)) {
2690 				isc_log_write(
2691 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2692 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2693 					"catz: "
2694 					"catz_addmodzone_taskaction: "
2695 					"zone '%s' is not a dynamically "
2696 					"added zone",
2697 					nameb);
2698 				goto cleanup;
2699 			}
2700 			if (dns_zone_get_parentcatz(zone) != ev->origin) {
2701 				isc_log_write(
2702 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2703 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2704 					"catz: catz_delzone_taskaction: "
2705 					"zone '%s' exists in multiple "
2706 					"catalog zones",
2707 					nameb);
2708 				goto cleanup;
2709 			}
2710 			dns_zone_detach(&zone);
2711 		}
2712 	} else {
2713 		if (result == ISC_R_SUCCESS) {
2714 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2715 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
2716 				      "catz: zone \"%s\" is overridden "
2717 				      "by explicitly configured zone",
2718 				      nameb);
2719 			goto cleanup;
2720 		} else if (result != ISC_R_NOTFOUND &&
2721 			   result != DNS_R_PARTIALMATCH) {
2722 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2723 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2724 				      "catz: error \"%s\" while trying to "
2725 				      "add zone \"%s\"",
2726 				      isc_result_totext(result), nameb);
2727 			goto cleanup;
2728 		} else { /* this can happen in case of DNS_R_PARTIALMATCH */
2729 			if (zone != NULL) {
2730 				dns_zone_detach(&zone);
2731 			}
2732 		}
2733 	}
2734 	RUNTIME_CHECK(zone == NULL);
2735 	/* Create a config for new zone */
2736 	confbuf = NULL;
2737 	result = dns_catz_generate_zonecfg(ev->origin, ev->entry, &confbuf);
2738 	if (result == ISC_R_SUCCESS) {
2739 		cfg_parser_reset(cfg->add_parser);
2740 		result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
2741 					  &cfg_type_addzoneconf, 0, &zoneconf);
2742 		isc_buffer_free(&confbuf);
2743 	}
2744 	/*
2745 	 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer3()
2746 	 * failed.
2747 	 */
2748 	if (result != ISC_R_SUCCESS) {
2749 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2750 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2751 			      "catz: error \"%s\" while trying to generate "
2752 			      "config for zone \"%s\"",
2753 			      isc_result_totext(result), nameb);
2754 		goto cleanup;
2755 	}
2756 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
2757 	if (!cfg_obj_islist(zlist)) {
2758 		CHECK(ISC_R_FAILURE);
2759 	}
2760 
2761 	/* For now we only support adding one zone at a time */
2762 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
2763 
2764 	/* Mark view unfrozen so that zone can be added */
2765 
2766 	result = isc_task_beginexclusive(task);
2767 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2768 	dns_view_thaw(ev->view);
2769 	result = configure_zone(
2770 		cfg->config, zoneobj, cfg->vconfig, ev->cbd->server->mctx,
2771 		ev->view, &ev->cbd->server->viewlist,
2772 		&ev->cbd->server->kasplist, cfg->actx, true, false, ev->mod);
2773 	dns_view_freeze(ev->view);
2774 	isc_task_endexclusive(task);
2775 
2776 	if (result != ISC_R_SUCCESS) {
2777 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2778 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2779 			      "catz: failed to configure zone \"%s\" - %d",
2780 			      nameb, result);
2781 		goto cleanup;
2782 	}
2783 
2784 	/* Is it there yet? */
2785 	CHECK(dns_zt_find(ev->view->zonetable,
2786 			  dns_catz_entry_getname(ev->entry), 0, NULL, &zone));
2787 
2788 	/*
2789 	 * Load the zone from the master file.	If this fails, we'll
2790 	 * need to undo the configuration we've done already.
2791 	 */
2792 	result = dns_zone_load(zone, true);
2793 	if (result != ISC_R_SUCCESS) {
2794 		dns_db_t *dbp = NULL;
2795 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2796 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2797 			      "catz: dns_zone_load() failed "
2798 			      "with %s; reverting.",
2799 			      isc_result_totext(result));
2800 
2801 		/* If the zone loaded partially, unload it */
2802 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2803 			dns_db_detach(&dbp);
2804 			dns_zone_unload(zone);
2805 		}
2806 
2807 		/* Remove the zone from the zone table */
2808 		dns_zt_unmount(ev->view->zonetable, zone);
2809 		goto cleanup;
2810 	}
2811 
2812 	/* Flag the zone as having been added at runtime */
2813 	dns_zone_setadded(zone, true);
2814 	dns_zone_set_parentcatz(zone, ev->origin);
2815 
2816 cleanup:
2817 	if (zone != NULL) {
2818 		dns_zone_detach(&zone);
2819 	}
2820 	if (zoneconf != NULL) {
2821 		cfg_obj_destroy(cfg->add_parser, &zoneconf);
2822 	}
2823 	dns_catz_entry_detach(ev->origin, &ev->entry);
2824 	dns_catz_zone_detach(&ev->origin);
2825 	dns_view_detach(&ev->view);
2826 	isc_event_free(ISC_EVENT_PTR(&ev));
2827 }
2828 
2829 static void
catz_delzone_taskaction(isc_task_t * task,isc_event_t * event0)2830 catz_delzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2831 	catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2832 	isc_result_t result;
2833 	dns_zone_t *zone = NULL;
2834 	dns_db_t *dbp = NULL;
2835 	char cname[DNS_NAME_FORMATSIZE];
2836 	const char *file;
2837 
2838 	result = isc_task_beginexclusive(task);
2839 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2840 
2841 	dns_name_format(dns_catz_entry_getname(ev->entry), cname,
2842 			DNS_NAME_FORMATSIZE);
2843 	result = dns_zt_find(ev->view->zonetable,
2844 			     dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
2845 	if (result != ISC_R_SUCCESS) {
2846 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2847 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2848 			      "catz: catz_delzone_taskaction: "
2849 			      "zone '%s' not found",
2850 			      cname);
2851 		goto cleanup;
2852 	}
2853 
2854 	if (!dns_zone_getadded(zone)) {
2855 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2856 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2857 			      "catz: catz_delzone_taskaction: "
2858 			      "zone '%s' is not a dynamically added zone",
2859 			      cname);
2860 		goto cleanup;
2861 	}
2862 
2863 	if (dns_zone_get_parentcatz(zone) != ev->origin) {
2864 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2865 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2866 			      "catz: catz_delzone_taskaction: zone "
2867 			      "'%s' exists in multiple catalog zones",
2868 			      cname);
2869 		goto cleanup;
2870 	}
2871 
2872 	/* Stop answering for this zone */
2873 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2874 		dns_db_detach(&dbp);
2875 		dns_zone_unload(zone);
2876 	}
2877 
2878 	CHECK(dns_zt_unmount(ev->view->zonetable, zone));
2879 	file = dns_zone_getfile(zone);
2880 	if (file != NULL) {
2881 		isc_file_remove(file);
2882 		file = dns_zone_getjournal(zone);
2883 		if (file != NULL) {
2884 			isc_file_remove(file);
2885 		}
2886 	}
2887 
2888 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2889 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2890 		      "catz: catz_delzone_taskaction: "
2891 		      "zone '%s' deleted",
2892 		      cname);
2893 cleanup:
2894 	isc_task_endexclusive(task);
2895 	if (zone != NULL) {
2896 		dns_zone_detach(&zone);
2897 	}
2898 	dns_catz_entry_detach(ev->origin, &ev->entry);
2899 	dns_catz_zone_detach(&ev->origin);
2900 	dns_view_detach(&ev->view);
2901 	isc_event_free(ISC_EVENT_PTR(&ev));
2902 }
2903 
2904 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)2905 catz_create_chg_task(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
2906 		     dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata,
2907 		     isc_eventtype_t type) {
2908 	catz_chgzone_event_t *event;
2909 	isc_task_t *task;
2910 	isc_result_t result;
2911 	isc_taskaction_t action = NULL;
2912 
2913 	switch (type) {
2914 	case DNS_EVENT_CATZADDZONE:
2915 	case DNS_EVENT_CATZMODZONE:
2916 		action = catz_addmodzone_taskaction;
2917 		break;
2918 	case DNS_EVENT_CATZDELZONE:
2919 		action = catz_delzone_taskaction;
2920 		break;
2921 	default:
2922 		REQUIRE(0);
2923 	}
2924 
2925 	event = (catz_chgzone_event_t *)isc_event_allocate(
2926 		view->mctx, origin, type, action, NULL, sizeof(*event));
2927 
2928 	event->cbd = (catz_cb_data_t *)udata;
2929 	event->entry = NULL;
2930 	event->origin = NULL;
2931 	event->view = NULL;
2932 	event->mod = (type == DNS_EVENT_CATZMODZONE);
2933 	dns_catz_entry_attach(entry, &event->entry);
2934 	dns_catz_zone_attach(origin, &event->origin);
2935 	dns_view_attach(view, &event->view);
2936 
2937 	task = NULL;
2938 	result = isc_taskmgr_excltask(taskmgr, &task);
2939 	REQUIRE(result == ISC_R_SUCCESS);
2940 	isc_task_send(task, ISC_EVENT_PTR(&event));
2941 	isc_task_detach(&task);
2942 
2943 	return (ISC_R_SUCCESS);
2944 }
2945 
2946 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)2947 catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
2948 	     isc_taskmgr_t *taskmgr, void *udata) {
2949 	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
2950 				     DNS_EVENT_CATZADDZONE));
2951 }
2952 
2953 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)2954 catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
2955 	     isc_taskmgr_t *taskmgr, void *udata) {
2956 	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
2957 				     DNS_EVENT_CATZDELZONE));
2958 }
2959 
2960 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)2961 catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
2962 	     isc_taskmgr_t *taskmgr, void *udata) {
2963 	return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
2964 				     DNS_EVENT_CATZMODZONE));
2965 }
2966 
2967 static isc_result_t
configure_catz_zone(dns_view_t * view,const cfg_obj_t * config,const cfg_listelt_t * element)2968 configure_catz_zone(dns_view_t *view, const cfg_obj_t *config,
2969 		    const cfg_listelt_t *element) {
2970 	const cfg_obj_t *catz_obj, *obj;
2971 	dns_catz_zone_t *zone = NULL;
2972 	const char *str;
2973 	isc_result_t result;
2974 	dns_name_t origin;
2975 	dns_catz_options_t *opts;
2976 	dns_view_t *pview = NULL;
2977 
2978 	dns_name_init(&origin, NULL);
2979 	catz_obj = cfg_listelt_value(element);
2980 
2981 	str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
2982 
2983 	result = dns_name_fromstring(&origin, str, DNS_NAME_DOWNCASE,
2984 				     view->mctx);
2985 	if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname)) {
2986 		result = DNS_R_EMPTYLABEL;
2987 	}
2988 
2989 	if (result != ISC_R_SUCCESS) {
2990 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
2991 			    "catz: invalid zone name '%s'", str);
2992 		goto cleanup;
2993 	}
2994 
2995 	result = dns_catz_add_zone(view->catzs, &origin, &zone);
2996 	if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
2997 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
2998 			    "catz: unable to create catalog zone '%s', "
2999 			    "error %s",
3000 			    str, isc_result_totext(result));
3001 		goto cleanup;
3002 	}
3003 
3004 	if (result == ISC_R_EXISTS) {
3005 		isc_ht_iter_t *it = NULL;
3006 
3007 		result = dns_viewlist_find(&named_g_server->viewlist,
3008 					   view->name, view->rdclass, &pview);
3009 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3010 
3011 		/*
3012 		 * xxxwpk todo: reconfigure the zone!!!!
3013 		 */
3014 		cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3015 			    "catz: catalog zone '%s' will not be reconfigured",
3016 			    str);
3017 		/*
3018 		 * We have to walk through all the member zones and attach
3019 		 * them to current view
3020 		 */
3021 		result = dns_catz_get_iterator(zone, &it);
3022 		if (result != ISC_R_SUCCESS) {
3023 			cfg_obj_log(catz_obj, named_g_lctx,
3024 				    DNS_CATZ_ERROR_LEVEL,
3025 				    "catz: unable to create iterator");
3026 			goto cleanup;
3027 		}
3028 
3029 		for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
3030 		     result = isc_ht_iter_next(it))
3031 		{
3032 			dns_name_t *name = NULL;
3033 			dns_zone_t *dnszone = NULL;
3034 			dns_catz_entry_t *entry = NULL;
3035 			isc_result_t tresult;
3036 
3037 			isc_ht_iter_current(it, (void **)&entry);
3038 			name = dns_catz_entry_getname(entry);
3039 
3040 			tresult = dns_view_findzone(pview, name, &dnszone);
3041 			if (tresult != ISC_R_SUCCESS) {
3042 				continue;
3043 			}
3044 
3045 			dns_zone_setview(dnszone, view);
3046 			dns_view_addzone(view, dnszone);
3047 
3048 			/*
3049 			 * The dns_view_findzone() call above increments the
3050 			 * zone's reference count, which we need to decrement
3051 			 * back.  However, as dns_zone_detach() sets the
3052 			 * supplied pointer to NULL, calling it is deferred
3053 			 * until the dnszone variable is no longer used.
3054 			 */
3055 			dns_zone_detach(&dnszone);
3056 		}
3057 
3058 		isc_ht_iter_destroy(&it);
3059 
3060 		result = ISC_R_SUCCESS;
3061 	}
3062 
3063 	dns_catz_zone_resetdefoptions(zone);
3064 	opts = dns_catz_zone_getdefoptions(zone);
3065 
3066 	obj = cfg_tuple_get(catz_obj, "default-masters");
3067 	if (obj == NULL || !cfg_obj_istuple(obj)) {
3068 		obj = cfg_tuple_get(catz_obj, "default-primaries");
3069 	}
3070 	if (obj != NULL && cfg_obj_istuple(obj)) {
3071 		result = named_config_getipandkeylist(
3072 			config, "primaries", obj, view->mctx, &opts->masters);
3073 	}
3074 
3075 	obj = cfg_tuple_get(catz_obj, "in-memory");
3076 	if (obj != NULL && cfg_obj_isboolean(obj)) {
3077 		opts->in_memory = cfg_obj_asboolean(obj);
3078 	}
3079 
3080 	obj = cfg_tuple_get(catz_obj, "zone-directory");
3081 	if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) {
3082 		opts->zonedir = isc_mem_strdup(view->mctx,
3083 					       cfg_obj_asstring(obj));
3084 		if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) {
3085 			cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3086 				    "catz: zone-directory '%s' "
3087 				    "not found; zone files will not be "
3088 				    "saved",
3089 				    opts->zonedir);
3090 			opts->in_memory = true;
3091 		}
3092 	}
3093 
3094 	obj = cfg_tuple_get(catz_obj, "min-update-interval");
3095 	if (obj != NULL && cfg_obj_isduration(obj)) {
3096 		opts->min_update_interval = cfg_obj_asduration(obj);
3097 	}
3098 
3099 cleanup:
3100 	if (pview != NULL) {
3101 		dns_view_detach(&pview);
3102 	}
3103 	dns_name_free(&origin, view->mctx);
3104 
3105 	return (result);
3106 }
3107 
3108 static catz_cb_data_t ns_catz_cbdata;
3109 static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
3110 	catz_addzone, catz_modzone, catz_delzone, &ns_catz_cbdata
3111 };
3112 
3113 static isc_result_t
configure_catz(dns_view_t * view,const cfg_obj_t * config,const cfg_obj_t * catz_obj)3114 configure_catz(dns_view_t *view, const cfg_obj_t *config,
3115 	       const cfg_obj_t *catz_obj) {
3116 	const cfg_listelt_t *zone_element;
3117 	const dns_catz_zones_t *old = NULL;
3118 	dns_view_t *pview = NULL;
3119 	isc_result_t result;
3120 
3121 	/* xxxwpk TODO do it cleaner, once, somewhere */
3122 	ns_catz_cbdata.server = named_g_server;
3123 
3124 	zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
3125 	if (zone_element == NULL) {
3126 		return (ISC_R_SUCCESS);
3127 	}
3128 
3129 	CHECK(dns_catz_new_zones(&view->catzs, &ns_catz_zonemodmethods,
3130 				 view->mctx, named_g_taskmgr,
3131 				 named_g_timermgr));
3132 
3133 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
3134 				   view->rdclass, &pview);
3135 	if (result == ISC_R_SUCCESS) {
3136 		old = pview->catzs;
3137 	}
3138 
3139 	if (old != NULL) {
3140 		dns_catz_catzs_detach(&view->catzs);
3141 		dns_catz_catzs_attach(pview->catzs, &view->catzs);
3142 		dns_catz_prereconfig(view->catzs);
3143 	}
3144 
3145 	while (zone_element != NULL) {
3146 		CHECK(configure_catz_zone(view, config, zone_element));
3147 		zone_element = cfg_list_next(zone_element);
3148 	}
3149 
3150 	if (old != NULL) {
3151 		dns_catz_postreconfig(view->catzs);
3152 	}
3153 
3154 	result = ISC_R_SUCCESS;
3155 
3156 cleanup:
3157 	if (pview != NULL) {
3158 		dns_view_detach(&pview);
3159 	}
3160 
3161 	return (result);
3162 }
3163 
3164 #define CHECK_RRL(cond, pat, val1, val2)                                   \
3165 	do {                                                               \
3166 		if (!(cond)) {                                             \
3167 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, pat, \
3168 				    val1, val2);                           \
3169 			result = ISC_R_RANGE;                              \
3170 			goto cleanup;                                      \
3171 		}                                                          \
3172 	} while (0)
3173 
3174 #define CHECK_RRL_RATE(rate, def, max_rate, name)                           \
3175 	do {                                                                \
3176 		obj = NULL;                                                 \
3177 		rrl->rate.str = name;                                       \
3178 		result = cfg_map_get(map, name, &obj);                      \
3179 		if (result == ISC_R_SUCCESS) {                              \
3180 			rrl->rate.r = cfg_obj_asuint32(obj);                \
3181 			CHECK_RRL(rrl->rate.r <= max_rate, name " %d > %d", \
3182 				  rrl->rate.r, max_rate);                   \
3183 		} else {                                                    \
3184 			rrl->rate.r = def;                                  \
3185 		}                                                           \
3186 		rrl->rate.scaled = rrl->rate.r;                             \
3187 	} while (0)
3188 
3189 static isc_result_t
configure_rrl(dns_view_t * view,const cfg_obj_t * config,const cfg_obj_t * map)3190 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
3191 	const cfg_obj_t *obj;
3192 	dns_rrl_t *rrl;
3193 	isc_result_t result;
3194 	int min_entries, i, j;
3195 
3196 	/*
3197 	 * Most DNS servers have few clients, but intentinally open
3198 	 * recursive and authoritative servers often have many.
3199 	 * So start with a small number of entries unless told otherwise
3200 	 * to reduce cold-start costs.
3201 	 */
3202 	min_entries = 500;
3203 	obj = NULL;
3204 	result = cfg_map_get(map, "min-table-size", &obj);
3205 	if (result == ISC_R_SUCCESS) {
3206 		min_entries = cfg_obj_asuint32(obj);
3207 		if (min_entries < 1) {
3208 			min_entries = 1;
3209 		}
3210 	}
3211 	result = dns_rrl_init(&rrl, view, min_entries);
3212 	if (result != ISC_R_SUCCESS) {
3213 		return (result);
3214 	}
3215 
3216 	i = ISC_MAX(20000, min_entries);
3217 	obj = NULL;
3218 	result = cfg_map_get(map, "max-table-size", &obj);
3219 	if (result == ISC_R_SUCCESS) {
3220 		i = cfg_obj_asuint32(obj);
3221 		CHECK_RRL(i >= min_entries,
3222 			  "max-table-size %d < min-table-size %d", i,
3223 			  min_entries);
3224 	}
3225 	rrl->max_entries = i;
3226 
3227 	CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
3228 		       "responses-per-second");
3229 	CHECK_RRL_RATE(referrals_per_second, rrl->responses_per_second.r,
3230 		       DNS_RRL_MAX_RATE, "referrals-per-second");
3231 	CHECK_RRL_RATE(nodata_per_second, rrl->responses_per_second.r,
3232 		       DNS_RRL_MAX_RATE, "nodata-per-second");
3233 	CHECK_RRL_RATE(nxdomains_per_second, rrl->responses_per_second.r,
3234 		       DNS_RRL_MAX_RATE, "nxdomains-per-second");
3235 	CHECK_RRL_RATE(errors_per_second, rrl->responses_per_second.r,
3236 		       DNS_RRL_MAX_RATE, "errors-per-second");
3237 
3238 	CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
3239 
3240 	CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
3241 
3242 	i = 15;
3243 	obj = NULL;
3244 	result = cfg_map_get(map, "window", &obj);
3245 	if (result == ISC_R_SUCCESS) {
3246 		i = cfg_obj_asuint32(obj);
3247 		CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
3248 			  "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
3249 	}
3250 	rrl->window = i;
3251 
3252 	i = 0;
3253 	obj = NULL;
3254 	result = cfg_map_get(map, "qps-scale", &obj);
3255 	if (result == ISC_R_SUCCESS) {
3256 		i = cfg_obj_asuint32(obj);
3257 		CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
3258 	}
3259 	rrl->qps_scale = i;
3260 	rrl->qps = 1.0;
3261 
3262 	i = 24;
3263 	obj = NULL;
3264 	result = cfg_map_get(map, "ipv4-prefix-length", &obj);
3265 	if (result == ISC_R_SUCCESS) {
3266 		i = cfg_obj_asuint32(obj);
3267 		CHECK_RRL(i >= 8 && i <= 32,
3268 			  "invalid 'ipv4-prefix-length %d'%s", i, "");
3269 	}
3270 	rrl->ipv4_prefixlen = i;
3271 	if (i == 32) {
3272 		rrl->ipv4_mask = 0xffffffff;
3273 	} else {
3274 		rrl->ipv4_mask = htonl(0xffffffff << (32 - i));
3275 	}
3276 
3277 	i = 56;
3278 	obj = NULL;
3279 	result = cfg_map_get(map, "ipv6-prefix-length", &obj);
3280 	if (result == ISC_R_SUCCESS) {
3281 		i = cfg_obj_asuint32(obj);
3282 		CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
3283 			  "ipv6-prefix-length %d < 16 or > %d", i,
3284 			  DNS_RRL_MAX_PREFIX);
3285 	}
3286 	rrl->ipv6_prefixlen = i;
3287 	for (j = 0; j < 4; ++j) {
3288 		if (i <= 0) {
3289 			rrl->ipv6_mask[j] = 0;
3290 		} else if (i < 32) {
3291 			rrl->ipv6_mask[j] = htonl(0xffffffff << (32 - i));
3292 		} else {
3293 			rrl->ipv6_mask[j] = 0xffffffff;
3294 		}
3295 		i -= 32;
3296 	}
3297 
3298 	obj = NULL;
3299 	result = cfg_map_get(map, "exempt-clients", &obj);
3300 	if (result == ISC_R_SUCCESS) {
3301 		result = cfg_acl_fromconfig(obj, config, named_g_lctx,
3302 					    named_g_aclconfctx, named_g_mctx, 0,
3303 					    &rrl->exempt);
3304 		CHECK_RRL(result == ISC_R_SUCCESS, "invalid %s%s",
3305 			  "address match list", "");
3306 	}
3307 
3308 	obj = NULL;
3309 	result = cfg_map_get(map, "log-only", &obj);
3310 	if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) {
3311 		rrl->log_only = true;
3312 	} else {
3313 		rrl->log_only = false;
3314 	}
3315 
3316 	return (ISC_R_SUCCESS);
3317 
3318 cleanup:
3319 	dns_rrl_view_destroy(view);
3320 	return (result);
3321 }
3322 
3323 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)3324 add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3325 	const dns_name_t *origin, const dns_name_t *contact) {
3326 	dns_dbnode_t *node = NULL;
3327 	dns_rdata_t rdata = DNS_RDATA_INIT;
3328 	dns_rdatalist_t rdatalist;
3329 	dns_rdataset_t rdataset;
3330 	isc_result_t result;
3331 	unsigned char buf[DNS_SOA_BUFFERSIZE];
3332 
3333 	CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 0, 28800,
3334 				 7200, 604800, 86400, buf, &rdata));
3335 
3336 	dns_rdatalist_init(&rdatalist);
3337 	rdatalist.type = rdata.type;
3338 	rdatalist.rdclass = rdata.rdclass;
3339 	rdatalist.ttl = 86400;
3340 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3341 
3342 	dns_rdataset_init(&rdataset);
3343 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3344 	CHECK(dns_db_findnode(db, name, true, &node));
3345 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3346 
3347 cleanup:
3348 	if (node != NULL) {
3349 		dns_db_detachnode(db, &node);
3350 	}
3351 	return (result);
3352 }
3353 
3354 static isc_result_t
add_ns(dns_db_t * db,dns_dbversion_t * version,const dns_name_t * name,const dns_name_t * nsname)3355 add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3356        const dns_name_t *nsname) {
3357 	dns_dbnode_t *node = NULL;
3358 	dns_rdata_ns_t ns;
3359 	dns_rdata_t rdata = DNS_RDATA_INIT;
3360 	dns_rdatalist_t rdatalist;
3361 	dns_rdataset_t rdataset;
3362 	isc_result_t result;
3363 	isc_buffer_t b;
3364 	unsigned char buf[DNS_NAME_MAXWIRE];
3365 
3366 	isc_buffer_init(&b, buf, sizeof(buf));
3367 
3368 	ns.common.rdtype = dns_rdatatype_ns;
3369 	ns.common.rdclass = dns_db_class(db);
3370 	ns.mctx = NULL;
3371 	dns_name_init(&ns.name, NULL);
3372 	dns_name_clone(nsname, &ns.name);
3373 	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
3374 				   &ns, &b));
3375 
3376 	dns_rdatalist_init(&rdatalist);
3377 	rdatalist.type = rdata.type;
3378 	rdatalist.rdclass = rdata.rdclass;
3379 	rdatalist.ttl = 86400;
3380 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3381 
3382 	dns_rdataset_init(&rdataset);
3383 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3384 	CHECK(dns_db_findnode(db, name, true, &node));
3385 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3386 
3387 cleanup:
3388 	if (node != NULL) {
3389 		dns_db_detachnode(db, &node);
3390 	}
3391 	return (result);
3392 }
3393 
3394 static isc_result_t
create_empty_zone(dns_zone_t * pzone,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)3395 create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
3396 		  const cfg_obj_t *zonelist, const char **empty_dbtype,
3397 		  int empty_dbtypec, dns_zonestat_level_t statlevel) {
3398 	char namebuf[DNS_NAME_FORMATSIZE];
3399 	const cfg_listelt_t *element;
3400 	const cfg_obj_t *obj;
3401 	const cfg_obj_t *zconfig;
3402 	const cfg_obj_t *zoptions;
3403 	const char *rbt_dbtype[4] = { "rbt" };
3404 	const char *sep = ": view ";
3405 	const char *str;
3406 	const char *viewname = view->name;
3407 	dns_db_t *db = NULL;
3408 	dns_dbversion_t *version = NULL;
3409 	dns_fixedname_t cfixed;
3410 	dns_fixedname_t fixed;
3411 	dns_fixedname_t nsfixed;
3412 	dns_name_t *contact;
3413 	dns_name_t *ns;
3414 	dns_name_t *zname;
3415 	dns_zone_t *zone = NULL;
3416 	int rbt_dbtypec = 1;
3417 	isc_result_t result;
3418 	dns_namereln_t namereln;
3419 	int order;
3420 	unsigned int nlabels;
3421 
3422 	zname = dns_fixedname_initname(&fixed);
3423 	ns = dns_fixedname_initname(&nsfixed);
3424 	contact = dns_fixedname_initname(&cfixed);
3425 
3426 	/*
3427 	 * Look for forward "zones" beneath this empty zone and if so
3428 	 * create a custom db for the empty zone.
3429 	 */
3430 	for (element = cfg_list_first(zonelist); element != NULL;
3431 	     element = cfg_list_next(element))
3432 	{
3433 		zconfig = cfg_listelt_value(element);
3434 		str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3435 		CHECK(dns_name_fromstring(zname, str, 0, NULL));
3436 		namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
3437 		if (namereln != dns_namereln_subdomain) {
3438 			continue;
3439 		}
3440 
3441 		zoptions = cfg_tuple_get(zconfig, "options");
3442 
3443 		obj = NULL;
3444 		(void)cfg_map_get(zoptions, "type", &obj);
3445 		if (obj != NULL &&
3446 		    strcasecmp(cfg_obj_asstring(obj), "forward") == 0) {
3447 			obj = NULL;
3448 			(void)cfg_map_get(zoptions, "forward", &obj);
3449 			if (obj == NULL) {
3450 				continue;
3451 			}
3452 			if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) {
3453 				continue;
3454 			}
3455 		}
3456 		if (db == NULL) {
3457 			CHECK(dns_db_create(view->mctx, "rbt", name,
3458 					    dns_dbtype_zone, view->rdclass, 0,
3459 					    NULL, &db));
3460 			CHECK(dns_db_newversion(db, &version));
3461 			if (strcmp(empty_dbtype[2], "@") == 0) {
3462 				dns_name_clone(name, ns);
3463 			} else {
3464 				CHECK(dns_name_fromstring(ns, empty_dbtype[2],
3465 							  0, NULL));
3466 			}
3467 			CHECK(dns_name_fromstring(contact, empty_dbtype[3], 0,
3468 						  NULL));
3469 			CHECK(add_soa(db, version, name, ns, contact));
3470 			CHECK(add_ns(db, version, name, ns));
3471 		}
3472 		CHECK(add_ns(db, version, zname, dns_rootname));
3473 	}
3474 
3475 	/*
3476 	 * Is the existing zone the ok to use?
3477 	 */
3478 	if (pzone != NULL) {
3479 		unsigned int typec;
3480 		const char **dbargv;
3481 
3482 		if (db != NULL) {
3483 			typec = rbt_dbtypec;
3484 			dbargv = rbt_dbtype;
3485 		} else {
3486 			typec = empty_dbtypec;
3487 			dbargv = empty_dbtype;
3488 		}
3489 
3490 		result = check_dbtype(pzone, typec, dbargv, view->mctx);
3491 		if (result != ISC_R_SUCCESS) {
3492 			pzone = NULL;
3493 		}
3494 
3495 		if (pzone != NULL &&
3496 		    dns_zone_gettype(pzone) != dns_zone_primary) {
3497 			pzone = NULL;
3498 		}
3499 		if (pzone != NULL && dns_zone_getfile(pzone) != NULL) {
3500 			pzone = NULL;
3501 		}
3502 		if (pzone != NULL) {
3503 			dns_zone_getraw(pzone, &zone);
3504 			if (zone != NULL) {
3505 				dns_zone_detach(&zone);
3506 				pzone = NULL;
3507 			}
3508 		}
3509 	}
3510 
3511 	if (pzone == NULL) {
3512 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
3513 		CHECK(dns_zone_setorigin(zone, name));
3514 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3515 		if (db == NULL) {
3516 			dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype);
3517 		}
3518 		dns_zone_setclass(zone, view->rdclass);
3519 		dns_zone_settype(zone, dns_zone_primary);
3520 		dns_zone_setstats(zone, named_g_server->zonestats);
3521 	} else {
3522 		dns_zone_attach(pzone, &zone);
3523 	}
3524 
3525 	dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
3526 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3527 	dns_zone_setnotifytype(zone, dns_notifytype_no);
3528 	dns_zone_setdialup(zone, dns_dialuptype_no);
3529 	dns_zone_setautomatic(zone, true);
3530 	if (view->queryacl != NULL) {
3531 		dns_zone_setqueryacl(zone, view->queryacl);
3532 	} else {
3533 		dns_zone_clearqueryacl(zone);
3534 	}
3535 	if (view->queryonacl != NULL) {
3536 		dns_zone_setqueryonacl(zone, view->queryonacl);
3537 	} else {
3538 		dns_zone_clearqueryonacl(zone);
3539 	}
3540 	dns_zone_clearupdateacl(zone);
3541 	if (view->transferacl != NULL) {
3542 		dns_zone_setxfracl(zone, view->transferacl);
3543 	} else {
3544 		dns_zone_clearxfracl(zone);
3545 	}
3546 
3547 	CHECK(setquerystats(zone, view->mctx, statlevel));
3548 	if (db != NULL) {
3549 		dns_db_closeversion(db, &version, true);
3550 		CHECK(dns_zone_replacedb(zone, db, false));
3551 	}
3552 	dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true);
3553 	dns_zone_setview(zone, view);
3554 	CHECK(dns_view_addzone(view, zone));
3555 
3556 	if (!strcmp(viewname, "_default")) {
3557 		sep = "";
3558 		viewname = "";
3559 	}
3560 	dns_name_format(name, namebuf, sizeof(namebuf));
3561 	isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD,
3562 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3563 		      "automatic empty zone%s%s: %s", sep, viewname, namebuf);
3564 
3565 cleanup:
3566 	if (zone != NULL) {
3567 		dns_zone_detach(&zone);
3568 	}
3569 	if (version != NULL) {
3570 		dns_db_closeversion(db, &version, false);
3571 	}
3572 	if (db != NULL) {
3573 		dns_db_detach(&db);
3574 	}
3575 
3576 	INSIST(version == NULL);
3577 
3578 	return (result);
3579 }
3580 
3581 static isc_result_t
create_ipv4only_zone(dns_zone_t * pzone,dns_view_t * view,const dns_name_t * name,const char * type,isc_mem_t * mctx,const char * server,const char * contact)3582 create_ipv4only_zone(dns_zone_t *pzone, dns_view_t *view,
3583 		     const dns_name_t *name, const char *type, isc_mem_t *mctx,
3584 		     const char *server, const char *contact) {
3585 	char namebuf[DNS_NAME_FORMATSIZE];
3586 	const char *dbtype[4] = { "_builtin", NULL, "@", "." };
3587 	const char *sep = ": view ";
3588 	const char *viewname = view->name;
3589 	dns_zone_t *zone = NULL;
3590 	int dbtypec = 4;
3591 	isc_result_t result;
3592 
3593 	REQUIRE(type != NULL);
3594 
3595 	if (!strcmp(viewname, "_default")) {
3596 		sep = "";
3597 		viewname = "";
3598 	}
3599 
3600 	dbtype[1] = type;
3601 	if (server != NULL) {
3602 		dbtype[2] = server;
3603 	}
3604 	if (contact != NULL) {
3605 		dbtype[3] = contact;
3606 	}
3607 
3608 	if (pzone != NULL) {
3609 		result = check_dbtype(pzone, dbtypec, dbtype, view->mctx);
3610 		if (result != ISC_R_SUCCESS) {
3611 			pzone = NULL;
3612 		}
3613 	}
3614 
3615 	if (pzone == NULL) {
3616 		/*
3617 		 * Create the actual zone.
3618 		 */
3619 		CHECK(dns_zone_create(&zone, mctx));
3620 		CHECK(dns_zone_setorigin(zone, name));
3621 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3622 		dns_zone_setclass(zone, view->rdclass);
3623 		dns_zone_settype(zone, dns_zone_primary);
3624 		dns_zone_setstats(zone, named_g_server->zonestats);
3625 		dns_zone_setdbtype(zone, dbtypec, dbtype);
3626 		dns_zone_setdialup(zone, dns_dialuptype_no);
3627 		dns_zone_setnotifytype(zone, dns_notifytype_no);
3628 		dns_zone_setautomatic(zone, true);
3629 		dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3630 	} else {
3631 		dns_zone_attach(pzone, &zone);
3632 	}
3633 	if (view->queryacl != NULL) {
3634 		dns_zone_setqueryacl(zone, view->queryacl);
3635 	} else {
3636 		dns_zone_clearqueryacl(zone);
3637 	}
3638 	if (view->queryonacl != NULL) {
3639 		dns_zone_setqueryonacl(zone, view->queryonacl);
3640 	} else {
3641 		dns_zone_clearqueryonacl(zone);
3642 	}
3643 	dns_zone_setview(zone, view);
3644 	CHECK(dns_view_addzone(view, zone));
3645 
3646 	dns_name_format(name, namebuf, sizeof(namebuf));
3647 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3648 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3649 		      "automatic ipv4only zone%s%s: %s", sep, viewname,
3650 		      namebuf);
3651 
3652 cleanup:
3653 	if (zone != NULL) {
3654 		dns_zone_detach(&zone);
3655 	}
3656 	return (result);
3657 }
3658 
3659 #ifdef HAVE_DNSTAP
3660 static isc_result_t
configure_dnstap(const cfg_obj_t ** maps,dns_view_t * view)3661 configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
3662 	isc_result_t result;
3663 	const cfg_obj_t *obj, *obj2;
3664 	const cfg_listelt_t *element;
3665 	const char *dpath;
3666 	const cfg_obj_t *dlist = NULL;
3667 	dns_dtmsgtype_t dttypes = 0;
3668 	unsigned int i;
3669 	struct fstrm_iothr_options *fopt = NULL;
3670 
3671 	result = named_config_get(maps, "dnstap", &dlist);
3672 	if (result != ISC_R_SUCCESS) {
3673 		return (ISC_R_SUCCESS);
3674 	}
3675 
3676 	for (element = cfg_list_first(dlist); element != NULL;
3677 	     element = cfg_list_next(element))
3678 	{
3679 		const char *str;
3680 		dns_dtmsgtype_t dt = 0;
3681 
3682 		obj = cfg_listelt_value(element);
3683 		obj2 = cfg_tuple_get(obj, "type");
3684 		str = cfg_obj_asstring(obj2);
3685 		if (strcasecmp(str, "client") == 0) {
3686 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR;
3687 		} else if (strcasecmp(str, "auth") == 0) {
3688 			dt |= DNS_DTTYPE_AQ | DNS_DTTYPE_AR;
3689 		} else if (strcasecmp(str, "resolver") == 0) {
3690 			dt |= DNS_DTTYPE_RQ | DNS_DTTYPE_RR;
3691 		} else if (strcasecmp(str, "forwarder") == 0) {
3692 			dt |= DNS_DTTYPE_FQ | DNS_DTTYPE_FR;
3693 		} else if (strcasecmp(str, "update") == 0) {
3694 			dt |= DNS_DTTYPE_UQ | DNS_DTTYPE_UR;
3695 		} else if (strcasecmp(str, "all") == 0) {
3696 			dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR | DNS_DTTYPE_AQ |
3697 			      DNS_DTTYPE_AR | DNS_DTTYPE_RQ | DNS_DTTYPE_RR |
3698 			      DNS_DTTYPE_FQ | DNS_DTTYPE_FR | DNS_DTTYPE_UQ |
3699 			      DNS_DTTYPE_UR;
3700 		}
3701 
3702 		obj2 = cfg_tuple_get(obj, "mode");
3703 		if (obj2 == NULL || cfg_obj_isvoid(obj2)) {
3704 			dttypes |= dt;
3705 			continue;
3706 		}
3707 
3708 		str = cfg_obj_asstring(obj2);
3709 		if (strcasecmp(str, "query") == 0) {
3710 			dt &= ~DNS_DTTYPE_RESPONSE;
3711 		} else if (strcasecmp(str, "response") == 0) {
3712 			dt &= ~DNS_DTTYPE_QUERY;
3713 		}
3714 
3715 		dttypes |= dt;
3716 	}
3717 
3718 	if (named_g_server->dtenv == NULL && dttypes != 0) {
3719 		dns_dtmode_t dmode;
3720 		uint64_t max_size = 0;
3721 		uint32_t rolls = 0;
3722 		isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment;
3723 
3724 		obj = NULL;
3725 		CHECKM(named_config_get(maps, "dnstap-output", &obj),
3726 		       "'dnstap-output' must be set if 'dnstap' is set");
3727 
3728 		obj2 = cfg_tuple_get(obj, "mode");
3729 		if (obj2 == NULL) {
3730 			CHECKM(ISC_R_FAILURE, "dnstap-output mode not found");
3731 		}
3732 		if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) {
3733 			dmode = dns_dtmode_file;
3734 		} else {
3735 			dmode = dns_dtmode_unix;
3736 		}
3737 
3738 		obj2 = cfg_tuple_get(obj, "path");
3739 		if (obj2 == NULL) {
3740 			CHECKM(ISC_R_FAILURE, "dnstap-output path not found");
3741 		}
3742 
3743 		dpath = cfg_obj_asstring(obj2);
3744 
3745 		obj2 = cfg_tuple_get(obj, "size");
3746 		if (obj2 != NULL && cfg_obj_isuint64(obj2)) {
3747 			max_size = cfg_obj_asuint64(obj2);
3748 			if (max_size > SIZE_MAX) {
3749 				cfg_obj_log(obj2, named_g_lctx, ISC_LOG_WARNING,
3750 					    "'dnstap-output size "
3751 					    "%" PRIu64 "' "
3752 					    "is too large for this "
3753 					    "system; reducing to %lu",
3754 					    max_size, (unsigned long)SIZE_MAX);
3755 				max_size = SIZE_MAX;
3756 			}
3757 		}
3758 
3759 		obj2 = cfg_tuple_get(obj, "versions");
3760 		if (obj2 != NULL && cfg_obj_isuint32(obj2)) {
3761 			rolls = cfg_obj_asuint32(obj2);
3762 		} else {
3763 			rolls = ISC_LOG_ROLLINFINITE;
3764 		}
3765 
3766 		obj2 = cfg_tuple_get(obj, "suffix");
3767 		if (obj2 != NULL && cfg_obj_isstring(obj2) &&
3768 		    strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0)
3769 		{
3770 			suffix = isc_log_rollsuffix_timestamp;
3771 		}
3772 
3773 		fopt = fstrm_iothr_options_init();
3774 		/*
3775 		 * Both network threads and worker threads may log dnstap data.
3776 		 */
3777 		fstrm_iothr_options_set_num_input_queues(fopt,
3778 							 2 * named_g_cpus);
3779 		fstrm_iothr_options_set_queue_model(
3780 			fopt, FSTRM_IOTHR_QUEUE_MODEL_MPSC);
3781 
3782 		obj = NULL;
3783 		result = named_config_get(maps, "fstrm-set-buffer-hint", &obj);
3784 		if (result == ISC_R_SUCCESS) {
3785 			i = cfg_obj_asuint32(obj);
3786 			fstrm_iothr_options_set_buffer_hint(fopt, i);
3787 		}
3788 
3789 		obj = NULL;
3790 		result = named_config_get(maps, "fstrm-set-flush-timeout",
3791 					  &obj);
3792 		if (result == ISC_R_SUCCESS) {
3793 			i = cfg_obj_asuint32(obj);
3794 			fstrm_iothr_options_set_flush_timeout(fopt, i);
3795 		}
3796 
3797 		obj = NULL;
3798 		result = named_config_get(maps, "fstrm-set-input-queue-size",
3799 					  &obj);
3800 		if (result == ISC_R_SUCCESS) {
3801 			i = cfg_obj_asuint32(obj);
3802 			fstrm_iothr_options_set_input_queue_size(fopt, i);
3803 		}
3804 
3805 		obj = NULL;
3806 		result = named_config_get(
3807 			maps, "fstrm-set-output-notify-threshold", &obj);
3808 		if (result == ISC_R_SUCCESS) {
3809 			i = cfg_obj_asuint32(obj);
3810 			fstrm_iothr_options_set_queue_notify_threshold(fopt, i);
3811 		}
3812 
3813 		obj = NULL;
3814 		result = named_config_get(maps, "fstrm-set-output-queue-model",
3815 					  &obj);
3816 		if (result == ISC_R_SUCCESS) {
3817 			if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0) {
3818 				i = FSTRM_IOTHR_QUEUE_MODEL_SPSC;
3819 			} else {
3820 				i = FSTRM_IOTHR_QUEUE_MODEL_MPSC;
3821 			}
3822 			fstrm_iothr_options_set_queue_model(fopt, i);
3823 		}
3824 
3825 		obj = NULL;
3826 		result = named_config_get(maps, "fstrm-set-output-queue-size",
3827 					  &obj);
3828 		if (result == ISC_R_SUCCESS) {
3829 			i = cfg_obj_asuint32(obj);
3830 			fstrm_iothr_options_set_output_queue_size(fopt, i);
3831 		}
3832 
3833 		obj = NULL;
3834 		result = named_config_get(maps, "fstrm-set-reopen-interval",
3835 					  &obj);
3836 		if (result == ISC_R_SUCCESS) {
3837 			i = cfg_obj_asduration(obj);
3838 			fstrm_iothr_options_set_reopen_interval(fopt, i);
3839 		}
3840 
3841 		CHECKM(dns_dt_create(named_g_mctx, dmode, dpath, &fopt,
3842 				     named_g_server->task,
3843 				     &named_g_server->dtenv),
3844 		       "unable to create dnstap environment");
3845 
3846 		CHECKM(dns_dt_setupfile(named_g_server->dtenv, max_size, rolls,
3847 					suffix),
3848 		       "unable to set up dnstap logfile");
3849 	}
3850 
3851 	if (named_g_server->dtenv == NULL) {
3852 		return (ISC_R_SUCCESS);
3853 	}
3854 
3855 	obj = NULL;
3856 	result = named_config_get(maps, "dnstap-version", &obj);
3857 	if (result != ISC_R_SUCCESS) {
3858 		/* not specified; use the product and version */
3859 		dns_dt_setversion(named_g_server->dtenv, PACKAGE_STRING);
3860 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3861 		/* Quoted string */
3862 		dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj));
3863 	}
3864 
3865 	obj = NULL;
3866 	result = named_config_get(maps, "dnstap-identity", &obj);
3867 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
3868 		/* "hostname" is interpreted as boolean true */
3869 		char buf[256];
3870 		result = named_os_gethostname(buf, sizeof(buf));
3871 		if (result == ISC_R_SUCCESS) {
3872 			dns_dt_setidentity(named_g_server->dtenv, buf);
3873 		}
3874 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3875 		/* Quoted string */
3876 		dns_dt_setidentity(named_g_server->dtenv,
3877 				   cfg_obj_asstring(obj));
3878 	}
3879 
3880 	dns_dt_attach(named_g_server->dtenv, &view->dtenv);
3881 	view->dttypes = dttypes;
3882 
3883 	result = ISC_R_SUCCESS;
3884 
3885 cleanup:
3886 	if (fopt != NULL) {
3887 		fstrm_iothr_options_destroy(&fopt);
3888 	}
3889 
3890 	return (result);
3891 }
3892 #endif /* HAVE_DNSTAP */
3893 
3894 static isc_result_t
create_mapped_acl(void)3895 create_mapped_acl(void) {
3896 	isc_result_t result;
3897 	dns_acl_t *acl = NULL;
3898 	struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT;
3899 	isc_netaddr_t addr;
3900 
3901 	isc_netaddr_fromin6(&addr, &in6);
3902 
3903 	result = dns_acl_create(named_g_mctx, 1, &acl);
3904 	if (result != ISC_R_SUCCESS) {
3905 		return (result);
3906 	}
3907 
3908 	result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
3909 	if (result == ISC_R_SUCCESS) {
3910 		dns_acl_attach(acl, &named_g_mapped);
3911 	}
3912 	dns_acl_detach(&acl);
3913 	return (result);
3914 }
3915 
3916 /*%
3917  * A callback for the cfg_pluginlist_foreach() call in configure_view() below.
3918  * If registering any plugin fails, registering subsequent ones is not
3919  * attempted.
3920  */
3921 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)3922 register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
3923 		    const char *plugin_path, const char *parameters,
3924 		    void *callback_data) {
3925 	dns_view_t *view = callback_data;
3926 	char full_path[PATH_MAX];
3927 	isc_result_t result;
3928 
3929 	result = ns_plugin_expandpath(plugin_path, full_path,
3930 				      sizeof(full_path));
3931 	if (result != ISC_R_SUCCESS) {
3932 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3933 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3934 			      "%s: plugin configuration failed: "
3935 			      "unable to get full plugin path: %s",
3936 			      plugin_path, isc_result_totext(result));
3937 		return (result);
3938 	}
3939 
3940 	result = ns_plugin_register(full_path, parameters, config,
3941 				    cfg_obj_file(obj), cfg_obj_line(obj),
3942 				    named_g_mctx, named_g_lctx,
3943 				    named_g_aclconfctx, view);
3944 	if (result != ISC_R_SUCCESS) {
3945 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3946 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3947 			      "%s: plugin configuration failed: %s", full_path,
3948 			      isc_result_totext(result));
3949 	}
3950 
3951 	return (result);
3952 }
3953 
3954 /*
3955  * Determine if a minimal-sized cache can be used for a given view, according
3956  * to 'maps' (implicit defaults, global options, view options) and 'optionmaps'
3957  * (global options, view options).  This is only allowed for views which have
3958  * recursion disabled and do not have "max-cache-size" set explicitly.  Using
3959  * minimal-sized caches prevents a situation in which all explicitly configured
3960  * and built-in views inherit the default "max-cache-size 90%;" setting, which
3961  * could lead to memory exhaustion with multiple views configured.
3962  */
3963 static bool
minimal_cache_allowed(const cfg_obj_t * maps[4],const cfg_obj_t * optionmaps[3])3964 minimal_cache_allowed(const cfg_obj_t *maps[4],
3965 		      const cfg_obj_t *optionmaps[3]) {
3966 	const cfg_obj_t *obj;
3967 
3968 	/*
3969 	 * Do not use a minimal-sized cache for a view with recursion enabled.
3970 	 */
3971 	obj = NULL;
3972 	(void)named_config_get(maps, "recursion", &obj);
3973 	INSIST(obj != NULL);
3974 	if (cfg_obj_asboolean(obj)) {
3975 		return (false);
3976 	}
3977 
3978 	/*
3979 	 * Do not use a minimal-sized cache if a specific size was requested.
3980 	 */
3981 	obj = NULL;
3982 	(void)named_config_get(optionmaps, "max-cache-size", &obj);
3983 	if (obj != NULL) {
3984 		return (false);
3985 	}
3986 
3987 	return (true);
3988 }
3989 
3990 static const char *const response_synonyms[] = { "response", NULL };
3991 
3992 /*
3993  * Configure 'view' according to 'vconfig', taking defaults from
3994  * 'config' where values are missing in 'vconfig'.
3995  *
3996  * When configuring the default view, 'vconfig' will be NULL and the
3997  * global defaults in 'config' used exclusively.
3998  */
3999 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)4000 configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
4001 	       cfg_obj_t *vconfig, named_cachelist_t *cachelist,
4002 	       dns_kasplist_t *kasplist, const cfg_obj_t *bindkeys,
4003 	       isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints) {
4004 	const cfg_obj_t *maps[4];
4005 	const cfg_obj_t *cfgmaps[3];
4006 	const cfg_obj_t *optionmaps[3];
4007 	const cfg_obj_t *options = NULL;
4008 	const cfg_obj_t *voptions = NULL;
4009 	const cfg_obj_t *forwardtype;
4010 	const cfg_obj_t *forwarders;
4011 	const cfg_obj_t *alternates;
4012 	const cfg_obj_t *zonelist;
4013 	const cfg_obj_t *dlzlist;
4014 	const cfg_obj_t *dlz;
4015 	unsigned int dlzargc;
4016 	char **dlzargv;
4017 	const cfg_obj_t *dyndb_list, *plugin_list;
4018 	const cfg_obj_t *disabled;
4019 	const cfg_obj_t *obj, *obj2;
4020 	const cfg_listelt_t *element;
4021 	in_port_t port;
4022 	dns_cache_t *cache = NULL;
4023 	isc_result_t result;
4024 	size_t max_cache_size;
4025 	uint32_t max_cache_size_percent = 0;
4026 	size_t max_adb_size;
4027 	uint32_t lame_ttl, fail_ttl;
4028 	uint32_t max_stale_ttl = 0;
4029 	uint32_t stale_refresh_time = 0;
4030 	dns_tsig_keyring_t *ring = NULL;
4031 	dns_transport_list_t *transports = NULL;
4032 	dns_view_t *pview = NULL; /* Production view */
4033 	isc_mem_t *cmctx = NULL, *hmctx = NULL;
4034 	dns_dispatch_t *dispatch4 = NULL;
4035 	dns_dispatch_t *dispatch6 = NULL;
4036 	bool shared_cache = false;
4037 	int i = 0, j = 0, k = 0;
4038 	const char *str;
4039 	const char *cachename = NULL;
4040 	dns_order_t *order = NULL;
4041 	uint32_t udpsize;
4042 	uint32_t maxbits;
4043 	unsigned int resopts = 0;
4044 	dns_zone_t *zone = NULL;
4045 	uint32_t max_clients_per_query;
4046 	bool empty_zones_enable;
4047 	const cfg_obj_t *disablelist = NULL;
4048 	isc_stats_t *resstats = NULL;
4049 	dns_stats_t *resquerystats = NULL;
4050 	bool auto_root = false;
4051 	named_cache_t *nsc;
4052 	bool zero_no_soattl;
4053 	dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
4054 	unsigned int query_timeout, ndisp;
4055 	bool old_rpz_ok = false;
4056 	isc_dscp_t dscp4 = -1, dscp6 = -1;
4057 	dns_dyndbctx_t *dctx = NULL;
4058 	unsigned int resolver_param;
4059 	dns_ntatable_t *ntatable = NULL;
4060 	const char *qminmode = NULL;
4061 
4062 	REQUIRE(DNS_VIEW_VALID(view));
4063 
4064 	if (config != NULL) {
4065 		(void)cfg_map_get(config, "options", &options);
4066 	}
4067 
4068 	/*
4069 	 * maps: view options, options, defaults
4070 	 * cfgmaps: view options, config
4071 	 * optionmaps: view options, options
4072 	 */
4073 	if (vconfig != NULL) {
4074 		voptions = cfg_tuple_get(vconfig, "options");
4075 		maps[i++] = voptions;
4076 		optionmaps[j++] = voptions;
4077 		cfgmaps[k++] = voptions;
4078 	}
4079 	if (options != NULL) {
4080 		maps[i++] = options;
4081 		optionmaps[j++] = options;
4082 	}
4083 
4084 	maps[i++] = named_g_defaults;
4085 	maps[i] = NULL;
4086 	optionmaps[j] = NULL;
4087 	if (config != NULL) {
4088 		cfgmaps[k++] = config;
4089 	}
4090 	cfgmaps[k] = NULL;
4091 
4092 	/*
4093 	 * Set the view's port number for outgoing queries.
4094 	 */
4095 	CHECKM(named_config_getport(config, "port", &port), "port");
4096 	dns_view_setdstport(view, port);
4097 
4098 	/*
4099 	 * Make the list of response policy zone names for a view that
4100 	 * is used for real lookups and so cares about hints.
4101 	 */
4102 	obj = NULL;
4103 	if (view->rdclass == dns_rdataclass_in && need_hints &&
4104 	    named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS)
4105 	{
4106 		CHECK(configure_rpz(view, maps, obj, &old_rpz_ok));
4107 	}
4108 
4109 	obj = NULL;
4110 	if (view->rdclass == dns_rdataclass_in && need_hints &&
4111 	    named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
4112 	{
4113 		CHECK(configure_catz(view, config, obj));
4114 	}
4115 
4116 	/*
4117 	 * Configure the zones.
4118 	 */
4119 	zonelist = NULL;
4120 	if (voptions != NULL) {
4121 		(void)cfg_map_get(voptions, "zone", &zonelist);
4122 	} else {
4123 		(void)cfg_map_get(config, "zone", &zonelist);
4124 	}
4125 
4126 	/*
4127 	 * Load zone configuration
4128 	 */
4129 	for (element = cfg_list_first(zonelist); element != NULL;
4130 	     element = cfg_list_next(element))
4131 	{
4132 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
4133 		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
4134 				     viewlist, kasplist, actx, false,
4135 				     old_rpz_ok, false));
4136 	}
4137 
4138 	/*
4139 	 * Check that a master or slave zone was found for each
4140 	 * zone named in the response policy statement
4141 	 * unless we are using RPZ service interface.
4142 	 */
4143 	if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
4144 		dns_rpz_num_t n;
4145 
4146 		for (n = 0; n < view->rpzs->p.num_zones; ++n) {
4147 			if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
4148 				char namebuf[DNS_NAME_FORMATSIZE];
4149 
4150 				dns_name_format(&view->rpzs->zones[n]->origin,
4151 						namebuf, sizeof(namebuf));
4152 				isc_log_write(named_g_lctx,
4153 					      NAMED_LOGCATEGORY_GENERAL,
4154 					      NAMED_LOGMODULE_SERVER,
4155 					      DNS_RPZ_ERROR_LEVEL,
4156 					      "rpz '%s'"
4157 					      " is not a master or slave zone",
4158 					      namebuf);
4159 				result = ISC_R_NOTFOUND;
4160 				goto cleanup;
4161 			}
4162 		}
4163 	}
4164 
4165 	/*
4166 	 * If we're allowing added zones, then load zone configuration
4167 	 * from the newzone file for zones that were added during previous
4168 	 * runs.
4169 	 */
4170 	CHECK(configure_newzones(view, config, vconfig, mctx, actx));
4171 
4172 	/*
4173 	 * Create Dynamically Loadable Zone driver.
4174 	 */
4175 	dlzlist = NULL;
4176 	if (voptions != NULL) {
4177 		(void)cfg_map_get(voptions, "dlz", &dlzlist);
4178 	} else {
4179 		(void)cfg_map_get(config, "dlz", &dlzlist);
4180 	}
4181 
4182 	for (element = cfg_list_first(dlzlist); element != NULL;
4183 	     element = cfg_list_next(element))
4184 	{
4185 		dlz = cfg_listelt_value(element);
4186 
4187 		obj = NULL;
4188 		(void)cfg_map_get(dlz, "database", &obj);
4189 		if (obj != NULL) {
4190 			dns_dlzdb_t *dlzdb = NULL;
4191 			const cfg_obj_t *name, *search = NULL;
4192 			char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
4193 
4194 			if (s == NULL) {
4195 				result = ISC_R_NOMEMORY;
4196 				goto cleanup;
4197 			}
4198 
4199 			result = isc_commandline_strtoargv(mctx, s, &dlzargc,
4200 							   &dlzargv, 0);
4201 			if (result != ISC_R_SUCCESS) {
4202 				isc_mem_free(mctx, s);
4203 				goto cleanup;
4204 			}
4205 
4206 			name = cfg_map_getname(dlz);
4207 			result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
4208 					       dlzargv[0], dlzargc, dlzargv,
4209 					       &dlzdb);
4210 			isc_mem_free(mctx, s);
4211 			isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
4212 			if (result != ISC_R_SUCCESS) {
4213 				goto cleanup;
4214 			}
4215 
4216 			/*
4217 			 * If the DLZ backend supports configuration,
4218 			 * and is searchable, then call its configure
4219 			 * method now.  If not searchable, we'll take
4220 			 * care of it when we process the zone statement.
4221 			 */
4222 			(void)cfg_map_get(dlz, "search", &search);
4223 			if (search == NULL || cfg_obj_asboolean(search)) {
4224 				dlzdb->search = true;
4225 				result = dns_dlzconfigure(
4226 					view, dlzdb, dlzconfigure_callback);
4227 				if (result != ISC_R_SUCCESS) {
4228 					goto cleanup;
4229 				}
4230 				ISC_LIST_APPEND(view->dlz_searched, dlzdb,
4231 						link);
4232 			} else {
4233 				dlzdb->search = false;
4234 				ISC_LIST_APPEND(view->dlz_unsearched, dlzdb,
4235 						link);
4236 			}
4237 		}
4238 	}
4239 
4240 	/*
4241 	 * Obtain configuration parameters that affect the decision of whether
4242 	 * we can reuse/share an existing cache.
4243 	 */
4244 	obj = NULL;
4245 	result = named_config_get(maps, "max-cache-size", &obj);
4246 	INSIST(result == ISC_R_SUCCESS);
4247 	/*
4248 	 * If "-T maxcachesize=..." is in effect, it overrides any other
4249 	 * "max-cache-size" setting found in configuration, either implicit or
4250 	 * explicit.  For simplicity, the value passed to that command line
4251 	 * option is always treated as the number of bytes to set
4252 	 * "max-cache-size" to.
4253 	 */
4254 	if (named_g_maxcachesize != 0) {
4255 		max_cache_size = named_g_maxcachesize;
4256 	} else if (minimal_cache_allowed(maps, optionmaps)) {
4257 		/*
4258 		 * dns_cache_setcachesize() will adjust this to the smallest
4259 		 * allowed value.
4260 		 */
4261 		max_cache_size = 1;
4262 	} else if (cfg_obj_isstring(obj)) {
4263 		str = cfg_obj_asstring(obj);
4264 		INSIST(strcasecmp(str, "unlimited") == 0);
4265 		max_cache_size = 0;
4266 	} else if (cfg_obj_ispercentage(obj)) {
4267 		max_cache_size = SIZE_AS_PERCENT;
4268 		max_cache_size_percent = cfg_obj_aspercentage(obj);
4269 	} else {
4270 		isc_resourcevalue_t value;
4271 		value = cfg_obj_asuint64(obj);
4272 		if (value > SIZE_MAX) {
4273 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4274 				    "'max-cache-size "
4275 				    "%" PRIu64 "' "
4276 				    "is too large for this "
4277 				    "system; reducing to %lu",
4278 				    value, (unsigned long)SIZE_MAX);
4279 			value = SIZE_MAX;
4280 		}
4281 		max_cache_size = (size_t)value;
4282 	}
4283 
4284 	if (max_cache_size == SIZE_AS_PERCENT) {
4285 		uint64_t totalphys = isc_meminfo_totalphys();
4286 
4287 		max_cache_size =
4288 			(size_t)(totalphys * max_cache_size_percent / 100);
4289 		if (totalphys == 0) {
4290 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4291 				    "Unable to determine amount of physical "
4292 				    "memory, setting 'max-cache-size' to "
4293 				    "unlimited");
4294 		} else {
4295 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
4296 				    "'max-cache-size %d%%' "
4297 				    "- setting to %" PRIu64 "MB "
4298 				    "(out of %" PRIu64 "MB)",
4299 				    max_cache_size_percent,
4300 				    (uint64_t)(max_cache_size / (1024 * 1024)),
4301 				    totalphys / (1024 * 1024));
4302 		}
4303 	}
4304 
4305 	/* Check-names. */
4306 	obj = NULL;
4307 	result = named_checknames_get(maps, response_synonyms, &obj);
4308 	INSIST(result == ISC_R_SUCCESS);
4309 
4310 	str = cfg_obj_asstring(obj);
4311 	if (strcasecmp(str, "fail") == 0) {
4312 		resopts |= DNS_RESOLVER_CHECKNAMES |
4313 			   DNS_RESOLVER_CHECKNAMESFAIL;
4314 		view->checknames = true;
4315 	} else if (strcasecmp(str, "warn") == 0) {
4316 		resopts |= DNS_RESOLVER_CHECKNAMES;
4317 		view->checknames = false;
4318 	} else if (strcasecmp(str, "ignore") == 0) {
4319 		view->checknames = false;
4320 	} else {
4321 		INSIST(0);
4322 		ISC_UNREACHABLE();
4323 	}
4324 
4325 	obj = NULL;
4326 	result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj);
4327 	INSIST(result == ISC_R_SUCCESS);
4328 	zero_no_soattl = cfg_obj_asboolean(obj);
4329 
4330 	obj = NULL;
4331 	result = named_config_get(maps, "dns64", &obj);
4332 	if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
4333 	    strcmp(view->name, "_meta"))
4334 	{
4335 		isc_netaddr_t na, suffix, *sp;
4336 		unsigned int prefixlen;
4337 		const char *server, *contact;
4338 		const cfg_obj_t *myobj;
4339 
4340 		myobj = NULL;
4341 		result = named_config_get(maps, "dns64-server", &myobj);
4342 		if (result == ISC_R_SUCCESS) {
4343 			server = cfg_obj_asstring(myobj);
4344 		} else {
4345 			server = NULL;
4346 		}
4347 
4348 		myobj = NULL;
4349 		result = named_config_get(maps, "dns64-contact", &myobj);
4350 		if (result == ISC_R_SUCCESS) {
4351 			contact = cfg_obj_asstring(myobj);
4352 		} else {
4353 			contact = NULL;
4354 		}
4355 
4356 		for (element = cfg_list_first(obj); element != NULL;
4357 		     element = cfg_list_next(element))
4358 		{
4359 			const cfg_obj_t *map = cfg_listelt_value(element);
4360 			dns_dns64_t *dns64 = NULL;
4361 			unsigned int dns64options = 0;
4362 
4363 			cfg_obj_asnetprefix(cfg_map_getname(map), &na,
4364 					    &prefixlen);
4365 
4366 			obj = NULL;
4367 			(void)cfg_map_get(map, "suffix", &obj);
4368 			if (obj != NULL) {
4369 				sp = &suffix;
4370 				isc_netaddr_fromsockaddr(
4371 					sp, cfg_obj_assockaddr(obj));
4372 			} else {
4373 				sp = NULL;
4374 			}
4375 
4376 			clients = mapped = excluded = NULL;
4377 			obj = NULL;
4378 			(void)cfg_map_get(map, "clients", &obj);
4379 			if (obj != NULL) {
4380 				result = cfg_acl_fromconfig(obj, config,
4381 							    named_g_lctx, actx,
4382 							    mctx, 0, &clients);
4383 				if (result != ISC_R_SUCCESS) {
4384 					goto cleanup;
4385 				}
4386 			}
4387 			obj = NULL;
4388 			(void)cfg_map_get(map, "mapped", &obj);
4389 			if (obj != NULL) {
4390 				result = cfg_acl_fromconfig(obj, config,
4391 							    named_g_lctx, actx,
4392 							    mctx, 0, &mapped);
4393 				if (result != ISC_R_SUCCESS) {
4394 					goto cleanup;
4395 				}
4396 			}
4397 			obj = NULL;
4398 			(void)cfg_map_get(map, "exclude", &obj);
4399 			if (obj != NULL) {
4400 				result = cfg_acl_fromconfig(obj, config,
4401 							    named_g_lctx, actx,
4402 							    mctx, 0, &excluded);
4403 				if (result != ISC_R_SUCCESS) {
4404 					goto cleanup;
4405 				}
4406 			} else {
4407 				if (named_g_mapped == NULL) {
4408 					result = create_mapped_acl();
4409 					if (result != ISC_R_SUCCESS) {
4410 						goto cleanup;
4411 					}
4412 				}
4413 				dns_acl_attach(named_g_mapped, &excluded);
4414 			}
4415 
4416 			obj = NULL;
4417 			(void)cfg_map_get(map, "recursive-only", &obj);
4418 			if (obj != NULL && cfg_obj_asboolean(obj)) {
4419 				dns64options |= DNS_DNS64_RECURSIVE_ONLY;
4420 			}
4421 
4422 			obj = NULL;
4423 			(void)cfg_map_get(map, "break-dnssec", &obj);
4424 			if (obj != NULL && cfg_obj_asboolean(obj)) {
4425 				dns64options |= DNS_DNS64_BREAK_DNSSEC;
4426 			}
4427 
4428 			result = dns_dns64_create(mctx, &na, prefixlen, sp,
4429 						  clients, mapped, excluded,
4430 						  dns64options, &dns64);
4431 			if (result != ISC_R_SUCCESS) {
4432 				goto cleanup;
4433 			}
4434 			dns_dns64_append(&view->dns64, dns64);
4435 			view->dns64cnt++;
4436 			result = dns64_reverse(view, mctx, &na, prefixlen,
4437 					       server, contact);
4438 			if (result != ISC_R_SUCCESS) {
4439 				goto cleanup;
4440 			}
4441 			if (clients != NULL) {
4442 				dns_acl_detach(&clients);
4443 			}
4444 			if (mapped != NULL) {
4445 				dns_acl_detach(&mapped);
4446 			}
4447 			if (excluded != NULL) {
4448 				dns_acl_detach(&excluded);
4449 			}
4450 		}
4451 	}
4452 
4453 	obj = NULL;
4454 	result = named_config_get(maps, "dnssec-accept-expired", &obj);
4455 	INSIST(result == ISC_R_SUCCESS);
4456 	view->acceptexpired = cfg_obj_asboolean(obj);
4457 
4458 	obj = NULL;
4459 	/* 'optionmaps', not 'maps': don't check named_g_defaults yet */
4460 	(void)named_config_get(optionmaps, "dnssec-validation", &obj);
4461 	if (obj == NULL) {
4462 		/*
4463 		 * Default to VALIDATION_DEFAULT as set in config.c.
4464 		 */
4465 		(void)cfg_map_get(named_g_defaults, "dnssec-validation", &obj);
4466 		INSIST(obj != NULL);
4467 	}
4468 	if (obj != NULL) {
4469 		if (cfg_obj_isboolean(obj)) {
4470 			view->enablevalidation = cfg_obj_asboolean(obj);
4471 		} else {
4472 			/*
4473 			 * If dnssec-validation is set but not boolean,
4474 			 * then it must be "auto"
4475 			 */
4476 			view->enablevalidation = true;
4477 			auto_root = true;
4478 		}
4479 	}
4480 
4481 	obj = NULL;
4482 	result = named_config_get(maps, "max-cache-ttl", &obj);
4483 	INSIST(result == ISC_R_SUCCESS);
4484 	view->maxcachettl = cfg_obj_asduration(obj);
4485 
4486 	obj = NULL;
4487 	result = named_config_get(maps, "max-ncache-ttl", &obj);
4488 	INSIST(result == ISC_R_SUCCESS);
4489 	view->maxncachettl = cfg_obj_asduration(obj);
4490 
4491 	obj = NULL;
4492 	result = named_config_get(maps, "min-cache-ttl", &obj);
4493 	INSIST(result == ISC_R_SUCCESS);
4494 	view->mincachettl = cfg_obj_asduration(obj);
4495 
4496 	obj = NULL;
4497 	result = named_config_get(maps, "min-ncache-ttl", &obj);
4498 	INSIST(result == ISC_R_SUCCESS);
4499 	view->minncachettl = cfg_obj_asduration(obj);
4500 
4501 	obj = NULL;
4502 	result = named_config_get(maps, "synth-from-dnssec", &obj);
4503 	INSIST(result == ISC_R_SUCCESS);
4504 	view->synthfromdnssec = cfg_obj_asboolean(obj);
4505 
4506 	obj = NULL;
4507 	result = named_config_get(maps, "stale-cache-enable", &obj);
4508 	INSIST(result == ISC_R_SUCCESS);
4509 	if (cfg_obj_asboolean(obj)) {
4510 		obj = NULL;
4511 		result = named_config_get(maps, "max-stale-ttl", &obj);
4512 		INSIST(result == ISC_R_SUCCESS);
4513 		max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4514 	}
4515 	/*
4516 	 * If 'stale-cache-enable' is false, max_stale_ttl is set to 0,
4517 	 * meaning keeping stale RRsets in cache is disabled.
4518 	 */
4519 
4520 	obj = NULL;
4521 	result = named_config_get(maps, "stale-answer-enable", &obj);
4522 	INSIST(result == ISC_R_SUCCESS);
4523 	view->staleanswersenable = cfg_obj_asboolean(obj);
4524 
4525 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
4526 				   view->rdclass, &pview);
4527 	if (result == ISC_R_SUCCESS) {
4528 		view->staleanswersok = pview->staleanswersok;
4529 		dns_view_detach(&pview);
4530 	} else {
4531 		view->staleanswersok = dns_stale_answer_conf;
4532 	}
4533 
4534 	obj = NULL;
4535 	result = named_config_get(maps, "stale-answer-client-timeout", &obj);
4536 	INSIST(result == ISC_R_SUCCESS);
4537 	if (cfg_obj_isstring(obj)) {
4538 		/*
4539 		 * The only string values available for this option
4540 		 * are "disabled" and "off".
4541 		 * We use (uint32_t) -1 to represent disabled since
4542 		 * a value of zero means that stale data can be used
4543 		 * to promptly answer the query, while an attempt to
4544 		 * refresh the RRset will still be made in background.
4545 		 */
4546 		view->staleanswerclienttimeout = (uint32_t)-1;
4547 	} else {
4548 		view->staleanswerclienttimeout = cfg_obj_asuint32(obj);
4549 	}
4550 
4551 	obj = NULL;
4552 	result = named_config_get(maps, "stale-refresh-time", &obj);
4553 	INSIST(result == ISC_R_SUCCESS);
4554 	stale_refresh_time = cfg_obj_asduration(obj);
4555 
4556 	/*
4557 	 * Configure the view's cache.
4558 	 *
4559 	 * First, check to see if there are any attach-cache options.  If yes,
4560 	 * attempt to lookup an existing cache at attach it to the view.  If
4561 	 * there is not one, then try to reuse an existing cache if possible;
4562 	 * otherwise create a new cache.
4563 	 *
4564 	 * Note that the ADB is not preserved or shared in either case.
4565 	 *
4566 	 * When a matching view is found, the associated statistics are also
4567 	 * retrieved and reused.
4568 	 *
4569 	 * XXX Determining when it is safe to reuse or share a cache is tricky.
4570 	 * When the view's configuration changes, the cached data may become
4571 	 * invalid because it reflects our old view of the world.  We check
4572 	 * some of the configuration parameters that could invalidate the cache
4573 	 * or otherwise make it unshareable, but there are other configuration
4574 	 * options that should be checked.  For example, if a view uses a
4575 	 * forwarder, changes in the forwarder configuration may invalidate
4576 	 * the cache.  At the moment, it's the administrator's responsibility to
4577 	 * ensure these configuration options don't invalidate reusing/sharing.
4578 	 */
4579 	obj = NULL;
4580 	result = named_config_get(maps, "attach-cache", &obj);
4581 	if (result == ISC_R_SUCCESS) {
4582 		cachename = cfg_obj_asstring(obj);
4583 	} else {
4584 		cachename = view->name;
4585 	}
4586 	cache = NULL;
4587 	nsc = cachelist_find(cachelist, cachename, view->rdclass);
4588 	if (nsc != NULL) {
4589 		if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
4590 				    max_cache_size, max_stale_ttl,
4591 				    stale_refresh_time))
4592 		{
4593 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4594 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4595 				      "views %s and %s can't share the cache "
4596 				      "due to configuration parameter mismatch",
4597 				      nsc->primaryview->name, view->name);
4598 			result = ISC_R_FAILURE;
4599 			goto cleanup;
4600 		}
4601 		dns_cache_attach(nsc->cache, &cache);
4602 		shared_cache = true;
4603 	} else {
4604 		if (strcmp(cachename, view->name) == 0) {
4605 			result = dns_viewlist_find(&named_g_server->viewlist,
4606 						   cachename, view->rdclass,
4607 						   &pview);
4608 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4609 			{
4610 				goto cleanup;
4611 			}
4612 			if (pview != NULL) {
4613 				if (!cache_reusable(pview, view,
4614 						    zero_no_soattl)) {
4615 					isc_log_write(named_g_lctx,
4616 						      NAMED_LOGCATEGORY_GENERAL,
4617 						      NAMED_LOGMODULE_SERVER,
4618 						      ISC_LOG_DEBUG(1),
4619 						      "cache cannot be reused "
4620 						      "for view %s due to "
4621 						      "configuration parameter "
4622 						      "mismatch",
4623 						      view->name);
4624 				} else {
4625 					INSIST(pview->cache != NULL);
4626 					isc_log_write(named_g_lctx,
4627 						      NAMED_LOGCATEGORY_GENERAL,
4628 						      NAMED_LOGMODULE_SERVER,
4629 						      ISC_LOG_DEBUG(3),
4630 						      "reusing existing cache");
4631 					dns_cache_attach(pview->cache, &cache);
4632 				}
4633 				dns_view_getresstats(pview, &resstats);
4634 				dns_view_getresquerystats(pview,
4635 							  &resquerystats);
4636 				dns_view_detach(&pview);
4637 			}
4638 		}
4639 		if (cache == NULL) {
4640 			/*
4641 			 * Create a cache with the desired name.  This normally
4642 			 * equals the view name, but may also be a forward
4643 			 * reference to a view that share the cache with this
4644 			 * view but is not yet configured.  If it is not the
4645 			 * view name but not a forward reference either, then it
4646 			 * is simply a named cache that is not shared.
4647 			 *
4648 			 * We use two separate memory contexts for the
4649 			 * cache, for the main cache memory and the heap
4650 			 * memory.
4651 			 */
4652 			isc_mem_create(&cmctx);
4653 			isc_mem_setname(cmctx, "cache");
4654 			isc_mem_create(&hmctx);
4655 			isc_mem_setname(hmctx, "cache_heap");
4656 			CHECK(dns_cache_create(cmctx, hmctx, named_g_taskmgr,
4657 					       named_g_timermgr, view->rdclass,
4658 					       cachename, "rbt", 0, NULL,
4659 					       &cache));
4660 			isc_mem_detach(&cmctx);
4661 			isc_mem_detach(&hmctx);
4662 		}
4663 		nsc = isc_mem_get(mctx, sizeof(*nsc));
4664 		nsc->cache = NULL;
4665 		dns_cache_attach(cache, &nsc->cache);
4666 		nsc->primaryview = view;
4667 		nsc->needflush = false;
4668 		nsc->adbsizeadjusted = false;
4669 		nsc->rdclass = view->rdclass;
4670 		ISC_LINK_INIT(nsc, link);
4671 		ISC_LIST_APPEND(*cachelist, nsc, link);
4672 	}
4673 	dns_view_setcache(view, cache, shared_cache);
4674 
4675 	dns_cache_setcachesize(cache, max_cache_size);
4676 	dns_cache_setservestalettl(cache, max_stale_ttl);
4677 	dns_cache_setservestalerefresh(cache, stale_refresh_time);
4678 
4679 	dns_cache_detach(&cache);
4680 
4681 	obj = NULL;
4682 	result = named_config_get(maps, "stale-answer-ttl", &obj);
4683 	INSIST(result == ISC_R_SUCCESS);
4684 	view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4685 
4686 	/*
4687 	 * Resolver.
4688 	 */
4689 	CHECK(get_view_querysource_dispatch(
4690 		maps, AF_INET, &dispatch4, &dscp4,
4691 		(ISC_LIST_PREV(view, link) == NULL)));
4692 	CHECK(get_view_querysource_dispatch(
4693 		maps, AF_INET6, &dispatch6, &dscp6,
4694 		(ISC_LIST_PREV(view, link) == NULL)));
4695 	if (dispatch4 == NULL && dispatch6 == NULL) {
4696 		UNEXPECTED_ERROR(__FILE__, __LINE__,
4697 				 "unable to obtain either an IPv4 or"
4698 				 " an IPv6 dispatch");
4699 		result = ISC_R_UNEXPECTED;
4700 		goto cleanup;
4701 	}
4702 
4703 	if (resstats == NULL) {
4704 		CHECK(isc_stats_create(mctx, &resstats,
4705 				       dns_resstatscounter_max));
4706 	}
4707 	dns_view_setresstats(view, resstats);
4708 	if (resquerystats == NULL) {
4709 		CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
4710 	}
4711 	dns_view_setresquerystats(view, resquerystats);
4712 
4713 	ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH);
4714 	CHECK(dns_view_createresolver(
4715 		view, named_g_taskmgr, RESOLVER_NTASKS_PERCPU * named_g_cpus,
4716 		ndisp, named_g_netmgr, named_g_timermgr, resopts,
4717 		named_g_dispatchmgr, dispatch4, dispatch6));
4718 
4719 	if (dscp4 == -1) {
4720 		dscp4 = named_g_dscp;
4721 	}
4722 	if (dscp6 == -1) {
4723 		dscp6 = named_g_dscp;
4724 	}
4725 	if (dscp4 != -1) {
4726 		dns_resolver_setquerydscp4(view->resolver, dscp4);
4727 	}
4728 	if (dscp6 != -1) {
4729 		dns_resolver_setquerydscp6(view->resolver, dscp6);
4730 	}
4731 
4732 	/*
4733 	 * Set the ADB cache size to 1/8th of the max-cache-size or
4734 	 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
4735 	 */
4736 	max_adb_size = 0;
4737 	if (max_cache_size != 0U) {
4738 		max_adb_size = max_cache_size / 8;
4739 		if (max_adb_size == 0U) {
4740 			max_adb_size = 1; /* Force minimum. */
4741 		}
4742 		if (view != nsc->primaryview &&
4743 		    max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) {
4744 			max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
4745 			if (!nsc->adbsizeadjusted) {
4746 				dns_adb_setadbsize(nsc->primaryview->adb,
4747 						   MAX_ADB_SIZE_FOR_CACHESHARE);
4748 				nsc->adbsizeadjusted = true;
4749 			}
4750 		}
4751 	}
4752 	dns_adb_setadbsize(view->adb, max_adb_size);
4753 
4754 	/*
4755 	 * Set up ADB quotas
4756 	 */
4757 	{
4758 		uint32_t fps, freq;
4759 		double low, high, discount;
4760 
4761 		obj = NULL;
4762 		result = named_config_get(maps, "fetches-per-server", &obj);
4763 		INSIST(result == ISC_R_SUCCESS);
4764 		obj2 = cfg_tuple_get(obj, "fetches");
4765 		fps = cfg_obj_asuint32(obj2);
4766 		obj2 = cfg_tuple_get(obj, "response");
4767 		if (!cfg_obj_isvoid(obj2)) {
4768 			const char *resp = cfg_obj_asstring(obj2);
4769 			isc_result_t r = DNS_R_SERVFAIL;
4770 
4771 			if (strcasecmp(resp, "drop") == 0) {
4772 				r = DNS_R_DROP;
4773 			} else if (strcasecmp(resp, "fail") == 0) {
4774 				r = DNS_R_SERVFAIL;
4775 			} else {
4776 				INSIST(0);
4777 				ISC_UNREACHABLE();
4778 			}
4779 
4780 			dns_resolver_setquotaresponse(view->resolver,
4781 						      dns_quotatype_server, r);
4782 		}
4783 
4784 		obj = NULL;
4785 		result = named_config_get(maps, "fetch-quota-params", &obj);
4786 		INSIST(result == ISC_R_SUCCESS);
4787 
4788 		obj2 = cfg_tuple_get(obj, "frequency");
4789 		freq = cfg_obj_asuint32(obj2);
4790 
4791 		obj2 = cfg_tuple_get(obj, "low");
4792 		low = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4793 
4794 		obj2 = cfg_tuple_get(obj, "high");
4795 		high = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4796 
4797 		obj2 = cfg_tuple_get(obj, "discount");
4798 		discount = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4799 
4800 		dns_adb_setquota(view->adb, fps, freq, low, high, discount);
4801 	}
4802 
4803 	/*
4804 	 * Set resolver's lame-ttl.
4805 	 */
4806 	obj = NULL;
4807 	result = named_config_get(maps, "lame-ttl", &obj);
4808 	INSIST(result == ISC_R_SUCCESS);
4809 	lame_ttl = cfg_obj_asduration(obj);
4810 	if (lame_ttl > 1800) {
4811 		lame_ttl = 1800;
4812 	}
4813 	dns_resolver_setlamettl(view->resolver, lame_ttl);
4814 
4815 	/*
4816 	 * Set the resolver's query timeout.
4817 	 */
4818 	obj = NULL;
4819 	result = named_config_get(maps, "resolver-query-timeout", &obj);
4820 	INSIST(result == ISC_R_SUCCESS);
4821 	query_timeout = cfg_obj_asuint32(obj);
4822 	dns_resolver_settimeout(view->resolver, query_timeout);
4823 
4824 	/*
4825 	 * Adjust stale-answer-client-timeout upper bound
4826 	 * to be resolver-query-timeout - 1s.
4827 	 * This assignment is safe as dns_resolver_settimeout()
4828 	 * ensures that resolver->querytimeout value will be in the
4829 	 * [MINIMUM_QUERY_TIMEOUT, MAXIMUM_QUERY_TIMEOUT] range and
4830 	 * MINIMUM_QUERY_TIMEOUT is > 1000 (in ms).
4831 	 */
4832 	if (view->staleanswerclienttimeout != (uint32_t)-1 &&
4833 	    view->staleanswerclienttimeout >
4834 		    (dns_resolver_gettimeout(view->resolver) - 1000))
4835 	{
4836 		view->staleanswerclienttimeout =
4837 			dns_resolver_gettimeout(view->resolver) - 1000;
4838 		isc_log_write(
4839 			named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4840 			NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
4841 			"stale-answer-client-timeout adjusted to %" PRIu32,
4842 			view->staleanswerclienttimeout);
4843 	}
4844 
4845 	/* Specify whether to use 0-TTL for negative response for SOA query */
4846 	dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
4847 
4848 	/*
4849 	 * Set the resolver's EDNS UDP size.
4850 	 */
4851 	obj = NULL;
4852 	result = named_config_get(maps, "edns-udp-size", &obj);
4853 	INSIST(result == ISC_R_SUCCESS);
4854 	udpsize = cfg_obj_asuint32(obj);
4855 	if (udpsize < 512) {
4856 		udpsize = 512;
4857 	}
4858 	if (udpsize > 4096) {
4859 		udpsize = 4096;
4860 	}
4861 	dns_resolver_setudpsize(view->resolver, (uint16_t)udpsize);
4862 
4863 	/*
4864 	 * Set the maximum UDP response size.
4865 	 */
4866 	obj = NULL;
4867 	result = named_config_get(maps, "max-udp-size", &obj);
4868 	INSIST(result == ISC_R_SUCCESS);
4869 	udpsize = cfg_obj_asuint32(obj);
4870 	if (udpsize < 512) {
4871 		udpsize = 512;
4872 	}
4873 	if (udpsize > 4096) {
4874 		udpsize = 4096;
4875 	}
4876 	view->maxudp = udpsize;
4877 
4878 	/*
4879 	 * Set the maximum UDP when a COOKIE is not provided.
4880 	 */
4881 	obj = NULL;
4882 	result = named_config_get(maps, "nocookie-udp-size", &obj);
4883 	INSIST(result == ISC_R_SUCCESS);
4884 	udpsize = cfg_obj_asuint32(obj);
4885 	if (udpsize < 128) {
4886 		udpsize = 128;
4887 	}
4888 	if (udpsize > view->maxudp) {
4889 		udpsize = view->maxudp;
4890 	}
4891 	view->nocookieudp = udpsize;
4892 
4893 	/*
4894 	 * Set the maximum rsa exponent bits.
4895 	 */
4896 	obj = NULL;
4897 	result = named_config_get(maps, "max-rsa-exponent-size", &obj);
4898 	INSIST(result == ISC_R_SUCCESS);
4899 	maxbits = cfg_obj_asuint32(obj);
4900 	if (maxbits != 0 && maxbits < 35) {
4901 		maxbits = 35;
4902 	}
4903 	if (maxbits > 4096) {
4904 		maxbits = 4096;
4905 	}
4906 	view->maxbits = maxbits;
4907 
4908 	/*
4909 	 * Set resolver retry parameters.
4910 	 */
4911 	obj = NULL;
4912 	CHECK(named_config_get(maps, "resolver-retry-interval", &obj));
4913 	resolver_param = cfg_obj_asuint32(obj);
4914 	if (resolver_param > 0) {
4915 		dns_resolver_setretryinterval(view->resolver, resolver_param);
4916 	}
4917 
4918 	obj = NULL;
4919 	CHECK(named_config_get(maps, "resolver-nonbackoff-tries", &obj));
4920 	resolver_param = cfg_obj_asuint32(obj);
4921 	if (resolver_param > 0) {
4922 		dns_resolver_setnonbackofftries(view->resolver, resolver_param);
4923 	}
4924 
4925 	/*
4926 	 * Set supported DNSSEC algorithms.
4927 	 */
4928 	dns_resolver_reset_algorithms(view->resolver);
4929 	disabled = NULL;
4930 	(void)named_config_get(maps, "disable-algorithms", &disabled);
4931 	if (disabled != NULL) {
4932 		for (element = cfg_list_first(disabled); element != NULL;
4933 		     element = cfg_list_next(element))
4934 		{
4935 			CHECK(disable_algorithms(cfg_listelt_value(element),
4936 						 view->resolver));
4937 		}
4938 	}
4939 
4940 	/*
4941 	 * Set supported DS digest types.
4942 	 */
4943 	dns_resolver_reset_ds_digests(view->resolver);
4944 	disabled = NULL;
4945 	(void)named_config_get(maps, "disable-ds-digests", &disabled);
4946 	if (disabled != NULL) {
4947 		for (element = cfg_list_first(disabled); element != NULL;
4948 		     element = cfg_list_next(element))
4949 		{
4950 			CHECK(disable_ds_digests(cfg_listelt_value(element),
4951 						 view->resolver));
4952 		}
4953 	}
4954 
4955 	/*
4956 	 * A global or view "forwarders" option, if present,
4957 	 * creates an entry for "." in the forwarding table.
4958 	 */
4959 	forwardtype = NULL;
4960 	forwarders = NULL;
4961 	(void)named_config_get(maps, "forward", &forwardtype);
4962 	(void)named_config_get(maps, "forwarders", &forwarders);
4963 	if (forwarders != NULL) {
4964 		CHECK(configure_forward(config, view, dns_rootname, forwarders,
4965 					forwardtype));
4966 	}
4967 
4968 	/*
4969 	 * Dual Stack Servers.
4970 	 */
4971 	alternates = NULL;
4972 	(void)named_config_get(maps, "dual-stack-servers", &alternates);
4973 	if (alternates != NULL) {
4974 		CHECK(configure_alternates(config, view, alternates));
4975 	}
4976 
4977 	/*
4978 	 * We have default hints for class IN if we need them.
4979 	 */
4980 	if (view->rdclass == dns_rdataclass_in && view->hints == NULL) {
4981 		dns_view_sethints(view, named_g_server->in_roothints);
4982 	}
4983 
4984 	/*
4985 	 * If we still have no hints, this is a non-IN view with no
4986 	 * "hints zone" configured.  Issue a warning, except if this
4987 	 * is a root server.  Root servers never need to consult
4988 	 * their hints, so it's no point requiring users to configure
4989 	 * them.
4990 	 */
4991 	if (view->hints == NULL) {
4992 		dns_zone_t *rootzone = NULL;
4993 		(void)dns_view_findzone(view, dns_rootname, &rootzone);
4994 		if (rootzone != NULL) {
4995 			dns_zone_detach(&rootzone);
4996 			need_hints = false;
4997 		}
4998 		if (need_hints) {
4999 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
5000 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
5001 				      "no root hints for view '%s'",
5002 				      view->name);
5003 		}
5004 	}
5005 
5006 	/*
5007 	 * Configure the view's transports (DoT/DoH)
5008 	 */
5009 	CHECK(named_transports_fromconfig(config, vconfig, view->mctx,
5010 					  &transports));
5011 	dns_view_settransports(view, transports);
5012 	dns_transport_list_detach(&transports);
5013 
5014 	/*
5015 	 * Configure the view's TSIG keys.
5016 	 */
5017 	CHECK(named_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
5018 	if (named_g_server->sessionkey != NULL) {
5019 		CHECK(dns_tsigkeyring_add(ring, named_g_server->session_keyname,
5020 					  named_g_server->sessionkey));
5021 	}
5022 	dns_view_setkeyring(view, ring);
5023 	dns_tsigkeyring_detach(&ring);
5024 
5025 	/*
5026 	 * See if we can re-use a dynamic key ring.
5027 	 */
5028 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
5029 				   view->rdclass, &pview);
5030 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
5031 		goto cleanup;
5032 	}
5033 	if (pview != NULL) {
5034 		dns_view_getdynamickeyring(pview, &ring);
5035 		if (ring != NULL) {
5036 			dns_view_setdynamickeyring(view, ring);
5037 		}
5038 		dns_tsigkeyring_detach(&ring);
5039 		dns_view_detach(&pview);
5040 	} else {
5041 		dns_view_restorekeyring(view);
5042 	}
5043 
5044 	/*
5045 	 * Configure the view's peer list.
5046 	 */
5047 	{
5048 		const cfg_obj_t *peers = NULL;
5049 		dns_peerlist_t *newpeers = NULL;
5050 
5051 		(void)named_config_get(cfgmaps, "server", &peers);
5052 		CHECK(dns_peerlist_new(mctx, &newpeers));
5053 		for (element = cfg_list_first(peers); element != NULL;
5054 		     element = cfg_list_next(element))
5055 		{
5056 			const cfg_obj_t *cpeer = cfg_listelt_value(element);
5057 			dns_peer_t *peer;
5058 
5059 			CHECK(configure_peer(cpeer, mctx, &peer));
5060 			dns_peerlist_addpeer(newpeers, peer);
5061 			dns_peer_detach(&peer);
5062 		}
5063 		dns_peerlist_detach(&view->peers);
5064 		view->peers = newpeers; /* Transfer ownership. */
5065 	}
5066 
5067 	/*
5068 	 *	Configure the views rrset-order.
5069 	 */
5070 	{
5071 		const cfg_obj_t *rrsetorder = NULL;
5072 
5073 		(void)named_config_get(maps, "rrset-order", &rrsetorder);
5074 		CHECK(dns_order_create(mctx, &order));
5075 		for (element = cfg_list_first(rrsetorder); element != NULL;
5076 		     element = cfg_list_next(element))
5077 		{
5078 			const cfg_obj_t *ent = cfg_listelt_value(element);
5079 
5080 			CHECK(configure_order(order, ent));
5081 		}
5082 		if (view->order != NULL) {
5083 			dns_order_detach(&view->order);
5084 		}
5085 		dns_order_attach(order, &view->order);
5086 		dns_order_detach(&order);
5087 	}
5088 	/*
5089 	 * Copy the aclenv object.
5090 	 */
5091 	dns_aclenv_copy(view->aclenv, ns_interfacemgr_getaclenv(
5092 					      named_g_server->interfacemgr));
5093 
5094 	/*
5095 	 * Configure the "match-clients" and "match-destinations" ACL.
5096 	 * (These are only meaningful at the view level, but 'config'
5097 	 * must be passed so that named ACLs defined at the global level
5098 	 * can be retrieved.)
5099 	 */
5100 	CHECK(configure_view_acl(vconfig, config, NULL, "match-clients", NULL,
5101 				 actx, named_g_mctx, &view->matchclients));
5102 	CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations",
5103 				 NULL, actx, named_g_mctx,
5104 				 &view->matchdestinations));
5105 
5106 	/*
5107 	 * Configure the "match-recursive-only" option.
5108 	 */
5109 	obj = NULL;
5110 	(void)named_config_get(maps, "match-recursive-only", &obj);
5111 	if (obj != NULL && cfg_obj_asboolean(obj)) {
5112 		view->matchrecursiveonly = true;
5113 	} else {
5114 		view->matchrecursiveonly = false;
5115 	}
5116 
5117 	/*
5118 	 * Configure other configurable data.
5119 	 */
5120 	obj = NULL;
5121 	result = named_config_get(maps, "recursion", &obj);
5122 	INSIST(result == ISC_R_SUCCESS);
5123 	view->recursion = cfg_obj_asboolean(obj);
5124 
5125 	obj = NULL;
5126 	result = named_config_get(maps, "qname-minimization", &obj);
5127 	INSIST(result == ISC_R_SUCCESS);
5128 	qminmode = cfg_obj_asstring(obj);
5129 	INSIST(qminmode != NULL);
5130 	if (!strcmp(qminmode, "strict")) {
5131 		view->qminimization = true;
5132 		view->qmin_strict = true;
5133 	} else if (!strcmp(qminmode, "relaxed")) {
5134 		view->qminimization = true;
5135 		view->qmin_strict = false;
5136 	} else { /* "disabled" or "off" */
5137 		view->qminimization = false;
5138 		view->qmin_strict = false;
5139 	}
5140 
5141 	obj = NULL;
5142 	result = named_config_get(maps, "auth-nxdomain", &obj);
5143 	INSIST(result == ISC_R_SUCCESS);
5144 	view->auth_nxdomain = cfg_obj_asboolean(obj);
5145 
5146 	/* deprecated */
5147 	obj = NULL;
5148 	result = named_config_get(maps, "glue-cache", &obj);
5149 	INSIST(result == ISC_R_SUCCESS);
5150 	view->use_glue_cache = cfg_obj_asboolean(obj);
5151 
5152 	obj = NULL;
5153 	result = named_config_get(maps, "minimal-any", &obj);
5154 	INSIST(result == ISC_R_SUCCESS);
5155 	view->minimal_any = cfg_obj_asboolean(obj);
5156 
5157 	obj = NULL;
5158 	result = named_config_get(maps, "minimal-responses", &obj);
5159 	INSIST(result == ISC_R_SUCCESS);
5160 	if (cfg_obj_isboolean(obj)) {
5161 		if (cfg_obj_asboolean(obj)) {
5162 			view->minimalresponses = dns_minimal_yes;
5163 		} else {
5164 			view->minimalresponses = dns_minimal_no;
5165 		}
5166 	} else {
5167 		str = cfg_obj_asstring(obj);
5168 		if (strcasecmp(str, "no-auth") == 0) {
5169 			view->minimalresponses = dns_minimal_noauth;
5170 		} else if (strcasecmp(str, "no-auth-recursive") == 0) {
5171 			view->minimalresponses = dns_minimal_noauthrec;
5172 		} else {
5173 			INSIST(0);
5174 			ISC_UNREACHABLE();
5175 		}
5176 	}
5177 
5178 	obj = NULL;
5179 	result = named_config_get(maps, "transfer-format", &obj);
5180 	INSIST(result == ISC_R_SUCCESS);
5181 	str = cfg_obj_asstring(obj);
5182 	if (strcasecmp(str, "many-answers") == 0) {
5183 		view->transfer_format = dns_many_answers;
5184 	} else if (strcasecmp(str, "one-answer") == 0) {
5185 		view->transfer_format = dns_one_answer;
5186 	} else {
5187 		INSIST(0);
5188 		ISC_UNREACHABLE();
5189 	}
5190 
5191 	obj = NULL;
5192 	result = named_config_get(maps, "trust-anchor-telemetry", &obj);
5193 	INSIST(result == ISC_R_SUCCESS);
5194 	view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
5195 
5196 	obj = NULL;
5197 	result = named_config_get(maps, "root-key-sentinel", &obj);
5198 	INSIST(result == ISC_R_SUCCESS);
5199 	view->root_key_sentinel = cfg_obj_asboolean(obj);
5200 
5201 	/*
5202 	 * Set the "allow-query", "allow-query-cache", "allow-recursion",
5203 	 * "allow-recursion-on" and "allow-query-cache-on" ACLs if
5204 	 * configured in named.conf, but NOT from the global defaults.
5205 	 * This is done by leaving the third argument to configure_view_acl()
5206 	 * NULL.
5207 	 *
5208 	 * We ignore the global defaults here because these ACLs
5209 	 * can inherit from each other.  If any are still unset after
5210 	 * applying the inheritance rules, we'll look up the defaults at
5211 	 * that time.
5212 	 */
5213 
5214 	/* named.conf only */
5215 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query", NULL,
5216 				 actx, named_g_mctx, &view->queryacl));
5217 
5218 	/* named.conf only */
5219 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache",
5220 				 NULL, actx, named_g_mctx, &view->cacheacl));
5221 	/* named.conf only */
5222 	CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
5223 				 NULL, actx, named_g_mctx, &view->cacheonacl));
5224 
5225 	if (strcmp(view->name, "_bind") != 0 &&
5226 	    view->rdclass != dns_rdataclass_chaos) {
5227 		/* named.conf only */
5228 		CHECK(configure_view_acl(vconfig, config, NULL,
5229 					 "allow-recursion", NULL, actx,
5230 					 named_g_mctx, &view->recursionacl));
5231 		/* named.conf only */
5232 		CHECK(configure_view_acl(vconfig, config, NULL,
5233 					 "allow-recursion-on", NULL, actx,
5234 					 named_g_mctx, &view->recursiononacl));
5235 	}
5236 
5237 	if (view->recursion) {
5238 		/*
5239 		 * "allow-query-cache" inherits from "allow-recursion" if set,
5240 		 * otherwise from "allow-query" if set.
5241 		 */
5242 		if (view->cacheacl == NULL) {
5243 			if (view->recursionacl != NULL) {
5244 				dns_acl_attach(view->recursionacl,
5245 					       &view->cacheacl);
5246 			} else if (view->queryacl != NULL) {
5247 				dns_acl_attach(view->queryacl, &view->cacheacl);
5248 			}
5249 		}
5250 
5251 		/*
5252 		 * "allow-recursion" inherits from "allow-query-cache" if set,
5253 		 * otherwise from "allow-query" if set.
5254 		 */
5255 		if (view->recursionacl == NULL) {
5256 			if (view->cacheacl != NULL) {
5257 				dns_acl_attach(view->cacheacl,
5258 					       &view->recursionacl);
5259 			} else if (view->queryacl != NULL) {
5260 				dns_acl_attach(view->queryacl,
5261 					       &view->recursionacl);
5262 			}
5263 		}
5264 
5265 		/*
5266 		 * "allow-query-cache-on" inherits from "allow-recursion-on"
5267 		 * if set.
5268 		 */
5269 		if (view->cacheonacl == NULL) {
5270 			if (view->recursiononacl != NULL) {
5271 				dns_acl_attach(view->recursiononacl,
5272 					       &view->cacheonacl);
5273 			}
5274 		}
5275 
5276 		/*
5277 		 * "allow-recursion-on" inherits from "allow-query-cache-on"
5278 		 * if set.
5279 		 */
5280 		if (view->recursiononacl == NULL) {
5281 			if (view->cacheonacl != NULL) {
5282 				dns_acl_attach(view->cacheonacl,
5283 					       &view->recursiononacl);
5284 			}
5285 		}
5286 
5287 		/*
5288 		 * If any are still unset at this point, we now get default
5289 		 * values for from the global config.
5290 		 */
5291 
5292 		if (view->recursionacl == NULL) {
5293 			/* global default only */
5294 			CHECK(configure_view_acl(
5295 				NULL, NULL, named_g_config, "allow-recursion",
5296 				NULL, actx, named_g_mctx, &view->recursionacl));
5297 		}
5298 		if (view->recursiononacl == NULL) {
5299 			/* global default only */
5300 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5301 						 "allow-recursion-on", NULL,
5302 						 actx, named_g_mctx,
5303 						 &view->recursiononacl));
5304 		}
5305 		if (view->cacheacl == NULL) {
5306 			/* global default only */
5307 			CHECK(configure_view_acl(
5308 				NULL, NULL, named_g_config, "allow-query-cache",
5309 				NULL, actx, named_g_mctx, &view->cacheacl));
5310 		}
5311 		if (view->cacheonacl == NULL) {
5312 			/* global default only */
5313 			CHECK(configure_view_acl(NULL, NULL, named_g_config,
5314 						 "allow-query-cache-on", NULL,
5315 						 actx, named_g_mctx,
5316 						 &view->cacheonacl));
5317 		}
5318 	} else {
5319 		/*
5320 		 * We're not recursive; if the query-cache ACLs haven't
5321 		 * been set at the options/view level, set them to none.
5322 		 */
5323 		if (view->cacheacl == NULL) {
5324 			CHECK(dns_acl_none(mctx, &view->cacheacl));
5325 		}
5326 		if (view->cacheonacl == NULL) {
5327 			CHECK(dns_acl_none(mctx, &view->cacheonacl));
5328 		}
5329 	}
5330 
5331 	/*
5332 	 * Finished setting recursion and query-cache ACLs, so now we
5333 	 * can get the allow-query default if it wasn't set in named.conf
5334 	 */
5335 	if (view->queryacl == NULL) {
5336 		/* global default only */
5337 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5338 					 "allow-query", NULL, actx,
5339 					 named_g_mctx, &view->queryacl));
5340 	}
5341 
5342 	/*
5343 	 * Ignore case when compressing responses to the specified
5344 	 * clients. This causes case not always to be preserved,
5345 	 * and is needed by some broken clients.
5346 	 */
5347 	CHECK(configure_view_acl(vconfig, config, named_g_config,
5348 				 "no-case-compress", NULL, actx, named_g_mctx,
5349 				 &view->nocasecompress));
5350 
5351 	/*
5352 	 * Disable name compression completely, this is a tradeoff
5353 	 * between CPU and network usage.
5354 	 */
5355 	obj = NULL;
5356 	result = named_config_get(maps, "message-compression", &obj);
5357 	INSIST(result == ISC_R_SUCCESS);
5358 	view->msgcompression = cfg_obj_asboolean(obj);
5359 
5360 	/*
5361 	 * Filter setting on addresses in the answer section.
5362 	 */
5363 	CHECK(configure_view_acl(vconfig, config, named_g_config,
5364 				 "deny-answer-addresses", "acl", actx,
5365 				 named_g_mctx, &view->denyansweracl));
5366 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
5367 				       "except-from", named_g_mctx,
5368 				       &view->answeracl_exclude));
5369 
5370 	/*
5371 	 * Filter setting on names (CNAME/DNAME targets) in the answer section.
5372 	 */
5373 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5374 				       "name", named_g_mctx,
5375 				       &view->denyanswernames));
5376 	CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5377 				       "except-from", named_g_mctx,
5378 				       &view->answernames_exclude));
5379 
5380 	/*
5381 	 * Configure sortlist, if set
5382 	 */
5383 	CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx,
5384 				      &view->sortlist));
5385 
5386 	/*
5387 	 * Configure default allow-update and allow-update-forwarding ACLs,
5388 	 * so they can be inherited by zones. (XXX: These are not
5389 	 * read from the options/view level here. However, they may be
5390 	 * read from there in zoneconf.c:configure_zone_acl() later.)
5391 	 */
5392 	if (view->updateacl == NULL) {
5393 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5394 					 "allow-update", NULL, actx,
5395 					 named_g_mctx, &view->updateacl));
5396 	}
5397 	if (view->upfwdacl == NULL) {
5398 		CHECK(configure_view_acl(NULL, NULL, named_g_config,
5399 					 "allow-update-forwarding", NULL, actx,
5400 					 named_g_mctx, &view->upfwdacl));
5401 	}
5402 
5403 	/*
5404 	 * Configure default allow-transfer and allow-notify ACLs so they
5405 	 * can be inherited by zones.
5406 	 */
5407 	if (view->transferacl == NULL) {
5408 		CHECK(configure_view_acl(vconfig, config, named_g_config,
5409 					 "allow-transfer", NULL, actx,
5410 					 named_g_mctx, &view->transferacl));
5411 	}
5412 	if (view->notifyacl == NULL) {
5413 		CHECK(configure_view_acl(vconfig, config, named_g_config,
5414 					 "allow-notify", NULL, actx,
5415 					 named_g_mctx, &view->notifyacl));
5416 	}
5417 
5418 	obj = NULL;
5419 	result = named_config_get(maps, "provide-ixfr", &obj);
5420 	INSIST(result == ISC_R_SUCCESS);
5421 	view->provideixfr = cfg_obj_asboolean(obj);
5422 
5423 	obj = NULL;
5424 	result = named_config_get(maps, "request-nsid", &obj);
5425 	INSIST(result == ISC_R_SUCCESS);
5426 	view->requestnsid = cfg_obj_asboolean(obj);
5427 
5428 	obj = NULL;
5429 	result = named_config_get(maps, "send-cookie", &obj);
5430 	INSIST(result == ISC_R_SUCCESS);
5431 	view->sendcookie = cfg_obj_asboolean(obj);
5432 
5433 	obj = NULL;
5434 	if (view->pad_acl != NULL) {
5435 		dns_acl_detach(&view->pad_acl);
5436 	}
5437 	result = named_config_get(optionmaps, "response-padding", &obj);
5438 	if (result == ISC_R_SUCCESS) {
5439 		const cfg_obj_t *padobj = cfg_tuple_get(obj, "block-size");
5440 		const cfg_obj_t *aclobj = cfg_tuple_get(obj, "acl");
5441 		uint32_t padding = cfg_obj_asuint32(padobj);
5442 
5443 		if (padding > 512U) {
5444 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
5445 				    "response-padding block-size cannot "
5446 				    "exceed 512: lowering");
5447 			padding = 512U;
5448 		}
5449 		view->padding = (uint16_t)padding;
5450 		CHECK(cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx,
5451 					 named_g_mctx, 0, &view->pad_acl));
5452 	}
5453 
5454 	obj = NULL;
5455 	result = named_config_get(maps, "require-server-cookie", &obj);
5456 	INSIST(result == ISC_R_SUCCESS);
5457 	view->requireservercookie = cfg_obj_asboolean(obj);
5458 
5459 	obj = NULL;
5460 	result = named_config_get(maps, "v6-bias", &obj);
5461 	INSIST(result == ISC_R_SUCCESS);
5462 	view->v6bias = cfg_obj_asuint32(obj) * 1000;
5463 
5464 	obj = NULL;
5465 	result = named_config_get(maps, "max-clients-per-query", &obj);
5466 	INSIST(result == ISC_R_SUCCESS);
5467 	max_clients_per_query = cfg_obj_asuint32(obj);
5468 
5469 	obj = NULL;
5470 	result = named_config_get(maps, "clients-per-query", &obj);
5471 	INSIST(result == ISC_R_SUCCESS);
5472 	dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj),
5473 					max_clients_per_query);
5474 
5475 	obj = NULL;
5476 	result = named_config_get(maps, "max-recursion-depth", &obj);
5477 	INSIST(result == ISC_R_SUCCESS);
5478 	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
5479 
5480 	obj = NULL;
5481 	result = named_config_get(maps, "max-recursion-queries", &obj);
5482 	INSIST(result == ISC_R_SUCCESS);
5483 	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
5484 
5485 	obj = NULL;
5486 	result = named_config_get(maps, "fetches-per-zone", &obj);
5487 	INSIST(result == ISC_R_SUCCESS);
5488 	obj2 = cfg_tuple_get(obj, "fetches");
5489 	dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
5490 	obj2 = cfg_tuple_get(obj, "response");
5491 	if (!cfg_obj_isvoid(obj2)) {
5492 		const char *resp = cfg_obj_asstring(obj2);
5493 		isc_result_t r = DNS_R_SERVFAIL;
5494 
5495 		if (strcasecmp(resp, "drop") == 0) {
5496 			r = DNS_R_DROP;
5497 		} else if (strcasecmp(resp, "fail") == 0) {
5498 			r = DNS_R_SERVFAIL;
5499 		} else {
5500 			INSIST(0);
5501 			ISC_UNREACHABLE();
5502 		}
5503 
5504 		dns_resolver_setquotaresponse(view->resolver,
5505 					      dns_quotatype_zone, r);
5506 	}
5507 
5508 	obj = NULL;
5509 	result = named_config_get(maps, "prefetch", &obj);
5510 	if (result == ISC_R_SUCCESS) {
5511 		const cfg_obj_t *trigger, *eligible;
5512 
5513 		trigger = cfg_tuple_get(obj, "trigger");
5514 		view->prefetch_trigger = cfg_obj_asuint32(trigger);
5515 		if (view->prefetch_trigger > 10) {
5516 			view->prefetch_trigger = 10;
5517 		}
5518 		eligible = cfg_tuple_get(obj, "eligible");
5519 		if (cfg_obj_isvoid(eligible)) {
5520 			int m;
5521 			for (m = 1; maps[m] != NULL; m++) {
5522 				obj = NULL;
5523 				result = named_config_get(&maps[m], "prefetch",
5524 							  &obj);
5525 				INSIST(result == ISC_R_SUCCESS);
5526 				eligible = cfg_tuple_get(obj, "eligible");
5527 				if (cfg_obj_isuint32(eligible)) {
5528 					break;
5529 				}
5530 			}
5531 			INSIST(cfg_obj_isuint32(eligible));
5532 		}
5533 		view->prefetch_eligible = cfg_obj_asuint32(eligible);
5534 		if (view->prefetch_eligible < view->prefetch_trigger + 6) {
5535 			view->prefetch_eligible = view->prefetch_trigger + 6;
5536 		}
5537 	}
5538 
5539 	/*
5540 	 * For now, there is only one kind of trusted keys, the
5541 	 * "security roots".
5542 	 */
5543 	CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
5544 					auto_root, mctx));
5545 	dns_resolver_resetmustbesecure(view->resolver);
5546 	obj = NULL;
5547 	result = named_config_get(maps, "dnssec-must-be-secure", &obj);
5548 	if (result == ISC_R_SUCCESS) {
5549 		CHECK(mustbesecure(obj, view->resolver));
5550 	}
5551 
5552 	obj = NULL;
5553 	result = named_config_get(maps, "nta-recheck", &obj);
5554 	INSIST(result == ISC_R_SUCCESS);
5555 	view->nta_recheck = cfg_obj_asduration(obj);
5556 
5557 	obj = NULL;
5558 	result = named_config_get(maps, "nta-lifetime", &obj);
5559 	INSIST(result == ISC_R_SUCCESS);
5560 	view->nta_lifetime = cfg_obj_asduration(obj);
5561 
5562 	obj = NULL;
5563 	result = named_config_get(maps, "preferred-glue", &obj);
5564 	if (result == ISC_R_SUCCESS) {
5565 		str = cfg_obj_asstring(obj);
5566 		if (strcasecmp(str, "a") == 0) {
5567 			view->preferred_glue = dns_rdatatype_a;
5568 		} else if (strcasecmp(str, "aaaa") == 0) {
5569 			view->preferred_glue = dns_rdatatype_aaaa;
5570 		} else {
5571 			view->preferred_glue = 0;
5572 		}
5573 	} else {
5574 		view->preferred_glue = 0;
5575 	}
5576 
5577 	obj = NULL;
5578 	result = named_config_get(maps, "root-delegation-only", &obj);
5579 	if (result == ISC_R_SUCCESS) {
5580 		dns_view_setrootdelonly(view, true);
5581 	}
5582 	if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
5583 		const cfg_obj_t *exclude;
5584 		dns_fixedname_t fixed;
5585 		dns_name_t *name;
5586 
5587 		name = dns_fixedname_initname(&fixed);
5588 		for (element = cfg_list_first(obj); element != NULL;
5589 		     element = cfg_list_next(element))
5590 		{
5591 			exclude = cfg_listelt_value(element);
5592 			CHECK(dns_name_fromstring(
5593 				name, cfg_obj_asstring(exclude), 0, NULL));
5594 			CHECK(dns_view_excludedelegationonly(view, name));
5595 		}
5596 	} else {
5597 		dns_view_setrootdelonly(view, false);
5598 	}
5599 
5600 	/*
5601 	 * Load DynDB modules.
5602 	 */
5603 	dyndb_list = NULL;
5604 	if (voptions != NULL) {
5605 		(void)cfg_map_get(voptions, "dyndb", &dyndb_list);
5606 	} else {
5607 		(void)cfg_map_get(config, "dyndb", &dyndb_list);
5608 	}
5609 
5610 	for (element = cfg_list_first(dyndb_list); element != NULL;
5611 	     element = cfg_list_next(element))
5612 	{
5613 		const cfg_obj_t *dyndb = cfg_listelt_value(element);
5614 
5615 		if (dctx == NULL) {
5616 			const void *hashinit = isc_hash_get_initializer();
5617 			CHECK(dns_dyndb_createctx(mctx, hashinit, named_g_lctx,
5618 						  view, named_g_server->zonemgr,
5619 						  named_g_server->task,
5620 						  named_g_timermgr, &dctx));
5621 		}
5622 
5623 		CHECK(configure_dyndb(dyndb, mctx, dctx));
5624 	}
5625 
5626 	/*
5627 	 * Load plugins.
5628 	 */
5629 	plugin_list = NULL;
5630 	if (voptions != NULL) {
5631 		(void)cfg_map_get(voptions, "plugin", &plugin_list);
5632 	} else {
5633 		(void)cfg_map_get(config, "plugin", &plugin_list);
5634 	}
5635 
5636 	if (plugin_list != NULL) {
5637 		INSIST(view->hooktable == NULL);
5638 		CHECK(ns_hooktable_create(view->mctx,
5639 					  (ns_hooktable_t **)&view->hooktable));
5640 		view->hooktable_free = ns_hooktable_free;
5641 
5642 		ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
5643 		view->plugins_free = ns_plugins_free;
5644 
5645 		CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
5646 					     register_one_plugin, view));
5647 	}
5648 
5649 	/*
5650 	 * Setup automatic empty zones.  If recursion is off then
5651 	 * they are disabled by default.
5652 	 */
5653 	obj = NULL;
5654 	(void)named_config_get(maps, "empty-zones-enable", &obj);
5655 	(void)named_config_get(maps, "disable-empty-zone", &disablelist);
5656 	if (obj == NULL && disablelist == NULL &&
5657 	    view->rdclass == dns_rdataclass_in) {
5658 		empty_zones_enable = view->recursion;
5659 	} else if (view->rdclass == dns_rdataclass_in) {
5660 		if (obj != NULL) {
5661 			empty_zones_enable = cfg_obj_asboolean(obj);
5662 		} else {
5663 			empty_zones_enable = view->recursion;
5664 		}
5665 	} else {
5666 		empty_zones_enable = false;
5667 	}
5668 
5669 	if (empty_zones_enable) {
5670 		const char *empty;
5671 		int empty_zone = 0;
5672 		dns_fixedname_t fixed;
5673 		dns_name_t *name;
5674 		isc_buffer_t buffer;
5675 		char server[DNS_NAME_FORMATSIZE + 1];
5676 		char contact[DNS_NAME_FORMATSIZE + 1];
5677 		const char *empty_dbtype[4] = { "_builtin", "empty", NULL,
5678 						NULL };
5679 		int empty_dbtypec = 4;
5680 		dns_zonestat_level_t statlevel = dns_zonestat_none;
5681 
5682 		name = dns_fixedname_initname(&fixed);
5683 
5684 		obj = NULL;
5685 		result = named_config_get(maps, "empty-server", &obj);
5686 		if (result == ISC_R_SUCCESS) {
5687 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5688 						  0, NULL));
5689 			isc_buffer_init(&buffer, server, sizeof(server) - 1);
5690 			CHECK(dns_name_totext(name, false, &buffer));
5691 			server[isc_buffer_usedlength(&buffer)] = 0;
5692 			empty_dbtype[2] = server;
5693 		} else {
5694 			empty_dbtype[2] = "@";
5695 		}
5696 
5697 		obj = NULL;
5698 		result = named_config_get(maps, "empty-contact", &obj);
5699 		if (result == ISC_R_SUCCESS) {
5700 			CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5701 						  0, NULL));
5702 			isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
5703 			CHECK(dns_name_totext(name, false, &buffer));
5704 			contact[isc_buffer_usedlength(&buffer)] = 0;
5705 			empty_dbtype[3] = contact;
5706 		} else {
5707 			empty_dbtype[3] = ".";
5708 		}
5709 
5710 		obj = NULL;
5711 		result = named_config_get(maps, "zone-statistics", &obj);
5712 		INSIST(result == ISC_R_SUCCESS);
5713 		if (cfg_obj_isboolean(obj)) {
5714 			if (cfg_obj_asboolean(obj)) {
5715 				statlevel = dns_zonestat_full;
5716 			} else {
5717 				statlevel = dns_zonestat_none;
5718 			}
5719 		} else {
5720 			const char *levelstr = cfg_obj_asstring(obj);
5721 			if (strcasecmp(levelstr, "full") == 0) {
5722 				statlevel = dns_zonestat_full;
5723 			} else if (strcasecmp(levelstr, "terse") == 0) {
5724 				statlevel = dns_zonestat_terse;
5725 			} else if (strcasecmp(levelstr, "none") == 0) {
5726 				statlevel = dns_zonestat_none;
5727 			} else {
5728 				INSIST(0);
5729 				ISC_UNREACHABLE();
5730 			}
5731 		}
5732 
5733 		for (empty = empty_zones[empty_zone]; empty != NULL;
5734 		     empty = empty_zones[++empty_zone])
5735 		{
5736 			dns_forwarders_t *dnsforwarders = NULL;
5737 
5738 			/*
5739 			 * Look for zone on drop list.
5740 			 */
5741 			CHECK(dns_name_fromstring(name, empty, 0, NULL));
5742 			if (disablelist != NULL &&
5743 			    on_disable_list(disablelist, name)) {
5744 				continue;
5745 			}
5746 
5747 			/*
5748 			 * This zone already exists.
5749 			 */
5750 			(void)dns_view_findzone(view, name, &zone);
5751 			if (zone != NULL) {
5752 				dns_zone_detach(&zone);
5753 				continue;
5754 			}
5755 
5756 			/*
5757 			 * If we would forward this name don't add a
5758 			 * empty zone for it.
5759 			 */
5760 			result = dns_fwdtable_find(view->fwdtable, name, NULL,
5761 						   &dnsforwarders);
5762 			if (result == ISC_R_SUCCESS &&
5763 			    dnsforwarders->fwdpolicy == dns_fwdpolicy_only) {
5764 				continue;
5765 			}
5766 
5767 			/*
5768 			 * See if we can re-use a existing zone.
5769 			 */
5770 			result = dns_viewlist_find(&named_g_server->viewlist,
5771 						   view->name, view->rdclass,
5772 						   &pview);
5773 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
5774 			{
5775 				goto cleanup;
5776 			}
5777 
5778 			if (pview != NULL) {
5779 				(void)dns_view_findzone(pview, name, &zone);
5780 				dns_view_detach(&pview);
5781 			}
5782 
5783 			CHECK(create_empty_zone(zone, name, view, zonelist,
5784 						empty_dbtype, empty_dbtypec,
5785 						statlevel));
5786 			if (zone != NULL) {
5787 				dns_zone_detach(&zone);
5788 			}
5789 		}
5790 	}
5791 
5792 	obj = NULL;
5793 	if (view->rdclass == dns_rdataclass_in) {
5794 		(void)named_config_get(maps, "ipv4only-enable", &obj);
5795 	}
5796 	if (view->rdclass == dns_rdataclass_in && (obj != NULL)
5797 		    ? cfg_obj_asboolean(obj)
5798 		    : !ISC_LIST_EMPTY(view->dns64))
5799 	{
5800 		const char *server, *contact;
5801 		dns_fixedname_t fixed;
5802 		dns_name_t *name;
5803 		struct {
5804 			const char *name;
5805 			const char *type;
5806 		} zones[] = {
5807 			{ "ipv4only.arpa", "ipv4only" },
5808 			{ "170.0.0.192.in-addr.arpa", "ipv4reverse" },
5809 			{ "171.0.0.192.in-addr.arpa", "ipv4reverse" },
5810 		};
5811 		size_t ipv4only_zone;
5812 
5813 		obj = NULL;
5814 		result = named_config_get(maps, "ipv4only-server", &obj);
5815 		if (result == ISC_R_SUCCESS) {
5816 			server = cfg_obj_asstring(obj);
5817 		} else {
5818 			server = NULL;
5819 		}
5820 
5821 		obj = NULL;
5822 		result = named_config_get(maps, "ipv4only-contact", &obj);
5823 		if (result == ISC_R_SUCCESS) {
5824 			contact = cfg_obj_asstring(obj);
5825 		} else {
5826 			contact = NULL;
5827 		}
5828 
5829 		name = dns_fixedname_initname(&fixed);
5830 		for (ipv4only_zone = 0; ipv4only_zone < ARRAYSIZE(zones);
5831 		     ipv4only_zone++) {
5832 			dns_forwarders_t *dnsforwarders = NULL;
5833 
5834 			CHECK(dns_name_fromstring(
5835 				name, zones[ipv4only_zone].name, 0, NULL));
5836 
5837 			(void)dns_view_findzone(view, name, &zone);
5838 			if (zone != NULL) {
5839 				dns_zone_detach(&zone);
5840 				continue;
5841 			}
5842 
5843 			/*
5844 			 * If we would forward this name don't add it.
5845 			 */
5846 			result = dns_fwdtable_find(view->fwdtable, name, NULL,
5847 						   &dnsforwarders);
5848 			if (result == ISC_R_SUCCESS &&
5849 			    dnsforwarders->fwdpolicy == dns_fwdpolicy_only) {
5850 				continue;
5851 			}
5852 
5853 			/*
5854 			 * See if we can re-use a existing zone.
5855 			 */
5856 			result = dns_viewlist_find(&named_g_server->viewlist,
5857 						   view->name, view->rdclass,
5858 						   &pview);
5859 			if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
5860 			{
5861 				goto cleanup;
5862 			}
5863 
5864 			if (pview != NULL) {
5865 				(void)dns_view_findzone(pview, name, &zone);
5866 				dns_view_detach(&pview);
5867 			}
5868 
5869 			CHECK(create_ipv4only_zone(zone, view, name,
5870 						   zones[ipv4only_zone].type,
5871 						   mctx, server, contact));
5872 			if (zone != NULL) {
5873 				dns_zone_detach(&zone);
5874 			}
5875 		}
5876 	}
5877 
5878 	obj = NULL;
5879 	result = named_config_get(maps, "rate-limit", &obj);
5880 	if (result == ISC_R_SUCCESS) {
5881 		result = configure_rrl(view, config, obj);
5882 		if (result != ISC_R_SUCCESS) {
5883 			goto cleanup;
5884 		}
5885 	}
5886 
5887 	/*
5888 	 * Set the servfail-ttl.
5889 	 */
5890 	obj = NULL;
5891 	result = named_config_get(maps, "servfail-ttl", &obj);
5892 	INSIST(result == ISC_R_SUCCESS);
5893 	fail_ttl = cfg_obj_asduration(obj);
5894 	if (fail_ttl > 30) {
5895 		fail_ttl = 30;
5896 	}
5897 	dns_view_setfailttl(view, fail_ttl);
5898 
5899 	/*
5900 	 * Name space to look up redirect information in.
5901 	 */
5902 	obj = NULL;
5903 	result = named_config_get(maps, "nxdomain-redirect", &obj);
5904 	if (result == ISC_R_SUCCESS) {
5905 		dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
5906 		CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0,
5907 					  NULL));
5908 		view->redirectzone = name;
5909 	} else {
5910 		view->redirectzone = NULL;
5911 	}
5912 
5913 	/*
5914 	 * Exceptions to DNSSEC validation.
5915 	 */
5916 	obj = NULL;
5917 	result = named_config_get(maps, "validate-except", &obj);
5918 	if (result == ISC_R_SUCCESS) {
5919 		result = dns_view_getntatable(view, &ntatable);
5920 	}
5921 	if (result == ISC_R_SUCCESS) {
5922 		for (element = cfg_list_first(obj); element != NULL;
5923 		     element = cfg_list_next(element))
5924 		{
5925 			dns_fixedname_t fntaname;
5926 			dns_name_t *ntaname;
5927 
5928 			ntaname = dns_fixedname_initname(&fntaname);
5929 			obj = cfg_listelt_value(element);
5930 			CHECK(dns_name_fromstring(
5931 				ntaname, cfg_obj_asstring(obj), 0, NULL));
5932 			CHECK(dns_ntatable_add(ntatable, ntaname, true, 0,
5933 					       0xffffffffU));
5934 		}
5935 	}
5936 
5937 #ifdef HAVE_DNSTAP
5938 	/*
5939 	 * Set up the dnstap environment and configure message
5940 	 * types to log.
5941 	 */
5942 	CHECK(configure_dnstap(maps, view));
5943 #endif /* HAVE_DNSTAP */
5944 
5945 	result = ISC_R_SUCCESS;
5946 
5947 cleanup:
5948 	if (ntatable != NULL) {
5949 		dns_ntatable_detach(&ntatable);
5950 	}
5951 	if (clients != NULL) {
5952 		dns_acl_detach(&clients);
5953 	}
5954 	if (mapped != NULL) {
5955 		dns_acl_detach(&mapped);
5956 	}
5957 	if (excluded != NULL) {
5958 		dns_acl_detach(&excluded);
5959 	}
5960 	if (ring != NULL) {
5961 		dns_tsigkeyring_detach(&ring);
5962 	}
5963 	if (zone != NULL) {
5964 		dns_zone_detach(&zone);
5965 	}
5966 	if (dispatch4 != NULL) {
5967 		dns_dispatch_detach(&dispatch4);
5968 	}
5969 	if (dispatch6 != NULL) {
5970 		dns_dispatch_detach(&dispatch6);
5971 	}
5972 	if (resstats != NULL) {
5973 		isc_stats_detach(&resstats);
5974 	}
5975 	if (resquerystats != NULL) {
5976 		dns_stats_detach(&resquerystats);
5977 	}
5978 	if (order != NULL) {
5979 		dns_order_detach(&order);
5980 	}
5981 	if (cmctx != NULL) {
5982 		isc_mem_detach(&cmctx);
5983 	}
5984 	if (hmctx != NULL) {
5985 		isc_mem_detach(&hmctx);
5986 	}
5987 	if (cache != NULL) {
5988 		dns_cache_detach(&cache);
5989 	}
5990 	if (dctx != NULL) {
5991 		dns_dyndb_destroyctx(&dctx);
5992 	}
5993 
5994 	return (result);
5995 }
5996 
5997 static isc_result_t
configure_hints(dns_view_t * view,const char * filename)5998 configure_hints(dns_view_t *view, const char *filename) {
5999 	isc_result_t result;
6000 	dns_db_t *db;
6001 
6002 	db = NULL;
6003 	result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
6004 	if (result == ISC_R_SUCCESS) {
6005 		dns_view_sethints(view, db);
6006 		dns_db_detach(&db);
6007 	}
6008 
6009 	return (result);
6010 }
6011 
6012 static isc_result_t
configure_alternates(const cfg_obj_t * config,dns_view_t * view,const cfg_obj_t * alternates)6013 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
6014 		     const cfg_obj_t *alternates) {
6015 	const cfg_obj_t *portobj;
6016 	const cfg_obj_t *addresses;
6017 	const cfg_listelt_t *element;
6018 	isc_result_t result = ISC_R_SUCCESS;
6019 	in_port_t port;
6020 
6021 	/*
6022 	 * Determine which port to send requests to.
6023 	 */
6024 	CHECKM(named_config_getport(config, "port", &port), "port");
6025 
6026 	if (alternates != NULL) {
6027 		portobj = cfg_tuple_get(alternates, "port");
6028 		if (cfg_obj_isuint32(portobj)) {
6029 			uint32_t val = cfg_obj_asuint32(portobj);
6030 			if (val > UINT16_MAX) {
6031 				cfg_obj_log(portobj, named_g_lctx,
6032 					    ISC_LOG_ERROR,
6033 					    "port '%u' out of range", val);
6034 				return (ISC_R_RANGE);
6035 			}
6036 			port = (in_port_t)val;
6037 		}
6038 	}
6039 
6040 	addresses = NULL;
6041 	if (alternates != NULL) {
6042 		addresses = cfg_tuple_get(alternates, "addresses");
6043 	}
6044 
6045 	for (element = cfg_list_first(addresses); element != NULL;
6046 	     element = cfg_list_next(element))
6047 	{
6048 		const cfg_obj_t *alternate = cfg_listelt_value(element);
6049 		isc_sockaddr_t sa;
6050 
6051 		if (!cfg_obj_issockaddr(alternate)) {
6052 			dns_fixedname_t fixed;
6053 			dns_name_t *name;
6054 			const char *str = cfg_obj_asstring(
6055 				cfg_tuple_get(alternate, "name"));
6056 			isc_buffer_t buffer;
6057 			in_port_t myport = port;
6058 
6059 			isc_buffer_constinit(&buffer, str, strlen(str));
6060 			isc_buffer_add(&buffer, strlen(str));
6061 			name = dns_fixedname_initname(&fixed);
6062 			CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
6063 						NULL));
6064 
6065 			portobj = cfg_tuple_get(alternate, "port");
6066 			if (cfg_obj_isuint32(portobj)) {
6067 				uint32_t val = cfg_obj_asuint32(portobj);
6068 				if (val > UINT16_MAX) {
6069 					cfg_obj_log(portobj, named_g_lctx,
6070 						    ISC_LOG_ERROR,
6071 						    "port '%u' out of range",
6072 						    val);
6073 					return (ISC_R_RANGE);
6074 				}
6075 				myport = (in_port_t)val;
6076 			}
6077 			CHECK(dns_resolver_addalternate(view->resolver, NULL,
6078 							name, myport));
6079 			continue;
6080 		}
6081 
6082 		sa = *cfg_obj_assockaddr(alternate);
6083 		if (isc_sockaddr_getport(&sa) == 0) {
6084 			isc_sockaddr_setport(&sa, port);
6085 		}
6086 		CHECK(dns_resolver_addalternate(view->resolver, &sa, NULL, 0));
6087 	}
6088 
6089 cleanup:
6090 	return (result);
6091 }
6092 
6093 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)6094 configure_forward(const cfg_obj_t *config, dns_view_t *view,
6095 		  const dns_name_t *origin, const cfg_obj_t *forwarders,
6096 		  const cfg_obj_t *forwardtype) {
6097 	const cfg_obj_t *portobj, *dscpobj;
6098 	const cfg_obj_t *faddresses;
6099 	const cfg_listelt_t *element;
6100 	dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
6101 	dns_forwarderlist_t fwdlist;
6102 	dns_forwarder_t *fwd;
6103 	isc_result_t result;
6104 	in_port_t port;
6105 	isc_dscp_t dscp = -1;
6106 
6107 	ISC_LIST_INIT(fwdlist);
6108 
6109 	/*
6110 	 * Determine which port to send forwarded requests to.
6111 	 */
6112 	CHECKM(named_config_getport(config, "port", &port), "port");
6113 
6114 	if (forwarders != NULL) {
6115 		portobj = cfg_tuple_get(forwarders, "port");
6116 		if (cfg_obj_isuint32(portobj)) {
6117 			uint32_t val = cfg_obj_asuint32(portobj);
6118 			if (val > UINT16_MAX) {
6119 				cfg_obj_log(portobj, named_g_lctx,
6120 					    ISC_LOG_ERROR,
6121 					    "port '%u' out of range", val);
6122 				return (ISC_R_RANGE);
6123 			}
6124 			port = (in_port_t)val;
6125 		}
6126 	}
6127 
6128 	/*
6129 	 * DSCP value for forwarded requests.
6130 	 */
6131 	dscp = named_g_dscp;
6132 	if (forwarders != NULL) {
6133 		dscpobj = cfg_tuple_get(forwarders, "dscp");
6134 		if (cfg_obj_isuint32(dscpobj)) {
6135 			if (cfg_obj_asuint32(dscpobj) > 63) {
6136 				cfg_obj_log(dscpobj, named_g_lctx,
6137 					    ISC_LOG_ERROR,
6138 					    "dscp value '%u' is out of range",
6139 					    cfg_obj_asuint32(dscpobj));
6140 				return (ISC_R_RANGE);
6141 			}
6142 			dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
6143 		}
6144 	}
6145 
6146 	faddresses = NULL;
6147 	if (forwarders != NULL) {
6148 		faddresses = cfg_tuple_get(forwarders, "addresses");
6149 	}
6150 
6151 	for (element = cfg_list_first(faddresses); element != NULL;
6152 	     element = cfg_list_next(element))
6153 	{
6154 		const cfg_obj_t *forwarder = cfg_listelt_value(element);
6155 		fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
6156 		fwd->addr = *cfg_obj_assockaddr(forwarder);
6157 		if (isc_sockaddr_getport(&fwd->addr) == 0) {
6158 			isc_sockaddr_setport(&fwd->addr, port);
6159 		}
6160 		fwd->dscp = cfg_obj_getdscp(forwarder);
6161 		if (fwd->dscp == -1) {
6162 			fwd->dscp = dscp;
6163 		}
6164 		ISC_LINK_INIT(fwd, link);
6165 		ISC_LIST_APPEND(fwdlist, fwd, link);
6166 	}
6167 
6168 	if (ISC_LIST_EMPTY(fwdlist)) {
6169 		if (forwardtype != NULL) {
6170 			cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING,
6171 				    "no forwarders seen; disabling "
6172 				    "forwarding");
6173 		}
6174 		fwdpolicy = dns_fwdpolicy_none;
6175 	} else {
6176 		if (forwardtype == NULL) {
6177 			fwdpolicy = dns_fwdpolicy_first;
6178 		} else {
6179 			const char *forwardstr = cfg_obj_asstring(forwardtype);
6180 			if (strcasecmp(forwardstr, "first") == 0) {
6181 				fwdpolicy = dns_fwdpolicy_first;
6182 			} else if (strcasecmp(forwardstr, "only") == 0) {
6183 				fwdpolicy = dns_fwdpolicy_only;
6184 			} else {
6185 				INSIST(0);
6186 				ISC_UNREACHABLE();
6187 			}
6188 		}
6189 	}
6190 
6191 	result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
6192 				     fwdpolicy);
6193 	if (result != ISC_R_SUCCESS) {
6194 		char namebuf[DNS_NAME_FORMATSIZE];
6195 		dns_name_format(origin, namebuf, sizeof(namebuf));
6196 		cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING,
6197 			    "could not set up forwarding for domain '%s': %s",
6198 			    namebuf, isc_result_totext(result));
6199 		goto cleanup;
6200 	}
6201 
6202 	result = ISC_R_SUCCESS;
6203 
6204 cleanup:
6205 
6206 	while (!ISC_LIST_EMPTY(fwdlist)) {
6207 		fwd = ISC_LIST_HEAD(fwdlist);
6208 		ISC_LIST_UNLINK(fwdlist, fwd, link);
6209 		isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
6210 	}
6211 
6212 	return (result);
6213 }
6214 
6215 static isc_result_t
get_viewinfo(const cfg_obj_t * vconfig,const char ** namep,dns_rdataclass_t * classp)6216 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
6217 	     dns_rdataclass_t *classp) {
6218 	isc_result_t result = ISC_R_SUCCESS;
6219 	const char *viewname;
6220 	dns_rdataclass_t viewclass;
6221 
6222 	REQUIRE(namep != NULL && *namep == NULL);
6223 	REQUIRE(classp != NULL);
6224 
6225 	if (vconfig != NULL) {
6226 		const cfg_obj_t *classobj = NULL;
6227 
6228 		viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
6229 		classobj = cfg_tuple_get(vconfig, "class");
6230 		CHECK(named_config_getclass(classobj, dns_rdataclass_in,
6231 					    &viewclass));
6232 		if (dns_rdataclass_ismeta(viewclass)) {
6233 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6234 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6235 				      "view '%s': class must not be meta",
6236 				      viewname);
6237 			CHECK(ISC_R_FAILURE);
6238 		}
6239 	} else {
6240 		viewname = "_default";
6241 		viewclass = dns_rdataclass_in;
6242 	}
6243 
6244 	*namep = viewname;
6245 	*classp = viewclass;
6246 
6247 cleanup:
6248 	return (result);
6249 }
6250 
6251 /*
6252  * Find a view based on its configuration info and attach to it.
6253  *
6254  * If 'vconfig' is NULL, attach to the default view.
6255  */
6256 static isc_result_t
find_view(const cfg_obj_t * vconfig,dns_viewlist_t * viewlist,dns_view_t ** viewp)6257 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6258 	  dns_view_t **viewp) {
6259 	isc_result_t result;
6260 	const char *viewname = NULL;
6261 	dns_rdataclass_t viewclass;
6262 	dns_view_t *view = NULL;
6263 
6264 	result = get_viewinfo(vconfig, &viewname, &viewclass);
6265 	if (result != ISC_R_SUCCESS) {
6266 		return (result);
6267 	}
6268 
6269 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6270 	if (result != ISC_R_SUCCESS) {
6271 		return (result);
6272 	}
6273 
6274 	*viewp = view;
6275 	return (ISC_R_SUCCESS);
6276 }
6277 
6278 /*
6279  * Create a new view and add it to the list.
6280  *
6281  * If 'vconfig' is NULL, create the default view.
6282  *
6283  * The view created is attached to '*viewp'.
6284  */
6285 static isc_result_t
create_view(const cfg_obj_t * vconfig,dns_viewlist_t * viewlist,dns_view_t ** viewp)6286 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6287 	    dns_view_t **viewp) {
6288 	isc_result_t result;
6289 	const char *viewname = NULL;
6290 	dns_rdataclass_t viewclass;
6291 	dns_view_t *view = NULL;
6292 
6293 	result = get_viewinfo(vconfig, &viewname, &viewclass);
6294 	if (result != ISC_R_SUCCESS) {
6295 		return (result);
6296 	}
6297 
6298 	result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6299 	if (result == ISC_R_SUCCESS) {
6300 		return (ISC_R_EXISTS);
6301 	}
6302 	if (result != ISC_R_NOTFOUND) {
6303 		return (result);
6304 	}
6305 	INSIST(view == NULL);
6306 
6307 	result = dns_view_create(named_g_mctx, viewclass, viewname, &view);
6308 	if (result != ISC_R_SUCCESS) {
6309 		return (result);
6310 	}
6311 
6312 	isc_nonce_buf(view->secret, sizeof(view->secret));
6313 
6314 	ISC_LIST_APPEND(*viewlist, view, link);
6315 	dns_view_attach(view, viewp);
6316 	return (ISC_R_SUCCESS);
6317 }
6318 
6319 /*
6320  * Configure or reconfigure a zone.
6321  */
6322 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)6323 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
6324 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
6325 	       dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
6326 	       cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
6327 	       bool modify) {
6328 	dns_view_t *pview = NULL; /* Production view */
6329 	dns_zone_t *zone = NULL;  /* New or reused zone */
6330 	dns_zone_t *raw = NULL;	  /* New or reused raw zone */
6331 	dns_zone_t *dupzone = NULL;
6332 	const cfg_obj_t *options = NULL;
6333 	const cfg_obj_t *zoptions = NULL;
6334 	const cfg_obj_t *typeobj = NULL;
6335 	const cfg_obj_t *forwarders = NULL;
6336 	const cfg_obj_t *forwardtype = NULL;
6337 	const cfg_obj_t *ixfrfromdiffs = NULL;
6338 	const cfg_obj_t *only = NULL;
6339 	const cfg_obj_t *viewobj = NULL;
6340 	isc_result_t result;
6341 	isc_result_t tresult;
6342 	isc_buffer_t buffer;
6343 	dns_fixedname_t fixorigin;
6344 	dns_name_t *origin;
6345 	const char *zname;
6346 	dns_rdataclass_t zclass;
6347 	const char *ztypestr;
6348 	dns_rpz_num_t rpz_num;
6349 	bool zone_is_catz = false;
6350 	bool zone_maybe_inline = false;
6351 	bool inline_signing = false;
6352 
6353 	options = NULL;
6354 	(void)cfg_map_get(config, "options", &options);
6355 
6356 	zoptions = cfg_tuple_get(zconfig, "options");
6357 
6358 	/*
6359 	 * Get the zone origin as a dns_name_t.
6360 	 */
6361 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
6362 	isc_buffer_constinit(&buffer, zname, strlen(zname));
6363 	isc_buffer_add(&buffer, strlen(zname));
6364 	dns_fixedname_init(&fixorigin);
6365 	CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
6366 				dns_rootname, 0, NULL));
6367 	origin = dns_fixedname_name(&fixorigin);
6368 
6369 	CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"),
6370 				    view->rdclass, &zclass));
6371 	if (zclass != view->rdclass) {
6372 		const char *vname = NULL;
6373 		if (vconfig != NULL) {
6374 			vname = cfg_obj_asstring(
6375 				cfg_tuple_get(vconfig, "name"));
6376 		} else {
6377 			vname = "<default view>";
6378 		}
6379 
6380 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6381 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6382 			      "zone '%s': wrong class for view '%s'", zname,
6383 			      vname);
6384 		result = ISC_R_FAILURE;
6385 		goto cleanup;
6386 	}
6387 
6388 	(void)cfg_map_get(zoptions, "in-view", &viewobj);
6389 	if (viewobj != NULL) {
6390 		const char *inview = cfg_obj_asstring(viewobj);
6391 		dns_view_t *otherview = NULL;
6392 
6393 		if (viewlist == NULL) {
6394 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6395 				    "'in-view' option is not permitted in "
6396 				    "dynamically added zones");
6397 			result = ISC_R_FAILURE;
6398 			goto cleanup;
6399 		}
6400 
6401 		result = dns_viewlist_find(viewlist, inview, view->rdclass,
6402 					   &otherview);
6403 		if (result != ISC_R_SUCCESS) {
6404 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6405 				    "view '%s' is not yet defined.", inview);
6406 			result = ISC_R_FAILURE;
6407 			goto cleanup;
6408 		}
6409 
6410 		result = dns_view_findzone(otherview, origin, &zone);
6411 		dns_view_detach(&otherview);
6412 		if (result != ISC_R_SUCCESS) {
6413 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6414 				    "zone '%s' not defined in view '%s'", zname,
6415 				    inview);
6416 			result = ISC_R_FAILURE;
6417 			goto cleanup;
6418 		}
6419 
6420 		CHECK(dns_view_addzone(view, zone));
6421 		dns_zone_detach(&zone);
6422 
6423 		/*
6424 		 * If the zone contains a 'forwarders' statement, configure
6425 		 * selective forwarding.  Note: this is not inherited from the
6426 		 * other view.
6427 		 */
6428 		forwarders = NULL;
6429 		result = cfg_map_get(zoptions, "forwarders", &forwarders);
6430 		if (result == ISC_R_SUCCESS) {
6431 			forwardtype = NULL;
6432 			(void)cfg_map_get(zoptions, "forward", &forwardtype);
6433 			CHECK(configure_forward(config, view, origin,
6434 						forwarders, forwardtype));
6435 		}
6436 		result = ISC_R_SUCCESS;
6437 		goto cleanup;
6438 	}
6439 
6440 	(void)cfg_map_get(zoptions, "type", &typeobj);
6441 	if (typeobj == NULL) {
6442 		cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6443 			    "zone '%s' 'type' not specified", zname);
6444 		result = ISC_R_FAILURE;
6445 		goto cleanup;
6446 	}
6447 	ztypestr = cfg_obj_asstring(typeobj);
6448 
6449 	/*
6450 	 * "hints zones" aren't zones.	If we've got one,
6451 	 * configure it and return.
6452 	 */
6453 	if (strcasecmp(ztypestr, "hint") == 0) {
6454 		const cfg_obj_t *fileobj = NULL;
6455 		if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
6456 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6457 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6458 				      "zone '%s': 'file' not specified", zname);
6459 			result = ISC_R_FAILURE;
6460 			goto cleanup;
6461 		}
6462 		if (dns_name_equal(origin, dns_rootname)) {
6463 			const char *hintsfile = cfg_obj_asstring(fileobj);
6464 
6465 			CHECK(configure_hints(view, hintsfile));
6466 
6467 			/*
6468 			 * Hint zones may also refer to delegation only points.
6469 			 */
6470 			only = NULL;
6471 			tresult = cfg_map_get(zoptions, "delegation-only",
6472 					      &only);
6473 			if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
6474 			{
6475 				CHECK(dns_view_adddelegationonly(view, origin));
6476 			}
6477 		} else {
6478 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6479 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
6480 				      "ignoring non-root hint zone '%s'",
6481 				      zname);
6482 			result = ISC_R_SUCCESS;
6483 		}
6484 		/* Skip ordinary zone processing. */
6485 		goto cleanup;
6486 	}
6487 
6488 	/*
6489 	 * "forward zones" aren't zones either.  Translate this syntax into
6490 	 * the appropriate selective forwarding configuration and return.
6491 	 */
6492 	if (strcasecmp(ztypestr, "forward") == 0) {
6493 		forwardtype = NULL;
6494 		forwarders = NULL;
6495 
6496 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6497 		(void)cfg_map_get(zoptions, "forwarders", &forwarders);
6498 		CHECK(configure_forward(config, view, origin, forwarders,
6499 					forwardtype));
6500 
6501 		/*
6502 		 * Forward zones may also set delegation only.
6503 		 */
6504 		only = NULL;
6505 		tresult = cfg_map_get(zoptions, "delegation-only", &only);
6506 		if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) {
6507 			CHECK(dns_view_adddelegationonly(view, origin));
6508 		}
6509 		goto cleanup;
6510 	}
6511 
6512 	/*
6513 	 * "delegation-only zones" aren't zones either.
6514 	 */
6515 	if (strcasecmp(ztypestr, "delegation-only") == 0) {
6516 		result = dns_view_adddelegationonly(view, origin);
6517 		goto cleanup;
6518 	}
6519 
6520 	/*
6521 	 * Redirect zones only require minimal configuration.
6522 	 */
6523 	if (strcasecmp(ztypestr, "redirect") == 0) {
6524 		if (view->redirect != NULL) {
6525 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6526 				    "redirect zone already exists");
6527 			result = ISC_R_EXISTS;
6528 			goto cleanup;
6529 		}
6530 		result = dns_viewlist_find(viewlist, view->name, view->rdclass,
6531 					   &pview);
6532 		if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6533 			goto cleanup;
6534 		}
6535 		if (pview != NULL && pview->redirect != NULL) {
6536 			dns_zone_attach(pview->redirect, &zone);
6537 			dns_zone_setview(zone, view);
6538 		} else {
6539 			CHECK(dns_zonemgr_createzone(named_g_server->zonemgr,
6540 						     &zone));
6541 			CHECK(dns_zone_setorigin(zone, origin));
6542 			dns_zone_setview(zone, view);
6543 			CHECK(dns_zonemgr_managezone(named_g_server->zonemgr,
6544 						     zone));
6545 			dns_zone_setstats(zone, named_g_server->zonestats);
6546 		}
6547 		CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
6548 					   kasplist, zone, NULL));
6549 		dns_zone_attach(zone, &view->redirect);
6550 		goto cleanup;
6551 	}
6552 
6553 	if (!modify) {
6554 		/*
6555 		 * Check for duplicates in the new zone table.
6556 		 */
6557 		result = dns_view_findzone(view, origin, &dupzone);
6558 		if (result == ISC_R_SUCCESS) {
6559 			/*
6560 			 * We already have this zone!
6561 			 */
6562 			cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6563 				    "zone '%s' already exists", zname);
6564 			dns_zone_detach(&dupzone);
6565 			result = ISC_R_EXISTS;
6566 			goto cleanup;
6567 		}
6568 		INSIST(dupzone == NULL);
6569 	}
6570 
6571 	/*
6572 	 * Note whether this is a response policy zone and which one if so,
6573 	 * unless we are using RPZ service interface.  In that case, the
6574 	 * BIND zone database has nothing to do with rpz and so we don't care.
6575 	 */
6576 	for (rpz_num = 0;; ++rpz_num) {
6577 		if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
6578 		    view->rpzs->p.dnsrps_enabled)
6579 		{
6580 			rpz_num = DNS_RPZ_INVALID_NUM;
6581 			break;
6582 		}
6583 		if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
6584 		{
6585 			break;
6586 		}
6587 	}
6588 
6589 	if (view->catzs != NULL &&
6590 	    dns_catz_get_zone(view->catzs, origin) != NULL) {
6591 		zone_is_catz = true;
6592 	}
6593 
6594 	/*
6595 	 * See if we can reuse an existing zone.  This is
6596 	 * only possible if all of these are true:
6597 	 *   - The zone's view exists
6598 	 *   - A zone with the right name exists in the view
6599 	 *   - The zone is compatible with the config
6600 	 *     options (e.g., an existing master zone cannot
6601 	 *     be reused if the options specify a slave zone)
6602 	 *   - The zone was not and is still not a response policy zone
6603 	 *     or the zone is a policy zone with an unchanged number
6604 	 *     and we are using the old policy zone summary data.
6605 	 */
6606 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6607 				   view->rdclass, &pview);
6608 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6609 		goto cleanup;
6610 	}
6611 	if (pview != NULL) {
6612 		result = dns_view_findzone(pview, origin, &zone);
6613 	}
6614 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6615 		goto cleanup;
6616 	}
6617 
6618 	if (zone != NULL &&
6619 	    !named_zone_reusable(zone, zconfig, vconfig, config, aclconf))
6620 	{
6621 		dns_zone_detach(&zone);
6622 	}
6623 
6624 	if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
6625 			     (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
6626 	{
6627 		dns_zone_detach(&zone);
6628 	}
6629 
6630 	if (zone != NULL) {
6631 		/*
6632 		 * We found a reusable zone.  Make it use the
6633 		 * new view.
6634 		 */
6635 		dns_zone_setview(zone, view);
6636 	} else {
6637 		/*
6638 		 * We cannot reuse an existing zone, we have
6639 		 * to create a new one.
6640 		 */
6641 		CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6642 		CHECK(dns_zone_setorigin(zone, origin));
6643 		dns_zone_setview(zone, view);
6644 		CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6645 		dns_zone_setstats(zone, named_g_server->zonestats);
6646 	}
6647 	if (rpz_num != DNS_RPZ_INVALID_NUM) {
6648 		result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
6649 		if (result != ISC_R_SUCCESS) {
6650 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6651 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6652 				      "zone '%s': incompatible"
6653 				      " masterfile-format or database"
6654 				      " for a response policy zone",
6655 				      zname);
6656 			goto cleanup;
6657 		}
6658 	}
6659 
6660 	if (zone_is_catz) {
6661 		dns_zone_catz_enable(zone, view->catzs);
6662 	}
6663 
6664 	/*
6665 	 * If the zone contains a 'forwarders' statement, configure
6666 	 * selective forwarding.
6667 	 */
6668 	forwarders = NULL;
6669 	if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) {
6670 		forwardtype = NULL;
6671 		(void)cfg_map_get(zoptions, "forward", &forwardtype);
6672 		CHECK(configure_forward(config, view, origin, forwarders,
6673 					forwardtype));
6674 	}
6675 
6676 	/*
6677 	 * Stub and forward zones may also refer to delegation only points.
6678 	 */
6679 	only = NULL;
6680 	if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) {
6681 		if (cfg_obj_asboolean(only)) {
6682 			CHECK(dns_view_adddelegationonly(view, origin));
6683 		}
6684 	}
6685 
6686 	/*
6687 	 * Mark whether the zone was originally added at runtime or not
6688 	 */
6689 	dns_zone_setadded(zone, added);
6690 
6691 	/*
6692 	 * Determine if we need to set up inline signing.
6693 	 */
6694 	zone_maybe_inline = ((strcasecmp(ztypestr, "primary") == 0 ||
6695 			      strcasecmp(ztypestr, "master") == 0 ||
6696 			      strcasecmp(ztypestr, "secondary") == 0 ||
6697 			      strcasecmp(ztypestr, "slave") == 0));
6698 
6699 	if (zone_maybe_inline) {
6700 		inline_signing = named_zone_inlinesigning(
6701 			zone, zconfig, vconfig, config, aclconf);
6702 	}
6703 	if (inline_signing) {
6704 		dns_zone_getraw(zone, &raw);
6705 		if (raw == NULL) {
6706 			CHECK(dns_zone_create(&raw, mctx));
6707 			CHECK(dns_zone_setorigin(raw, origin));
6708 			dns_zone_setview(raw, view);
6709 			dns_zone_setstats(raw, named_g_server->zonestats);
6710 			CHECK(dns_zone_link(zone, raw));
6711 		}
6712 		if (cfg_map_get(zoptions, "ixfr-from-differences",
6713 				&ixfrfromdiffs) == ISC_R_SUCCESS)
6714 		{
6715 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6716 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6717 				      "zone '%s': 'ixfr-from-differences' is "
6718 				      "ignored for inline-signed zones",
6719 				      zname);
6720 		}
6721 	}
6722 
6723 	/*
6724 	 * Configure the zone.
6725 	 */
6726 	CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
6727 				   zone, raw));
6728 
6729 	/*
6730 	 * Add the zone to its view in the new view list.
6731 	 */
6732 	if (!modify) {
6733 		CHECK(dns_view_addzone(view, zone));
6734 	}
6735 
6736 	if (zone_is_catz) {
6737 		/*
6738 		 * force catz reload if the zone is loaded;
6739 		 * if it's not it'll get reloaded on zone load
6740 		 */
6741 		dns_db_t *db = NULL;
6742 
6743 		tresult = dns_zone_getdb(zone, &db);
6744 		if (tresult == ISC_R_SUCCESS) {
6745 			dns_catz_dbupdate_callback(db, view->catzs);
6746 			dns_db_detach(&db);
6747 		}
6748 	}
6749 
6750 	/*
6751 	 * Ensure that zone keys are reloaded on reconfig
6752 	 */
6753 	if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) {
6754 		dns_zone_rekey(zone, false);
6755 	}
6756 
6757 cleanup:
6758 	if (zone != NULL) {
6759 		dns_zone_detach(&zone);
6760 	}
6761 	if (raw != NULL) {
6762 		dns_zone_detach(&raw);
6763 	}
6764 	if (pview != NULL) {
6765 		dns_view_detach(&pview);
6766 	}
6767 
6768 	return (result);
6769 }
6770 
6771 /*
6772  * Configure built-in zone for storing managed-key data.
6773  */
6774 static isc_result_t
add_keydata_zone(dns_view_t * view,const char * directory,isc_mem_t * mctx)6775 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
6776 	isc_result_t result;
6777 	dns_view_t *pview = NULL;
6778 	dns_zone_t *zone = NULL;
6779 	dns_acl_t *none = NULL;
6780 	char filename[PATH_MAX];
6781 	bool defaultview;
6782 
6783 	REQUIRE(view != NULL);
6784 
6785 	/* See if we can re-use an existing keydata zone. */
6786 	result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6787 				   view->rdclass, &pview);
6788 	if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6789 		return (result);
6790 	}
6791 
6792 	if (pview != NULL) {
6793 		if (pview->managed_keys != NULL) {
6794 			dns_zone_attach(pview->managed_keys,
6795 					&view->managed_keys);
6796 			dns_zone_setview(pview->managed_keys, view);
6797 			dns_view_detach(&pview);
6798 			dns_zone_synckeyzone(view->managed_keys);
6799 			return (ISC_R_SUCCESS);
6800 		}
6801 
6802 		dns_view_detach(&pview);
6803 	}
6804 
6805 	/* No existing keydata zone was found; create one */
6806 	CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6807 	CHECK(dns_zone_setorigin(zone, dns_rootname));
6808 
6809 	defaultview = (strcmp(view->name, "_default") == 0);
6810 	CHECK(isc_file_sanitize(
6811 		directory, defaultview ? "managed-keys" : view->name,
6812 		defaultview ? "bind" : "mkeys", filename, sizeof(filename)));
6813 	CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text,
6814 			       &dns_master_style_default));
6815 
6816 	dns_zone_setview(zone, view);
6817 	dns_zone_settype(zone, dns_zone_key);
6818 	dns_zone_setclass(zone, view->rdclass);
6819 
6820 	CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6821 
6822 	CHECK(dns_acl_none(mctx, &none));
6823 	dns_zone_setqueryacl(zone, none);
6824 	dns_zone_setqueryonacl(zone, none);
6825 	dns_acl_detach(&none);
6826 
6827 	dns_zone_setdialup(zone, dns_dialuptype_no);
6828 	dns_zone_setnotifytype(zone, dns_notifytype_no);
6829 	dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
6830 	dns_zone_setjournalsize(zone, 0);
6831 
6832 	dns_zone_setstats(zone, named_g_server->zonestats);
6833 	CHECK(setquerystats(zone, mctx, dns_zonestat_none));
6834 
6835 	if (view->managed_keys != NULL) {
6836 		dns_zone_detach(&view->managed_keys);
6837 	}
6838 	dns_zone_attach(zone, &view->managed_keys);
6839 
6840 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6841 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6842 		      "set up managed keys zone for view %s, file '%s'",
6843 		      view->name, filename);
6844 
6845 cleanup:
6846 	if (zone != NULL) {
6847 		dns_zone_detach(&zone);
6848 	}
6849 	if (none != NULL) {
6850 		dns_acl_detach(&none);
6851 	}
6852 
6853 	return (result);
6854 }
6855 
6856 /*
6857  * Configure a single server quota.
6858  */
6859 static void
configure_server_quota(const cfg_obj_t ** maps,const char * name,isc_quota_t * quota)6860 configure_server_quota(const cfg_obj_t **maps, const char *name,
6861 		       isc_quota_t *quota) {
6862 	const cfg_obj_t *obj = NULL;
6863 	isc_result_t result;
6864 
6865 	result = named_config_get(maps, name, &obj);
6866 	INSIST(result == ISC_R_SUCCESS);
6867 	isc_quota_max(quota, cfg_obj_asuint32(obj));
6868 }
6869 
6870 /*
6871  * This function is called as soon as the 'directory' statement has been
6872  * parsed.  This can be extended to support other options if necessary.
6873  */
6874 static isc_result_t
directory_callback(const char * clausename,const cfg_obj_t * obj,void * arg)6875 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
6876 	isc_result_t result;
6877 	const char *directory;
6878 
6879 	REQUIRE(strcasecmp("directory", clausename) == 0);
6880 
6881 	UNUSED(arg);
6882 	UNUSED(clausename);
6883 
6884 	/*
6885 	 * Change directory.
6886 	 */
6887 	directory = cfg_obj_asstring(obj);
6888 
6889 	if (!isc_file_ischdiridempotent(directory)) {
6890 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
6891 			    "option 'directory' contains relative path '%s'",
6892 			    directory);
6893 	}
6894 
6895 	if (!isc_file_isdirwritable(directory)) {
6896 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6897 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6898 			      "directory '%s' is not writable", directory);
6899 		return (ISC_R_NOPERM);
6900 	}
6901 
6902 	result = isc_dir_chdir(directory);
6903 	if (result != ISC_R_SUCCESS) {
6904 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
6905 			    "change directory to '%s' failed: %s", directory,
6906 			    isc_result_totext(result));
6907 		return (result);
6908 	}
6909 
6910 	return (ISC_R_SUCCESS);
6911 }
6912 
6913 /*
6914  * This event callback is invoked to do periodic network interface
6915  * scanning.
6916  */
6917 
6918 static void
interface_timer_tick(isc_task_t * task,isc_event_t * event)6919 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
6920 	named_server_t *server = (named_server_t *)event->ev_arg;
6921 	INSIST(task == server->task);
6922 	UNUSED(task);
6923 
6924 	isc_event_free(&event);
6925 	ns_interfacemgr_scan(server->interfacemgr, false);
6926 }
6927 
6928 static void
heartbeat_timer_tick(isc_task_t * task,isc_event_t * event)6929 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
6930 	named_server_t *server = (named_server_t *)event->ev_arg;
6931 	dns_view_t *view;
6932 
6933 	UNUSED(task);
6934 	isc_event_free(&event);
6935 	view = ISC_LIST_HEAD(server->viewlist);
6936 	while (view != NULL) {
6937 		dns_view_dialup(view);
6938 		view = ISC_LIST_NEXT(view, link);
6939 	}
6940 }
6941 
6942 typedef struct {
6943 	isc_mem_t *mctx;
6944 	isc_task_t *task;
6945 	dns_fetch_t *fetch;
6946 	dns_view_t *view;
6947 	dns_fixedname_t tatname;
6948 	dns_fixedname_t keyname;
6949 	dns_rdataset_t rdataset;
6950 	dns_rdataset_t sigrdataset;
6951 } ns_tat_t;
6952 
6953 static int
cid(const void * a,const void * b)6954 cid(const void *a, const void *b) {
6955 	const uint16_t ida = *(const uint16_t *)a;
6956 	const uint16_t idb = *(const uint16_t *)b;
6957 	if (ida < idb) {
6958 		return (-1);
6959 	} else if (ida > idb) {
6960 		return (1);
6961 	} else {
6962 		return (0);
6963 	}
6964 }
6965 
6966 static void
tat_done(isc_task_t * task,isc_event_t * event)6967 tat_done(isc_task_t *task, isc_event_t *event) {
6968 	dns_fetchevent_t *devent;
6969 	ns_tat_t *tat;
6970 
6971 	INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE);
6972 	INSIST(event->ev_arg != NULL);
6973 
6974 	UNUSED(task);
6975 
6976 	tat = event->ev_arg;
6977 	devent = (dns_fetchevent_t *)event;
6978 
6979 	/* Free resources which are not of interest */
6980 	if (devent->node != NULL) {
6981 		dns_db_detachnode(devent->db, &devent->node);
6982 	}
6983 	if (devent->db != NULL) {
6984 		dns_db_detach(&devent->db);
6985 	}
6986 	isc_event_free(&event);
6987 	dns_resolver_destroyfetch(&tat->fetch);
6988 	if (dns_rdataset_isassociated(&tat->rdataset)) {
6989 		dns_rdataset_disassociate(&tat->rdataset);
6990 	}
6991 	if (dns_rdataset_isassociated(&tat->sigrdataset)) {
6992 		dns_rdataset_disassociate(&tat->sigrdataset);
6993 	}
6994 	dns_view_detach(&tat->view);
6995 	isc_task_detach(&tat->task);
6996 	isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
6997 }
6998 
6999 struct dotat_arg {
7000 	dns_view_t *view;
7001 	isc_task_t *task;
7002 };
7003 
7004 /*%
7005  * Prepare the QNAME for the TAT query to be sent by processing the trust
7006  * anchors present at 'keynode' of 'keytable'.  Store the result in 'dst' and
7007  * the domain name which 'keynode' is associated with in 'origin'.
7008  *
7009  * A maximum of 12 key IDs can be reported in a single TAT query due to the
7010  * 63-octet length limit for any single label in a domain name.  If there are
7011  * more than 12 keys configured at 'keynode', only the first 12 will be
7012  * reported in the TAT query.
7013  */
7014 static isc_result_t
get_tat_qname(dns_name_t * target,dns_name_t * keyname,dns_keynode_t * keynode)7015 get_tat_qname(dns_name_t *target, dns_name_t *keyname, dns_keynode_t *keynode) {
7016 	dns_rdataset_t dsset;
7017 	unsigned int i, n = 0;
7018 	uint16_t ids[12];
7019 	isc_textregion_t r;
7020 	char label[64];
7021 	int m;
7022 
7023 	dns_rdataset_init(&dsset);
7024 	if (dns_keynode_dsset(keynode, &dsset)) {
7025 		isc_result_t result;
7026 
7027 		for (result = dns_rdataset_first(&dsset);
7028 		     result == ISC_R_SUCCESS;
7029 		     result = dns_rdataset_next(&dsset))
7030 		{
7031 			dns_rdata_t rdata = DNS_RDATA_INIT;
7032 			dns_rdata_ds_t ds;
7033 
7034 			dns_rdata_reset(&rdata);
7035 			dns_rdataset_current(&dsset, &rdata);
7036 			result = dns_rdata_tostruct(&rdata, &ds, NULL);
7037 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
7038 			if (n < (sizeof(ids) / sizeof(ids[0]))) {
7039 				ids[n] = ds.key_tag;
7040 				n++;
7041 			}
7042 		}
7043 		dns_rdataset_disassociate(&dsset);
7044 	}
7045 
7046 	if (n == 0) {
7047 		return (DNS_R_EMPTYNAME);
7048 	}
7049 
7050 	if (n > 1) {
7051 		qsort(ids, n, sizeof(ids[0]), cid);
7052 	}
7053 
7054 	/*
7055 	 * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
7056 	 * of the keyid.
7057 	 */
7058 	label[0] = 0;
7059 	r.base = label;
7060 	r.length = sizeof(label);
7061 	m = snprintf(r.base, r.length, "_ta");
7062 	if (m < 0 || (unsigned)m > r.length) {
7063 		return (ISC_R_FAILURE);
7064 	}
7065 	isc_textregion_consume(&r, m);
7066 	for (i = 0; i < n; i++) {
7067 		m = snprintf(r.base, r.length, "-%04x", ids[i]);
7068 		if (m < 0 || (unsigned)m > r.length) {
7069 			return (ISC_R_FAILURE);
7070 		}
7071 		isc_textregion_consume(&r, m);
7072 	}
7073 
7074 	return (dns_name_fromstring2(target, label, keyname, 0, NULL));
7075 }
7076 
7077 static void
tat_send(isc_task_t * task,isc_event_t * event)7078 tat_send(isc_task_t *task, isc_event_t *event) {
7079 	ns_tat_t *tat;
7080 	char namebuf[DNS_NAME_FORMATSIZE];
7081 	dns_fixedname_t fdomain;
7082 	dns_name_t *domain;
7083 	dns_rdataset_t nameservers;
7084 	isc_result_t result;
7085 	dns_name_t *keyname;
7086 	dns_name_t *tatname;
7087 
7088 	INSIST(event != NULL && event->ev_type == NAMED_EVENT_TATSEND);
7089 	INSIST(event->ev_arg != NULL);
7090 
7091 	UNUSED(task);
7092 
7093 	tat = event->ev_arg;
7094 
7095 	keyname = dns_fixedname_name(&tat->keyname);
7096 	tatname = dns_fixedname_name(&tat->tatname);
7097 
7098 	dns_name_format(tatname, namebuf, sizeof(namebuf));
7099 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7100 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7101 		      "%s: sending trust-anchor-telemetry query '%s/NULL'",
7102 		      tat->view->name, namebuf);
7103 
7104 	/*
7105 	 * TAT queries should be sent to the authoritative servers for a given
7106 	 * zone.  If this function is called for a keytable node corresponding
7107 	 * to a locally served zone, calling dns_resolver_createfetch() with
7108 	 * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be
7109 	 * resolved locally, without sending any TAT queries upstream.
7110 	 *
7111 	 * Work around this issue by calling dns_view_findzonecut() first.  If
7112 	 * the zone is served locally, the NS RRset for the given domain name
7113 	 * will be retrieved from local data; if it is not, the deepest zone
7114 	 * cut we have for it will be retrieved from cache.  In either case,
7115 	 * passing the results to dns_resolver_createfetch() will prevent it
7116 	 * from returning NXDOMAIN for 'tatname' while still allowing it to
7117 	 * chase down any potential delegations returned by upstream servers in
7118 	 * order to eventually find the destination host to send the TAT query
7119 	 * to.
7120 	 *
7121 	 * After the dns_view_findzonecut() call, 'domain' will hold the
7122 	 * deepest zone cut we can find for 'keyname' while 'nameservers' will
7123 	 * hold the NS RRset at that zone cut.
7124 	 */
7125 	domain = dns_fixedname_initname(&fdomain);
7126 	dns_rdataset_init(&nameservers);
7127 	result = dns_view_findzonecut(tat->view, keyname, domain, NULL, 0, 0,
7128 				      true, true, &nameservers, NULL);
7129 	if (result == ISC_R_SUCCESS) {
7130 		result = dns_resolver_createfetch(
7131 			tat->view->resolver, tatname, dns_rdatatype_null,
7132 			domain, &nameservers, NULL, NULL, 0, 0, 0, NULL,
7133 			tat->task, tat_done, tat, &tat->rdataset,
7134 			&tat->sigrdataset, &tat->fetch);
7135 	}
7136 
7137 	/*
7138 	 * 'domain' holds the dns_name_t pointer inside a dst_key_t structure.
7139 	 * dns_resolver_createfetch() creates its own copy of 'domain' if it
7140 	 * succeeds.  Thus, 'domain' is not freed here.
7141 	 *
7142 	 * Even if dns_view_findzonecut() returned something else than
7143 	 * ISC_R_SUCCESS, it still could have associated 'nameservers'.
7144 	 * dns_resolver_createfetch() creates its own copy of 'nameservers' if
7145 	 * it succeeds.  Thus, we need to check whether 'nameservers' is
7146 	 * associated and release it if it is.
7147 	 */
7148 	if (dns_rdataset_isassociated(&nameservers)) {
7149 		dns_rdataset_disassociate(&nameservers);
7150 	}
7151 
7152 	if (result != ISC_R_SUCCESS) {
7153 		dns_view_detach(&tat->view);
7154 		isc_task_detach(&tat->task);
7155 		isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
7156 	}
7157 	isc_event_free(&event);
7158 }
7159 
7160 static void
dotat(dns_keytable_t * keytable,dns_keynode_t * keynode,dns_name_t * keyname,void * arg)7161 dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, dns_name_t *keyname,
7162       void *arg) {
7163 	struct dotat_arg *dotat_arg = arg;
7164 	isc_result_t result;
7165 	dns_view_t *view;
7166 	isc_task_t *task;
7167 	ns_tat_t *tat;
7168 	isc_event_t *event;
7169 
7170 	REQUIRE(keytable != NULL);
7171 	REQUIRE(keynode != NULL);
7172 	REQUIRE(dotat_arg != NULL);
7173 
7174 	view = dotat_arg->view;
7175 	task = dotat_arg->task;
7176 
7177 	tat = isc_mem_get(dotat_arg->view->mctx, sizeof(*tat));
7178 
7179 	tat->fetch = NULL;
7180 	tat->mctx = NULL;
7181 	tat->task = NULL;
7182 	tat->view = NULL;
7183 	dns_rdataset_init(&tat->rdataset);
7184 	dns_rdataset_init(&tat->sigrdataset);
7185 	dns_name_copy(keyname, dns_fixedname_initname(&tat->keyname));
7186 	result = get_tat_qname(dns_fixedname_initname(&tat->tatname), keyname,
7187 			       keynode);
7188 	if (result != ISC_R_SUCCESS) {
7189 		isc_mem_put(dotat_arg->view->mctx, tat, sizeof(*tat));
7190 		return;
7191 	}
7192 	isc_mem_attach(dotat_arg->view->mctx, &tat->mctx);
7193 	isc_task_attach(task, &tat->task);
7194 	dns_view_attach(view, &tat->view);
7195 
7196 	/*
7197 	 * We don't want to be holding the keytable lock when calling
7198 	 * dns_view_findzonecut() as it creates a lock order loop so
7199 	 * call dns_view_findzonecut() in a event handler.
7200 	 *
7201 	 * zone->lock (dns_zone_setviewcommit) while holding view->lock
7202 	 * (dns_view_setviewcommit)
7203 	 *
7204 	 * keytable->lock (dns_keytable_find) while holding zone->lock
7205 	 * (zone_asyncload)
7206 	 *
7207 	 * view->lock (dns_view_findzonecut) while holding keytable->lock
7208 	 * (dns_keytable_forall)
7209 	 */
7210 	event = isc_event_allocate(tat->mctx, keytable, NAMED_EVENT_TATSEND,
7211 				   tat_send, tat, sizeof(isc_event_t));
7212 	isc_task_send(task, &event);
7213 }
7214 
7215 static void
tat_timer_tick(isc_task_t * task,isc_event_t * event)7216 tat_timer_tick(isc_task_t *task, isc_event_t *event) {
7217 	isc_result_t result;
7218 	named_server_t *server = (named_server_t *)event->ev_arg;
7219 	struct dotat_arg arg;
7220 	dns_view_t *view;
7221 	dns_keytable_t *secroots = NULL;
7222 
7223 	isc_event_free(&event);
7224 
7225 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
7226 	     view = ISC_LIST_NEXT(view, link))
7227 	{
7228 		if (!view->trust_anchor_telemetry || !view->enablevalidation) {
7229 			continue;
7230 		}
7231 
7232 		result = dns_view_getsecroots(view, &secroots);
7233 		if (result != ISC_R_SUCCESS) {
7234 			continue;
7235 		}
7236 
7237 		arg.view = view;
7238 		arg.task = task;
7239 		(void)dns_keytable_forall(secroots, dotat, &arg);
7240 		dns_keytable_detach(&secroots);
7241 	}
7242 }
7243 
7244 static void
pps_timer_tick(isc_task_t * task,isc_event_t * event)7245 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
7246 	static unsigned int oldrequests = 0;
7247 	unsigned int requests = atomic_load_relaxed(&ns_client_requests);
7248 
7249 	UNUSED(task);
7250 	isc_event_free(&event);
7251 
7252 	/*
7253 	 * Don't worry about wrapping as the overflow result will be right.
7254 	 */
7255 	dns_pps = (requests - oldrequests) / 1200;
7256 	oldrequests = requests;
7257 }
7258 
7259 /*
7260  * Replace the current value of '*field', a dynamically allocated
7261  * string or NULL, with a dynamically allocated copy of the
7262  * null-terminated string pointed to by 'value', or NULL.
7263  */
7264 static isc_result_t
setstring(named_server_t * server,char ** field,const char * value)7265 setstring(named_server_t *server, char **field, const char *value) {
7266 	char *copy;
7267 
7268 	if (value != NULL) {
7269 		copy = isc_mem_strdup(server->mctx, value);
7270 	} else {
7271 		copy = NULL;
7272 	}
7273 
7274 	if (*field != NULL) {
7275 		isc_mem_free(server->mctx, *field);
7276 	}
7277 
7278 	*field = copy;
7279 	return (ISC_R_SUCCESS);
7280 }
7281 
7282 /*
7283  * Replace the current value of '*field', a dynamically allocated
7284  * string or NULL, with another dynamically allocated string
7285  * or NULL if whether 'obj' is a string or void value, respectively.
7286  */
7287 static isc_result_t
setoptstring(named_server_t * server,char ** field,const cfg_obj_t * obj)7288 setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) {
7289 	if (cfg_obj_isvoid(obj)) {
7290 		return (setstring(server, field, NULL));
7291 	} else {
7292 		return (setstring(server, field, cfg_obj_asstring(obj)));
7293 	}
7294 }
7295 
7296 static void
set_limit(const cfg_obj_t ** maps,const char * configname,const char * description,isc_resource_t resourceid,isc_resourcevalue_t defaultvalue)7297 set_limit(const cfg_obj_t **maps, const char *configname,
7298 	  const char *description, isc_resource_t resourceid,
7299 	  isc_resourcevalue_t defaultvalue) {
7300 	const cfg_obj_t *obj = NULL;
7301 	const char *resource;
7302 	isc_resourcevalue_t value;
7303 	isc_result_t result;
7304 
7305 	if (named_config_get(maps, configname, &obj) != ISC_R_SUCCESS) {
7306 		return;
7307 	}
7308 
7309 	if (cfg_obj_isstring(obj)) {
7310 		resource = cfg_obj_asstring(obj);
7311 		if (strcasecmp(resource, "unlimited") == 0) {
7312 			value = ISC_RESOURCE_UNLIMITED;
7313 		} else {
7314 			INSIST(strcasecmp(resource, "default") == 0);
7315 			value = defaultvalue;
7316 		}
7317 	} else {
7318 		value = cfg_obj_asuint64(obj);
7319 	}
7320 
7321 	result = isc_resource_setlimit(resourceid, value);
7322 	isc_log_write(
7323 		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7324 		result == ISC_R_SUCCESS ? ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
7325 		"set maximum %s to %" PRIu64 ": %s", description, value,
7326 		isc_result_totext(result));
7327 }
7328 
7329 #define SETLIMIT(cfgvar, resource, description)                       \
7330 	set_limit(maps, cfgvar, description, isc_resource_##resource, \
7331 		  named_g_init##resource)
7332 
7333 static void
set_limits(const cfg_obj_t ** maps)7334 set_limits(const cfg_obj_t **maps) {
7335 	SETLIMIT("stacksize", stacksize, "stack size");
7336 	SETLIMIT("datasize", datasize, "data size");
7337 	SETLIMIT("coresize", coresize, "core size");
7338 	SETLIMIT("files", openfiles, "open files");
7339 }
7340 
7341 static void
portset_fromconf(isc_portset_t * portset,const cfg_obj_t * ports,bool positive)7342 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
7343 		 bool positive) {
7344 	const cfg_listelt_t *element;
7345 
7346 	for (element = cfg_list_first(ports); element != NULL;
7347 	     element = cfg_list_next(element))
7348 	{
7349 		const cfg_obj_t *obj = cfg_listelt_value(element);
7350 
7351 		if (cfg_obj_isuint32(obj)) {
7352 			in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
7353 
7354 			if (positive) {
7355 				isc_portset_add(portset, port);
7356 			} else {
7357 				isc_portset_remove(portset, port);
7358 			}
7359 		} else {
7360 			const cfg_obj_t *obj_loport, *obj_hiport;
7361 			in_port_t loport, hiport;
7362 
7363 			obj_loport = cfg_tuple_get(obj, "loport");
7364 			loport = (in_port_t)cfg_obj_asuint32(obj_loport);
7365 			obj_hiport = cfg_tuple_get(obj, "hiport");
7366 			hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
7367 
7368 			if (positive) {
7369 				isc_portset_addrange(portset, loport, hiport);
7370 			} else {
7371 				isc_portset_removerange(portset, loport,
7372 							hiport);
7373 			}
7374 		}
7375 	}
7376 }
7377 
7378 static isc_result_t
removed(dns_zone_t * zone,void * uap)7379 removed(dns_zone_t *zone, void *uap) {
7380 	if (dns_zone_getview(zone) != uap) {
7381 		return (ISC_R_SUCCESS);
7382 	}
7383 
7384 	dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed",
7385 		     dns_zonetype_name(dns_zone_gettype(zone)));
7386 	return (ISC_R_SUCCESS);
7387 }
7388 
7389 static void
cleanup_session_key(named_server_t * server,isc_mem_t * mctx)7390 cleanup_session_key(named_server_t *server, isc_mem_t *mctx) {
7391 	if (server->session_keyfile != NULL) {
7392 		isc_file_remove(server->session_keyfile);
7393 		isc_mem_free(mctx, server->session_keyfile);
7394 		server->session_keyfile = NULL;
7395 	}
7396 
7397 	if (server->session_keyname != NULL) {
7398 		if (dns_name_dynamic(server->session_keyname)) {
7399 			dns_name_free(server->session_keyname, mctx);
7400 		}
7401 		isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
7402 		server->session_keyname = NULL;
7403 	}
7404 
7405 	if (server->sessionkey != NULL) {
7406 		dns_tsigkey_detach(&server->sessionkey);
7407 	}
7408 
7409 	server->session_keyalg = DST_ALG_UNKNOWN;
7410 	server->session_keybits = 0;
7411 }
7412 
7413 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)7414 generate_session_key(const char *filename, const char *keynamestr,
7415 		     const dns_name_t *keyname, const char *algstr,
7416 		     const dns_name_t *algname, unsigned int algtype,
7417 		     uint16_t bits, isc_mem_t *mctx, bool first_time,
7418 		     dns_tsigkey_t **tsigkeyp) {
7419 	isc_result_t result = ISC_R_SUCCESS;
7420 	dst_key_t *key = NULL;
7421 	isc_buffer_t key_txtbuffer;
7422 	isc_buffer_t key_rawbuffer;
7423 	char key_txtsecret[256];
7424 	char key_rawsecret[64];
7425 	isc_region_t key_rawregion;
7426 	isc_stdtime_t now;
7427 	dns_tsigkey_t *tsigkey = NULL;
7428 	FILE *fp = NULL;
7429 
7430 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7431 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7432 		      "generating session key for dynamic DNS");
7433 
7434 	/* generate key */
7435 	result = dst_key_generate(keyname, algtype, bits, 1, 0,
7436 				  DNS_KEYPROTO_ANY, dns_rdataclass_in, mctx,
7437 				  &key, NULL);
7438 	if (result != ISC_R_SUCCESS) {
7439 		return (result);
7440 	}
7441 
7442 	/*
7443 	 * Dump the key to the buffer for later use.  Should be done before
7444 	 * we transfer the ownership of key to tsigkey.
7445 	 */
7446 	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
7447 	CHECK(dst_key_tobuffer(key, &key_rawbuffer));
7448 
7449 	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
7450 	isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
7451 	CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
7452 
7453 	/* Store the key in tsigkey. */
7454 	isc_stdtime_get(&now);
7455 	CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key, false,
7456 					NULL, now, now, mctx, NULL, &tsigkey));
7457 
7458 	/* Dump the key to the key file. */
7459 	fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time);
7460 	if (fp == NULL) {
7461 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7462 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7463 			      "could not create %s", filename);
7464 		result = ISC_R_NOPERM;
7465 		goto cleanup;
7466 	}
7467 
7468 	fprintf(fp,
7469 		"key \"%s\" {\n"
7470 		"\talgorithm %s;\n"
7471 		"\tsecret \"%.*s\";\n};\n",
7472 		keynamestr, algstr, (int)isc_buffer_usedlength(&key_txtbuffer),
7473 		(char *)isc_buffer_base(&key_txtbuffer));
7474 
7475 	CHECK(isc_stdio_flush(fp));
7476 	result = isc_stdio_close(fp);
7477 	fp = NULL;
7478 	if (result != ISC_R_SUCCESS) {
7479 		goto cleanup;
7480 	}
7481 
7482 	dst_key_free(&key);
7483 
7484 	*tsigkeyp = tsigkey;
7485 
7486 	return (ISC_R_SUCCESS);
7487 
7488 cleanup:
7489 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7490 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7491 		      "failed to generate session key "
7492 		      "for dynamic DNS: %s",
7493 		      isc_result_totext(result));
7494 	if (fp != NULL) {
7495 		(void)isc_stdio_close(fp);
7496 		(void)isc_file_remove(filename);
7497 	}
7498 	if (tsigkey != NULL) {
7499 		dns_tsigkey_detach(&tsigkey);
7500 	}
7501 	if (key != NULL) {
7502 		dst_key_free(&key);
7503 	}
7504 
7505 	return (result);
7506 }
7507 
7508 static isc_result_t
configure_session_key(const cfg_obj_t ** maps,named_server_t * server,isc_mem_t * mctx,bool first_time)7509 configure_session_key(const cfg_obj_t **maps, named_server_t *server,
7510 		      isc_mem_t *mctx, bool first_time) {
7511 	const char *keyfile, *keynamestr, *algstr;
7512 	unsigned int algtype;
7513 	dns_fixedname_t fname;
7514 	dns_name_t *keyname;
7515 	const dns_name_t *algname;
7516 	isc_buffer_t buffer;
7517 	uint16_t bits;
7518 	const cfg_obj_t *obj;
7519 	bool need_deleteold = false;
7520 	bool need_createnew = false;
7521 	isc_result_t result;
7522 
7523 	obj = NULL;
7524 	result = named_config_get(maps, "session-keyfile", &obj);
7525 	if (result == ISC_R_SUCCESS) {
7526 		if (cfg_obj_isvoid(obj)) {
7527 			keyfile = NULL; /* disable it */
7528 		} else {
7529 			keyfile = cfg_obj_asstring(obj);
7530 		}
7531 	} else {
7532 		keyfile = named_g_defaultsessionkeyfile;
7533 	}
7534 
7535 	obj = NULL;
7536 	result = named_config_get(maps, "session-keyname", &obj);
7537 	INSIST(result == ISC_R_SUCCESS);
7538 	keynamestr = cfg_obj_asstring(obj);
7539 	isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
7540 	isc_buffer_add(&buffer, strlen(keynamestr));
7541 	keyname = dns_fixedname_initname(&fname);
7542 	result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
7543 	if (result != ISC_R_SUCCESS) {
7544 		return (result);
7545 	}
7546 
7547 	obj = NULL;
7548 	result = named_config_get(maps, "session-keyalg", &obj);
7549 	INSIST(result == ISC_R_SUCCESS);
7550 	algstr = cfg_obj_asstring(obj);
7551 	algname = NULL;
7552 	result = named_config_getkeyalgorithm2(algstr, &algname, &algtype,
7553 					       &bits);
7554 	if (result != ISC_R_SUCCESS) {
7555 		const char *s = " (keeping current key)";
7556 
7557 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7558 			    "session-keyalg: "
7559 			    "unsupported or unknown algorithm '%s'%s",
7560 			    algstr, server->session_keyfile != NULL ? s : "");
7561 		return (result);
7562 	}
7563 
7564 	/* See if we need to (re)generate a new key. */
7565 	if (keyfile == NULL) {
7566 		if (server->session_keyfile != NULL) {
7567 			need_deleteold = true;
7568 		}
7569 	} else if (server->session_keyfile == NULL) {
7570 		need_createnew = true;
7571 	} else if (strcmp(keyfile, server->session_keyfile) != 0 ||
7572 		   !dns_name_equal(server->session_keyname, keyname) ||
7573 		   server->session_keyalg != algtype ||
7574 		   server->session_keybits != bits)
7575 	{
7576 		need_deleteold = true;
7577 		need_createnew = true;
7578 	}
7579 
7580 	if (need_deleteold) {
7581 		INSIST(server->session_keyfile != NULL);
7582 		INSIST(server->session_keyname != NULL);
7583 		INSIST(server->sessionkey != NULL);
7584 
7585 		cleanup_session_key(server, mctx);
7586 	}
7587 
7588 	if (need_createnew) {
7589 		INSIST(server->sessionkey == NULL);
7590 		INSIST(server->session_keyfile == NULL);
7591 		INSIST(server->session_keyname == NULL);
7592 		INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
7593 		INSIST(server->session_keybits == 0);
7594 
7595 		server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
7596 		dns_name_init(server->session_keyname, NULL);
7597 		dns_name_dup(keyname, mctx, server->session_keyname);
7598 
7599 		server->session_keyfile = isc_mem_strdup(mctx, keyfile);
7600 
7601 		server->session_keyalg = algtype;
7602 		server->session_keybits = bits;
7603 
7604 		CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
7605 					   algname, algtype, bits, mctx,
7606 					   first_time, &server->sessionkey));
7607 	}
7608 
7609 	return (result);
7610 
7611 cleanup:
7612 	cleanup_session_key(server, mctx);
7613 	return (result);
7614 }
7615 
7616 #ifndef HAVE_LMDB
7617 static isc_result_t
count_newzones(dns_view_t * view,ns_cfgctx_t * nzcfg,int * num_zonesp)7618 count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7619 	isc_result_t result;
7620 
7621 	/* The new zone file may not exist. That is OK. */
7622 	if (!isc_file_exists(view->new_zone_file)) {
7623 		*num_zonesp = 0;
7624 		return (ISC_R_SUCCESS);
7625 	}
7626 
7627 	/*
7628 	 * In the case of NZF files, we also parse the configuration in
7629 	 * the file at this stage.
7630 	 *
7631 	 * This may be called in multiple views, so we reset
7632 	 * the parser each time.
7633 	 */
7634 	cfg_parser_reset(named_g_addparser);
7635 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
7636 				&cfg_type_addzoneconf, &nzcfg->nzf_config);
7637 	if (result == ISC_R_SUCCESS) {
7638 		int num_zones;
7639 
7640 		num_zones = count_zones(nzcfg->nzf_config);
7641 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7642 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7643 			      "NZF file '%s' contains %d zones",
7644 			      view->new_zone_file, num_zones);
7645 		if (num_zonesp != NULL) {
7646 			*num_zonesp = num_zones;
7647 		}
7648 	} else {
7649 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7650 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7651 			      "Error parsing NZF file '%s': %s",
7652 			      view->new_zone_file, isc_result_totext(result));
7653 	}
7654 
7655 	return (result);
7656 }
7657 
7658 #else /* HAVE_LMDB */
7659 
7660 static isc_result_t
count_newzones(dns_view_t * view,ns_cfgctx_t * nzcfg,int * num_zonesp)7661 count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7662 	isc_result_t result;
7663 	int n;
7664 
7665 	UNUSED(nzcfg);
7666 
7667 	REQUIRE(num_zonesp != NULL);
7668 
7669 	LOCK(&view->new_zone_lock);
7670 
7671 	CHECK(migrate_nzf(view));
7672 
7673 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7674 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7675 		      "loading NZD zone count from '%s' "
7676 		      "for view '%s'",
7677 		      view->new_zone_db, view->name);
7678 
7679 	CHECK(nzd_count(view, &n));
7680 
7681 	*num_zonesp = n;
7682 
7683 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7684 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7685 		      "NZD database '%s' contains %d zones", view->new_zone_db,
7686 		      n);
7687 
7688 cleanup:
7689 	if (result != ISC_R_SUCCESS) {
7690 		*num_zonesp = 0;
7691 	}
7692 
7693 	UNLOCK(&view->new_zone_lock);
7694 
7695 	return (ISC_R_SUCCESS);
7696 }
7697 
7698 #endif /* HAVE_LMDB */
7699 
7700 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)7701 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7702 	       cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx,
7703 	       int *num_zones) {
7704 	isc_result_t result = ISC_R_SUCCESS;
7705 	bool allow = false;
7706 	ns_cfgctx_t *nzcfg = NULL;
7707 	const cfg_obj_t *maps[4];
7708 	const cfg_obj_t *options = NULL, *voptions = NULL;
7709 	const cfg_obj_t *nz = NULL;
7710 	const cfg_obj_t *nzdir = NULL;
7711 	const char *dir = NULL;
7712 	const cfg_obj_t *obj = NULL;
7713 	int i = 0;
7714 	uint64_t mapsize = 0ULL;
7715 
7716 	REQUIRE(config != NULL);
7717 
7718 	if (vconfig != NULL) {
7719 		voptions = cfg_tuple_get(vconfig, "options");
7720 	}
7721 	if (voptions != NULL) {
7722 		maps[i++] = voptions;
7723 	}
7724 	result = cfg_map_get(config, "options", &options);
7725 	if (result == ISC_R_SUCCESS) {
7726 		maps[i++] = options;
7727 	}
7728 	maps[i++] = named_g_defaults;
7729 	maps[i] = NULL;
7730 
7731 	result = named_config_get(maps, "allow-new-zones", &nz);
7732 	if (result == ISC_R_SUCCESS) {
7733 		allow = cfg_obj_asboolean(nz);
7734 	}
7735 	result = named_config_get(maps, "new-zones-directory", &nzdir);
7736 	if (result == ISC_R_SUCCESS) {
7737 		dir = cfg_obj_asstring(nzdir);
7738 		if (dir != NULL) {
7739 			result = isc_file_isdirectory(dir);
7740 		}
7741 		if (result != ISC_R_SUCCESS) {
7742 			isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
7743 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7744 				      "invalid new-zones-directory %s: %s", dir,
7745 				      isc_result_totext(result));
7746 			return (result);
7747 		}
7748 		if (!isc_file_isdirwritable(dir)) {
7749 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7750 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7751 				      "new-zones-directory '%s' "
7752 				      "is not writable",
7753 				      dir);
7754 			return (ISC_R_NOPERM);
7755 		}
7756 
7757 		dns_view_setnewzonedir(view, dir);
7758 	}
7759 
7760 #ifdef HAVE_LMDB
7761 	result = named_config_get(maps, "lmdb-mapsize", &obj);
7762 	if (result == ISC_R_SUCCESS && obj != NULL) {
7763 		mapsize = cfg_obj_asuint64(obj);
7764 		if (mapsize < (1ULL << 20)) { /* 1 megabyte */
7765 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7766 				    "'lmdb-mapsize "
7767 				    "%" PRId64 "' "
7768 				    "is too small",
7769 				    mapsize);
7770 			return (ISC_R_FAILURE);
7771 		} else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
7772 			cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7773 				    "'lmdb-mapsize "
7774 				    "%" PRId64 "' "
7775 				    "is too large",
7776 				    mapsize);
7777 			return (ISC_R_FAILURE);
7778 		}
7779 	}
7780 #else  /* ifdef HAVE_LMDB */
7781 	UNUSED(obj);
7782 #endif /* HAVE_LMDB */
7783 
7784 	/*
7785 	 * A non-empty catalog-zones statement implies allow-new-zones
7786 	 */
7787 	if (!allow) {
7788 		const cfg_obj_t *cz = NULL;
7789 		result = named_config_get(maps, "catalog-zones", &cz);
7790 		if (result == ISC_R_SUCCESS) {
7791 			const cfg_listelt_t *e =
7792 				cfg_list_first(cfg_tuple_get(cz, "zone list"));
7793 			if (e != NULL) {
7794 				allow = true;
7795 			}
7796 		}
7797 	}
7798 
7799 	if (!allow) {
7800 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7801 		if (num_zones != NULL) {
7802 			*num_zones = 0;
7803 		}
7804 		return (ISC_R_SUCCESS);
7805 	}
7806 
7807 	nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
7808 
7809 	/*
7810 	 * We attach the parser that was used for config as well
7811 	 * as the one that will be used for added zones, to avoid
7812 	 * a shutdown race later.
7813 	 */
7814 	memset(nzcfg, 0, sizeof(*nzcfg));
7815 	cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
7816 	cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
7817 	isc_mem_attach(view->mctx, &nzcfg->mctx);
7818 	cfg_aclconfctx_attach(actx, &nzcfg->actx);
7819 
7820 	result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy,
7821 				      mapsize);
7822 	if (result != ISC_R_SUCCESS) {
7823 		dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7824 		return (result);
7825 	}
7826 
7827 	cfg_obj_attach(config, &nzcfg->config);
7828 	if (vconfig != NULL) {
7829 		cfg_obj_attach(vconfig, &nzcfg->vconfig);
7830 	}
7831 
7832 	result = count_newzones(view, nzcfg, num_zones);
7833 	return (result);
7834 }
7835 
7836 static void
configure_zone_setviewcommit(isc_result_t result,const cfg_obj_t * zconfig,dns_view_t * view)7837 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
7838 			     dns_view_t *view) {
7839 	const char *zname;
7840 	dns_fixedname_t fixorigin;
7841 	dns_name_t *origin;
7842 	isc_result_t result2;
7843 	dns_view_t *pview = NULL;
7844 	dns_zone_t *zone = NULL;
7845 
7846 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
7847 	origin = dns_fixedname_initname(&fixorigin);
7848 
7849 	result2 = dns_name_fromstring(origin, zname, 0, NULL);
7850 	if (result2 != ISC_R_SUCCESS) {
7851 		return;
7852 	}
7853 
7854 	result2 = dns_viewlist_find(&named_g_server->viewlist, view->name,
7855 				    view->rdclass, &pview);
7856 	if (result2 != ISC_R_SUCCESS) {
7857 		return;
7858 	}
7859 
7860 	result2 = dns_view_findzone(pview, origin, &zone);
7861 	if (result2 != ISC_R_SUCCESS) {
7862 		dns_view_detach(&pview);
7863 		return;
7864 	}
7865 
7866 	if (result == ISC_R_SUCCESS) {
7867 		dns_zone_setviewcommit(zone);
7868 	} else {
7869 		dns_zone_setviewrevert(zone);
7870 	}
7871 
7872 	dns_zone_detach(&zone);
7873 	dns_view_detach(&pview);
7874 }
7875 
7876 #ifndef HAVE_LMDB
7877 
7878 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)7879 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7880 		   isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
7881 	isc_result_t result;
7882 	ns_cfgctx_t *nzctx;
7883 	const cfg_obj_t *zonelist;
7884 	const cfg_listelt_t *element;
7885 
7886 	nzctx = view->new_zone_config;
7887 	if (nzctx == NULL || nzctx->nzf_config == NULL) {
7888 		return (ISC_R_SUCCESS);
7889 	}
7890 
7891 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7892 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7893 		      "loading additional zones for view '%s'", view->name);
7894 
7895 	zonelist = NULL;
7896 	cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
7897 
7898 	for (element = cfg_list_first(zonelist); element != NULL;
7899 	     element = cfg_list_next(element))
7900 	{
7901 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
7902 		CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
7903 				     &named_g_server->viewlist,
7904 				     &named_g_server->kasplist, actx, true,
7905 				     false, false));
7906 	}
7907 
7908 	result = ISC_R_SUCCESS;
7909 
7910 cleanup:
7911 	for (element = cfg_list_first(zonelist); element != NULL;
7912 	     element = cfg_list_next(element))
7913 	{
7914 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
7915 		configure_zone_setviewcommit(result, zconfig, view);
7916 	}
7917 
7918 	return (result);
7919 }
7920 
7921 #else /* HAVE_LMDB */
7922 
7923 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)7924 data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text,
7925 	    cfg_obj_t **zoneconfig) {
7926 	isc_result_t result;
7927 	const char *zone_name;
7928 	size_t zone_name_len;
7929 	const char *zone_config;
7930 	size_t zone_config_len;
7931 	cfg_obj_t *zoneconf = NULL;
7932 	char bufname[DNS_NAME_FORMATSIZE];
7933 
7934 	REQUIRE(view != NULL);
7935 	REQUIRE(key != NULL);
7936 	REQUIRE(data != NULL);
7937 	REQUIRE(text != NULL);
7938 	REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
7939 
7940 	if (*text == NULL) {
7941 		isc_buffer_allocate(view->mctx, text, 256);
7942 	} else {
7943 		isc_buffer_clear(*text);
7944 	}
7945 
7946 	zone_name = (const char *)key->mv_data;
7947 	zone_name_len = key->mv_size;
7948 	INSIST(zone_name != NULL && zone_name_len > 0);
7949 
7950 	zone_config = (const char *)data->mv_data;
7951 	zone_config_len = data->mv_size;
7952 	INSIST(zone_config != NULL && zone_config_len > 0);
7953 
7954 	/* zone zonename { config; }; */
7955 	result = isc_buffer_reserve(text, 6 + zone_name_len + 2 +
7956 						  zone_config_len + 2);
7957 	if (result != ISC_R_SUCCESS) {
7958 		goto cleanup;
7959 	}
7960 
7961 	CHECK(putstr(text, "zone \""));
7962 	CHECK(putmem(text, (const void *)zone_name, zone_name_len));
7963 	CHECK(putstr(text, "\" "));
7964 	CHECK(putmem(text, (const void *)zone_config, zone_config_len));
7965 	CHECK(putstr(text, ";\n"));
7966 
7967 	snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len,
7968 		 zone_name);
7969 
7970 	cfg_parser_reset(named_g_addparser);
7971 	result = cfg_parse_buffer(named_g_addparser, *text, bufname, 0,
7972 				  &cfg_type_addzoneconf, 0, &zoneconf);
7973 	if (result != ISC_R_SUCCESS) {
7974 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7975 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7976 			      "parsing config for zone '%.*s' in "
7977 			      "NZD database '%s' failed",
7978 			      (int)zone_name_len, zone_name, view->new_zone_db);
7979 		goto cleanup;
7980 	}
7981 
7982 	*zoneconfig = zoneconf;
7983 	zoneconf = NULL;
7984 	result = ISC_R_SUCCESS;
7985 
7986 cleanup:
7987 	if (zoneconf != NULL) {
7988 		cfg_obj_destroy(named_g_addparser, &zoneconf);
7989 	}
7990 
7991 	return (result);
7992 }
7993 
7994 /*%
7995  * Prototype for a callback which can be used with for_all_newzone_cfgs().
7996  */
7997 typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
7998 					 cfg_obj_t *config, cfg_obj_t *vconfig,
7999 					 isc_mem_t *mctx, dns_view_t *view,
8000 					 cfg_aclconfctx_t *actx);
8001 
8002 /*%
8003  * For each zone found in a NZD opened by the caller, create an object
8004  * representing its configuration and invoke "callback" with the created
8005  * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all
8006  * these are non-global variables required to invoke configure_zone()).
8007  * Immediately interrupt processing if an error is encountered while
8008  * transforming NZD data into a zone configuration object or if "callback"
8009  * returns an error.
8010  *
8011  * Caller must hold 'view->new_zone_lock'.
8012  */
8013 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)8014 for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
8015 		     cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8016 		     cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi) {
8017 	const cfg_obj_t *zconfig, *zlist;
8018 	isc_result_t result = ISC_R_SUCCESS;
8019 	cfg_obj_t *zconfigobj = NULL;
8020 	isc_buffer_t *text = NULL;
8021 	MDB_cursor *cursor = NULL;
8022 	MDB_val data, key;
8023 	int status;
8024 
8025 	status = mdb_cursor_open(txn, dbi, &cursor);
8026 	if (status != MDB_SUCCESS) {
8027 		return (ISC_R_FAILURE);
8028 	}
8029 
8030 	for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
8031 	     status == MDB_SUCCESS;
8032 	     status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
8033 	{
8034 		/*
8035 		 * Create a configuration object from data fetched from NZD.
8036 		 */
8037 		result = data_to_cfg(view, &key, &data, &text, &zconfigobj);
8038 		if (result != ISC_R_SUCCESS) {
8039 			break;
8040 		}
8041 
8042 		/*
8043 		 * Extract zone configuration from configuration object.
8044 		 */
8045 		zlist = NULL;
8046 		result = cfg_map_get(zconfigobj, "zone", &zlist);
8047 		if (result != ISC_R_SUCCESS) {
8048 			break;
8049 		} else if (!cfg_obj_islist(zlist)) {
8050 			result = ISC_R_FAILURE;
8051 			break;
8052 		}
8053 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
8054 
8055 		/*
8056 		 * Invoke callback.
8057 		 */
8058 		result = callback(zconfig, config, vconfig, mctx, view, actx);
8059 		if (result != ISC_R_SUCCESS) {
8060 			break;
8061 		}
8062 
8063 		/*
8064 		 * Destroy the configuration object created in this iteration.
8065 		 */
8066 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8067 	}
8068 
8069 	if (text != NULL) {
8070 		isc_buffer_free(&text);
8071 	}
8072 	if (zconfigobj != NULL) {
8073 		cfg_obj_destroy(named_g_addparser, &zconfigobj);
8074 	}
8075 	mdb_cursor_close(cursor);
8076 
8077 	return (result);
8078 }
8079 
8080 /*%
8081  * Attempt to configure a zone found in NZD and return the result.
8082  */
8083 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)8084 configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
8085 		  cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8086 		  cfg_aclconfctx_t *actx) {
8087 	return (configure_zone(
8088 		config, zconfig, vconfig, mctx, view, &named_g_server->viewlist,
8089 		&named_g_server->kasplist, actx, true, false, false));
8090 }
8091 
8092 /*%
8093  * Revert new view assignment for a zone found in NZD.
8094  */
8095 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)8096 configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config,
8097 			 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8098 			 cfg_aclconfctx_t *actx) {
8099 	UNUSED(config);
8100 	UNUSED(vconfig);
8101 	UNUSED(mctx);
8102 	UNUSED(actx);
8103 
8104 	configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view);
8105 
8106 	return (ISC_R_SUCCESS);
8107 }
8108 
8109 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)8110 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
8111 		   isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
8112 	isc_result_t result;
8113 	MDB_txn *txn = NULL;
8114 	MDB_dbi dbi;
8115 
8116 	if (view->new_zone_config == NULL) {
8117 		return (ISC_R_SUCCESS);
8118 	}
8119 
8120 	LOCK(&view->new_zone_lock);
8121 
8122 	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
8123 	if (result != ISC_R_SUCCESS) {
8124 		UNLOCK(&view->new_zone_lock);
8125 		return (ISC_R_SUCCESS);
8126 	}
8127 
8128 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8129 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8130 		      "loading NZD configs from '%s' "
8131 		      "for view '%s'",
8132 		      view->new_zone_db, view->name);
8133 
8134 	result = for_all_newzone_cfgs(configure_newzone, config, vconfig, mctx,
8135 				      view, actx, txn, dbi);
8136 	if (result != ISC_R_SUCCESS) {
8137 		/*
8138 		 * An error was encountered while attempting to configure zones
8139 		 * found in NZD.  As this error may have been caused by a
8140 		 * configure_zone() failure, try restoring a sane configuration
8141 		 * by reattaching all zones found in NZD to the old view.  If
8142 		 * this also fails, too bad, there is nothing more we can do in
8143 		 * terms of trying to make things right.
8144 		 */
8145 		(void)for_all_newzone_cfgs(configure_newzone_revert, config,
8146 					   vconfig, mctx, view, actx, txn, dbi);
8147 	}
8148 
8149 	(void)nzd_close(&txn, false);
8150 
8151 	UNLOCK(&view->new_zone_lock);
8152 
8153 	return (result);
8154 }
8155 
8156 static isc_result_t
get_newzone_config(dns_view_t * view,const char * zonename,cfg_obj_t ** zoneconfig)8157 get_newzone_config(dns_view_t *view, const char *zonename,
8158 		   cfg_obj_t **zoneconfig) {
8159 	isc_result_t result;
8160 	int status;
8161 	cfg_obj_t *zoneconf = NULL;
8162 	isc_buffer_t *text = NULL;
8163 	MDB_txn *txn = NULL;
8164 	MDB_dbi dbi;
8165 	MDB_val key, data;
8166 	char zname[DNS_NAME_FORMATSIZE];
8167 	dns_fixedname_t fname;
8168 	dns_name_t *name;
8169 	isc_buffer_t b;
8170 
8171 	INSIST(zoneconfig != NULL && *zoneconfig == NULL);
8172 
8173 	LOCK(&view->new_zone_lock);
8174 
8175 	CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
8176 
8177 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8178 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8179 		      "loading NZD config from '%s' "
8180 		      "for zone '%s'",
8181 		      view->new_zone_db, zonename);
8182 
8183 	/* Normalize zone name */
8184 	isc_buffer_constinit(&b, zonename, strlen(zonename));
8185 	isc_buffer_add(&b, strlen(zonename));
8186 	name = dns_fixedname_initname(&fname);
8187 	CHECK(dns_name_fromtext(name, &b, dns_rootname, DNS_NAME_DOWNCASE,
8188 				NULL));
8189 	dns_name_format(name, zname, sizeof(zname));
8190 
8191 	key.mv_data = zname;
8192 	key.mv_size = strlen(zname);
8193 
8194 	status = mdb_get(txn, dbi, &key, &data);
8195 	if (status != MDB_SUCCESS) {
8196 		CHECK(ISC_R_FAILURE);
8197 	}
8198 
8199 	CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
8200 
8201 	*zoneconfig = zoneconf;
8202 	zoneconf = NULL;
8203 	result = ISC_R_SUCCESS;
8204 
8205 cleanup:
8206 	(void)nzd_close(&txn, false);
8207 
8208 	UNLOCK(&view->new_zone_lock);
8209 
8210 	if (zoneconf != NULL) {
8211 		cfg_obj_destroy(named_g_addparser, &zoneconf);
8212 	}
8213 	if (text != NULL) {
8214 		isc_buffer_free(&text);
8215 	}
8216 
8217 	return (result);
8218 }
8219 
8220 #endif /* HAVE_LMDB */
8221 
8222 static int
count_zones(const cfg_obj_t * conf)8223 count_zones(const cfg_obj_t *conf) {
8224 	const cfg_obj_t *zonelist = NULL;
8225 	const cfg_listelt_t *element;
8226 	int n = 0;
8227 
8228 	REQUIRE(conf != NULL);
8229 
8230 	cfg_map_get(conf, "zone", &zonelist);
8231 	for (element = cfg_list_first(zonelist); element != NULL;
8232 	     element = cfg_list_next(element))
8233 	{
8234 		n++;
8235 	}
8236 
8237 	return (n);
8238 }
8239 
8240 static isc_result_t
check_lockfile(named_server_t * server,const cfg_obj_t * config,bool first_time)8241 check_lockfile(named_server_t *server, const cfg_obj_t *config,
8242 	       bool first_time) {
8243 	isc_result_t result;
8244 	const char *filename = NULL;
8245 	const cfg_obj_t *maps[3];
8246 	const cfg_obj_t *options;
8247 	const cfg_obj_t *obj;
8248 	int i;
8249 
8250 	i = 0;
8251 	options = NULL;
8252 	result = cfg_map_get(config, "options", &options);
8253 	if (result == ISC_R_SUCCESS) {
8254 		maps[i++] = options;
8255 	}
8256 	maps[i++] = named_g_defaults;
8257 	maps[i] = NULL;
8258 
8259 	obj = NULL;
8260 	(void)named_config_get(maps, "lock-file", &obj);
8261 
8262 	if (!first_time) {
8263 		if (obj != NULL && !cfg_obj_isstring(obj) &&
8264 		    server->lockfile != NULL &&
8265 		    strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
8266 		{
8267 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8268 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8269 				      "changing 'lock-file' "
8270 				      "has no effect until the "
8271 				      "server is restarted");
8272 		}
8273 
8274 		return (ISC_R_SUCCESS);
8275 	}
8276 
8277 	if (obj != NULL) {
8278 		if (cfg_obj_isvoid(obj)) {
8279 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8280 				      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
8281 				      "skipping lock-file check ");
8282 			return (ISC_R_SUCCESS);
8283 		} else if (named_g_forcelock) {
8284 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8285 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8286 				      "'lock-file' has no effect "
8287 				      "because the server was run with -X");
8288 			server->lockfile = isc_mem_strdup(
8289 				server->mctx, named_g_defaultlockfile);
8290 		} else {
8291 			filename = cfg_obj_asstring(obj);
8292 			server->lockfile = isc_mem_strdup(server->mctx,
8293 							  filename);
8294 		}
8295 
8296 		if (server->lockfile == NULL) {
8297 			return (ISC_R_NOMEMORY);
8298 		}
8299 	}
8300 
8301 	if (named_g_forcelock && named_g_defaultlockfile != NULL) {
8302 		INSIST(server->lockfile == NULL);
8303 		server->lockfile = isc_mem_strdup(server->mctx,
8304 						  named_g_defaultlockfile);
8305 	}
8306 
8307 	if (server->lockfile == NULL) {
8308 		return (ISC_R_SUCCESS);
8309 	}
8310 
8311 	if (named_os_issingleton(server->lockfile)) {
8312 		return (ISC_R_SUCCESS);
8313 	}
8314 
8315 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8316 		      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8317 		      "could not lock %s; another named "
8318 		      "process may be running",
8319 		      server->lockfile);
8320 	return (ISC_R_FAILURE);
8321 }
8322 
8323 static isc_result_t
load_configuration(const char * filename,named_server_t * server,bool first_time)8324 load_configuration(const char *filename, named_server_t *server,
8325 		   bool first_time) {
8326 	cfg_obj_t *config = NULL, *bindkeys = NULL;
8327 	cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
8328 	const cfg_listelt_t *element;
8329 	const cfg_obj_t *builtin_views;
8330 	const cfg_obj_t *maps[3];
8331 	const cfg_obj_t *obj;
8332 	const cfg_obj_t *options;
8333 	const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
8334 	const cfg_obj_t *kasps;
8335 	dns_kasp_t *kasp = NULL;
8336 	dns_kasp_t *kasp_next = NULL;
8337 	dns_kasplist_t tmpkasplist, kasplist;
8338 	const cfg_obj_t *views;
8339 	dns_view_t *view = NULL;
8340 	dns_view_t *view_next = NULL;
8341 	dns_viewlist_t tmpviewlist;
8342 	dns_viewlist_t viewlist, builtin_viewlist;
8343 	in_port_t listen_port, udpport_low, udpport_high;
8344 	int i, backlog;
8345 	int num_zones = 0;
8346 	bool exclusive = false;
8347 	isc_interval_t interval;
8348 	isc_logconfig_t *logc = NULL;
8349 	isc_portset_t *v4portset = NULL;
8350 	isc_portset_t *v6portset = NULL;
8351 	isc_resourcevalue_t nfiles;
8352 	isc_result_t result, tresult;
8353 	uint32_t heartbeat_interval;
8354 	uint32_t interface_interval;
8355 	uint32_t reserved;
8356 	uint32_t udpsize;
8357 	uint32_t transfer_message_size;
8358 	uint32_t recv_tcp_buffer_size;
8359 	uint32_t send_tcp_buffer_size;
8360 	uint32_t recv_udp_buffer_size;
8361 	uint32_t send_udp_buffer_size;
8362 	named_cache_t *nsc;
8363 	named_cachelist_t cachelist, tmpcachelist;
8364 	ns_altsecret_t *altsecret;
8365 	ns_altsecretlist_t altsecrets, tmpaltsecrets;
8366 	unsigned int maxsocks;
8367 	uint32_t softquota = 0;
8368 	uint32_t max;
8369 	uint64_t initial, idle, keepalive, advertised;
8370 	dns_aclenv_t *env =
8371 		ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
8372 
8373 	ISC_LIST_INIT(kasplist);
8374 	ISC_LIST_INIT(viewlist);
8375 	ISC_LIST_INIT(builtin_viewlist);
8376 	ISC_LIST_INIT(cachelist);
8377 	ISC_LIST_INIT(altsecrets);
8378 
8379 	/* Create the ACL configuration context */
8380 	if (named_g_aclconfctx != NULL) {
8381 		cfg_aclconfctx_detach(&named_g_aclconfctx);
8382 	}
8383 	CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx));
8384 
8385 	/*
8386 	 * Shut down all dyndb instances.
8387 	 */
8388 	dns_dyndb_cleanup(false);
8389 
8390 	/*
8391 	 * Parse the global default pseudo-config file.
8392 	 */
8393 	if (first_time) {
8394 		result = named_config_parsedefaults(named_g_parser,
8395 						    &named_g_config);
8396 		if (result != ISC_R_SUCCESS) {
8397 			named_main_earlyfatal("unable to load "
8398 					      "internal defaults: %s",
8399 					      isc_result_totext(result));
8400 		}
8401 		RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
8402 					  &named_g_defaults) == ISC_R_SUCCESS);
8403 	}
8404 
8405 	/*
8406 	 * Parse the configuration file using the new config code.
8407 	 */
8408 	config = NULL;
8409 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8410 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8411 		      "loading configuration from '%s'", filename);
8412 	CHECK(cfg_parser_create(named_g_mctx, named_g_lctx, &conf_parser));
8413 	cfg_parser_setcallback(conf_parser, directory_callback, NULL);
8414 	result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf,
8415 				&config);
8416 
8417 	CHECK(result);
8418 
8419 	/*
8420 	 * Check the validity of the configuration.
8421 	 *
8422 	 * (Ignore plugin parameters for now; they will be
8423 	 * checked later when the modules are actually loaded and
8424 	 * registered.)
8425 	 */
8426 	CHECK(bind9_check_namedconf(config, false, named_g_lctx, named_g_mctx));
8427 
8428 	/*
8429 	 * Fill in the maps array, used for resolving defaults.
8430 	 */
8431 	i = 0;
8432 	options = NULL;
8433 	result = cfg_map_get(config, "options", &options);
8434 	if (result == ISC_R_SUCCESS) {
8435 		maps[i++] = options;
8436 	}
8437 	maps[i++] = named_g_defaults;
8438 	maps[i] = NULL;
8439 
8440 #if HAVE_LIBNGHTTP2
8441 	obj = NULL;
8442 	result = named_config_get(maps, "http-port", &obj);
8443 	INSIST(result == ISC_R_SUCCESS);
8444 	named_g_httpport = (in_port_t)cfg_obj_asuint32(obj);
8445 
8446 	obj = NULL;
8447 	result = named_config_get(maps, "https-port", &obj);
8448 	INSIST(result == ISC_R_SUCCESS);
8449 	named_g_httpsport = (in_port_t)cfg_obj_asuint32(obj);
8450 
8451 	obj = NULL;
8452 	result = named_config_get(maps, "http-listener-clients", &obj);
8453 	INSIST(result == ISC_R_SUCCESS);
8454 	named_g_http_listener_clients = cfg_obj_asuint32(obj);
8455 
8456 	obj = NULL;
8457 	result = named_config_get(maps, "http-streams-per-connection", &obj);
8458 	INSIST(result == ISC_R_SUCCESS);
8459 	named_g_http_streams_per_conn = cfg_obj_asuint32(obj);
8460 #endif
8461 
8462 	/*
8463 	 * If bind.keys exists, load it.  If "dnssec-validation auto"
8464 	 * is turned on, the root key found there will be used as a
8465 	 * default trust anchor.
8466 	 */
8467 	obj = NULL;
8468 	result = named_config_get(maps, "bindkeys-file", &obj);
8469 	INSIST(result == ISC_R_SUCCESS);
8470 	CHECKM(setstring(server, &server->bindkeysfile, cfg_obj_asstring(obj)),
8471 	       "strdup");
8472 	INSIST(server->bindkeysfile != NULL);
8473 
8474 	if (access(server->bindkeysfile, R_OK) == 0) {
8475 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8476 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8477 			      "reading built-in trust anchors "
8478 			      "from file '%s'",
8479 			      server->bindkeysfile);
8480 
8481 		CHECK(cfg_parser_create(named_g_mctx, named_g_lctx,
8482 					&bindkeys_parser));
8483 
8484 		result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
8485 					&cfg_type_bindkeys, &bindkeys);
8486 		if (result != ISC_R_SUCCESS) {
8487 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8488 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8489 				      "unable to parse '%s' error '%s'; using "
8490 				      "built-in keys instead",
8491 				      server->bindkeysfile,
8492 				      isc_result_totext(result));
8493 		}
8494 	} else {
8495 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8496 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8497 			      "unable to open '%s'; using built-in keys "
8498 			      "instead",
8499 			      server->bindkeysfile);
8500 	}
8501 
8502 	/* Ensure exclusive access to configuration data. */
8503 	if (!exclusive) {
8504 		result = isc_task_beginexclusive(server->task);
8505 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
8506 		exclusive = true;
8507 	}
8508 
8509 	/*
8510 	 * Set process limits, which (usually) needs to be done as root.
8511 	 */
8512 	set_limits(maps);
8513 
8514 	/*
8515 	 * Check the process lockfile.
8516 	 */
8517 	CHECK(check_lockfile(server, config, first_time));
8518 
8519 	/*
8520 	 * Check if max number of open sockets that the system allows is
8521 	 * sufficiently large.	Failing this condition is not necessarily fatal,
8522 	 * but may cause subsequent runtime failures for a busy recursive
8523 	 * server.
8524 	 */
8525 	result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &maxsocks);
8526 	if (result != ISC_R_SUCCESS) {
8527 		maxsocks = 0;
8528 	}
8529 	result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
8530 	if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
8531 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8532 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8533 			      "max open files (%" PRIu64 ")"
8534 			      " is smaller than max sockets (%u)",
8535 			      nfiles, maxsocks);
8536 	}
8537 
8538 	/*
8539 	 * Set the number of socket reserved for TCP, stdio etc.
8540 	 */
8541 	obj = NULL;
8542 	result = named_config_get(maps, "reserved-sockets", &obj);
8543 	INSIST(result == ISC_R_SUCCESS);
8544 	reserved = cfg_obj_asuint32(obj);
8545 	if (maxsocks != 0) {
8546 		if (maxsocks < 128U) { /* Prevent underflow. */
8547 			reserved = 0;
8548 		} else if (reserved > maxsocks - 128U) { /* Minimum UDP space.
8549 							  */
8550 			reserved = maxsocks - 128;
8551 		}
8552 	}
8553 	/* Minimum TCP/stdio space. */
8554 	if (reserved < 128U) {
8555 		reserved = 128;
8556 	}
8557 	if (reserved + 128U > maxsocks && maxsocks != 0) {
8558 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8559 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8560 			      "less than 128 UDP sockets available after "
8561 			      "applying 'reserved-sockets' and 'maxsockets'");
8562 	}
8563 	isc_socketmgr_setreserved(named_g_socketmgr, reserved);
8564 
8565 #if defined(HAVE_GEOIP2)
8566 	/*
8567 	 * Release any previously opened GeoIP2 databases.
8568 	 */
8569 	named_geoip_unload();
8570 
8571 	/*
8572 	 * Initialize GeoIP databases from the configured location.
8573 	 * This should happen before configuring any ACLs, so that we
8574 	 * know what databases are available and can reject any GeoIP
8575 	 * ACLs that can't work.
8576 	 */
8577 	obj = NULL;
8578 	result = named_config_get(maps, "geoip-directory", &obj);
8579 	INSIST(result == ISC_R_SUCCESS);
8580 	if (cfg_obj_isstring(obj)) {
8581 		char *dir;
8582 		DE_CONST(cfg_obj_asstring(obj), dir);
8583 		named_geoip_load(dir);
8584 	}
8585 	named_g_aclconfctx->geoip = named_g_geoip;
8586 #endif /* HAVE_GEOIP2 */
8587 
8588 	/*
8589 	 * Configure various server options.
8590 	 */
8591 	configure_server_quota(maps, "transfers-out",
8592 			       &server->sctx->xfroutquota);
8593 	configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
8594 	configure_server_quota(maps, "recursive-clients",
8595 			       &server->sctx->recursionquota);
8596 
8597 	max = isc_quota_getmax(&server->sctx->recursionquota);
8598 	if (max > 1000) {
8599 		unsigned margin = ISC_MAX(100, named_g_cpus + 1);
8600 		if (margin + 100 > max) {
8601 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8602 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8603 				      "'recursive-clients %d' too low when "
8604 				      "running with %d worker threads",
8605 				      max, named_g_cpus);
8606 			CHECK(ISC_R_RANGE);
8607 		}
8608 		softquota = max - margin;
8609 	} else {
8610 		softquota = (max * 90) / 100;
8611 	}
8612 
8613 	isc_quota_soft(&server->sctx->recursionquota, softquota);
8614 
8615 	/*
8616 	 * Set "blackhole". Only legal at options level; there is
8617 	 * no default.
8618 	 */
8619 	CHECK(configure_view_acl(NULL, config, NULL, "blackhole", NULL,
8620 				 named_g_aclconfctx, named_g_mctx,
8621 				 &server->sctx->blackholeacl));
8622 	if (server->sctx->blackholeacl != NULL) {
8623 		dns_dispatchmgr_setblackhole(named_g_dispatchmgr,
8624 					     server->sctx->blackholeacl);
8625 	}
8626 
8627 	/*
8628 	 * Set "keep-response-order". Only legal at options or
8629 	 * global defaults level.
8630 	 */
8631 	CHECK(configure_view_acl(NULL, config, named_g_config,
8632 				 "keep-response-order", NULL,
8633 				 named_g_aclconfctx, named_g_mctx,
8634 				 &server->sctx->keepresporder));
8635 
8636 	obj = NULL;
8637 	result = named_config_get(maps, "match-mapped-addresses", &obj);
8638 	INSIST(result == ISC_R_SUCCESS);
8639 	env->match_mapped = cfg_obj_asboolean(obj);
8640 
8641 	CHECKM(named_statschannels_configure(named_g_server, config,
8642 					     named_g_aclconfctx),
8643 	       "configuring statistics server(s)");
8644 
8645 	/*
8646 	 * Configure the network manager
8647 	 */
8648 	obj = NULL;
8649 	result = named_config_get(maps, "tcp-initial-timeout", &obj);
8650 	INSIST(result == ISC_R_SUCCESS);
8651 	initial = cfg_obj_asuint32(obj) * 100;
8652 	if (initial > MAX_INITIAL_TIMEOUT) {
8653 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8654 			    "tcp-initial-timeout value is out of range: "
8655 			    "lowering to %" PRIu32,
8656 			    MAX_INITIAL_TIMEOUT / 100);
8657 		initial = MAX_INITIAL_TIMEOUT;
8658 	} else if (initial < MIN_INITIAL_TIMEOUT) {
8659 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8660 			    "tcp-initial-timeout value is out of range: "
8661 			    "raising to %" PRIu32,
8662 			    MIN_INITIAL_TIMEOUT / 100);
8663 		initial = MIN_INITIAL_TIMEOUT;
8664 	}
8665 
8666 	obj = NULL;
8667 	result = named_config_get(maps, "tcp-idle-timeout", &obj);
8668 	INSIST(result == ISC_R_SUCCESS);
8669 	idle = cfg_obj_asuint32(obj) * 100;
8670 	if (idle > MAX_IDLE_TIMEOUT) {
8671 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8672 			    "tcp-idle-timeout value is out of range: "
8673 			    "lowering to %" PRIu32,
8674 			    MAX_IDLE_TIMEOUT / 100);
8675 		idle = MAX_IDLE_TIMEOUT;
8676 	} else if (idle < MIN_IDLE_TIMEOUT) {
8677 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8678 			    "tcp-idle-timeout value is out of range: "
8679 			    "raising to %" PRIu32,
8680 			    MIN_IDLE_TIMEOUT / 100);
8681 		idle = MIN_IDLE_TIMEOUT;
8682 	}
8683 
8684 	obj = NULL;
8685 	result = named_config_get(maps, "tcp-keepalive-timeout", &obj);
8686 	INSIST(result == ISC_R_SUCCESS);
8687 	keepalive = cfg_obj_asuint32(obj) * 100;
8688 	if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
8689 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8690 			    "tcp-keepalive-timeout value is out of range: "
8691 			    "lowering to %" PRIu32,
8692 			    MAX_KEEPALIVE_TIMEOUT / 100);
8693 		keepalive = MAX_KEEPALIVE_TIMEOUT;
8694 	} else if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
8695 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8696 			    "tcp-keepalive-timeout value is out of range: "
8697 			    "raising to %" PRIu32,
8698 			    MIN_KEEPALIVE_TIMEOUT / 100);
8699 		keepalive = MIN_KEEPALIVE_TIMEOUT;
8700 	}
8701 
8702 	obj = NULL;
8703 	result = named_config_get(maps, "tcp-advertised-timeout", &obj);
8704 	INSIST(result == ISC_R_SUCCESS);
8705 	advertised = cfg_obj_asuint32(obj) * 100;
8706 	if (advertised > MAX_ADVERTISED_TIMEOUT) {
8707 		cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8708 			    "tcp-advertized-timeout value is out of range: "
8709 			    "lowering to %" PRIu32,
8710 			    MAX_ADVERTISED_TIMEOUT / 100);
8711 		advertised = MAX_ADVERTISED_TIMEOUT;
8712 	}
8713 
8714 	isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
8715 			   advertised);
8716 
8717 #define CAP_IF_NOT_ZERO(v, min, max) \
8718 	if (v > 0 && v < min) {      \
8719 		v = min;             \
8720 	} else if (v > max) {        \
8721 		v = max;             \
8722 	}
8723 
8724 	/* Set the kernel send and receive buffer sizes */
8725 	obj = NULL;
8726 	result = named_config_get(maps, "tcp-receive-buffer", &obj);
8727 	INSIST(result == ISC_R_SUCCESS);
8728 	recv_tcp_buffer_size = cfg_obj_asuint32(obj);
8729 	CAP_IF_NOT_ZERO(recv_tcp_buffer_size, 4096, INT32_MAX);
8730 
8731 	obj = NULL;
8732 	result = named_config_get(maps, "tcp-send-buffer", &obj);
8733 	INSIST(result == ISC_R_SUCCESS);
8734 	send_tcp_buffer_size = cfg_obj_asuint32(obj);
8735 	CAP_IF_NOT_ZERO(send_tcp_buffer_size, 4096, INT32_MAX);
8736 
8737 	obj = NULL;
8738 	result = named_config_get(maps, "udp-receive-buffer", &obj);
8739 	INSIST(result == ISC_R_SUCCESS);
8740 	recv_udp_buffer_size = cfg_obj_asuint32(obj);
8741 	CAP_IF_NOT_ZERO(recv_udp_buffer_size, 4096, INT32_MAX);
8742 
8743 	obj = NULL;
8744 	result = named_config_get(maps, "udp-send-buffer", &obj);
8745 	INSIST(result == ISC_R_SUCCESS);
8746 	send_udp_buffer_size = cfg_obj_asuint32(obj);
8747 	CAP_IF_NOT_ZERO(send_udp_buffer_size, 4096, INT32_MAX);
8748 
8749 	isc_nm_setnetbuffers(named_g_netmgr, recv_tcp_buffer_size,
8750 			     send_tcp_buffer_size, recv_udp_buffer_size,
8751 			     send_udp_buffer_size);
8752 
8753 #undef CAP_IF_NOT_ZERO
8754 
8755 	/*
8756 	 * Configure sets of UDP query source ports.
8757 	 */
8758 	CHECKM(isc_portset_create(named_g_mctx, &v4portset), "creating UDP "
8759 							     "port set");
8760 	CHECKM(isc_portset_create(named_g_mctx, &v6portset), "creating UDP "
8761 							     "port set");
8762 
8763 	usev4ports = NULL;
8764 	usev6ports = NULL;
8765 	avoidv4ports = NULL;
8766 	avoidv6ports = NULL;
8767 
8768 	(void)named_config_get(maps, "use-v4-udp-ports", &usev4ports);
8769 	if (usev4ports != NULL) {
8770 		portset_fromconf(v4portset, usev4ports, true);
8771 	} else {
8772 		CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
8773 					       &udpport_high),
8774 		       "get the default UDP/IPv4 port range");
8775 		if (udpport_low == udpport_high) {
8776 			isc_portset_add(v4portset, udpport_low);
8777 		} else {
8778 			isc_portset_addrange(v4portset, udpport_low,
8779 					     udpport_high);
8780 		}
8781 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) {
8782 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8783 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8784 				      "using default UDP/IPv4 port range: "
8785 				      "[%d, %d]",
8786 				      udpport_low, udpport_high);
8787 		}
8788 	}
8789 	(void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
8790 	if (avoidv4ports != NULL) {
8791 		portset_fromconf(v4portset, avoidv4ports, false);
8792 	}
8793 
8794 	(void)named_config_get(maps, "use-v6-udp-ports", &usev6ports);
8795 	if (usev6ports != NULL) {
8796 		portset_fromconf(v6portset, usev6ports, true);
8797 	} else {
8798 		CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
8799 					       &udpport_high),
8800 		       "get the default UDP/IPv6 port range");
8801 		if (udpport_low == udpport_high) {
8802 			isc_portset_add(v6portset, udpport_low);
8803 		} else {
8804 			isc_portset_addrange(v6portset, udpport_low,
8805 					     udpport_high);
8806 		}
8807 		if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) {
8808 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8809 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8810 				      "using default UDP/IPv6 port range: "
8811 				      "[%d, %d]",
8812 				      udpport_low, udpport_high);
8813 		}
8814 	}
8815 	(void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
8816 	if (avoidv6ports != NULL) {
8817 		portset_fromconf(v6portset, avoidv6ports, false);
8818 	}
8819 
8820 	dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset,
8821 				      v6portset);
8822 
8823 	/*
8824 	 * Set the EDNS UDP size when we don't match a view.
8825 	 */
8826 	obj = NULL;
8827 	result = named_config_get(maps, "edns-udp-size", &obj);
8828 	INSIST(result == ISC_R_SUCCESS);
8829 	udpsize = cfg_obj_asuint32(obj);
8830 	if (udpsize < 512) {
8831 		udpsize = 512;
8832 	}
8833 	if (udpsize > 4096) {
8834 		udpsize = 4096;
8835 	}
8836 	server->sctx->udpsize = (uint16_t)udpsize;
8837 
8838 	/* Set the transfer message size for TCP */
8839 	obj = NULL;
8840 	result = named_config_get(maps, "transfer-message-size", &obj);
8841 	INSIST(result == ISC_R_SUCCESS);
8842 	transfer_message_size = cfg_obj_asuint32(obj);
8843 	if (transfer_message_size < 512) {
8844 		transfer_message_size = 512;
8845 	} else if (transfer_message_size > 65535) {
8846 		transfer_message_size = 65535;
8847 	}
8848 	server->sctx->transfer_tcp_message_size =
8849 		(uint16_t)transfer_message_size;
8850 
8851 	/*
8852 	 * Configure the zone manager.
8853 	 */
8854 	obj = NULL;
8855 	result = named_config_get(maps, "transfers-in", &obj);
8856 	INSIST(result == ISC_R_SUCCESS);
8857 	dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
8858 
8859 	obj = NULL;
8860 	result = named_config_get(maps, "transfers-per-ns", &obj);
8861 	INSIST(result == ISC_R_SUCCESS);
8862 	dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
8863 
8864 	obj = NULL;
8865 	result = named_config_get(maps, "notify-rate", &obj);
8866 	INSIST(result == ISC_R_SUCCESS);
8867 	dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
8868 
8869 	obj = NULL;
8870 	result = named_config_get(maps, "startup-notify-rate", &obj);
8871 	INSIST(result == ISC_R_SUCCESS);
8872 	dns_zonemgr_setstartupnotifyrate(server->zonemgr,
8873 					 cfg_obj_asuint32(obj));
8874 
8875 	obj = NULL;
8876 	result = named_config_get(maps, "serial-query-rate", &obj);
8877 	INSIST(result == ISC_R_SUCCESS);
8878 	dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
8879 
8880 	/*
8881 	 * Determine which port to use for listening for incoming connections.
8882 	 */
8883 	if (named_g_port != 0) {
8884 		listen_port = named_g_port;
8885 	} else {
8886 		CHECKM(named_config_getport(config, "port", &listen_port),
8887 		       "port");
8888 	}
8889 
8890 	/*
8891 	 * Determining the default DSCP code point.
8892 	 */
8893 	CHECKM(named_config_getdscp(config, &named_g_dscp), "dscp");
8894 
8895 	/*
8896 	 * Find the listen queue depth.
8897 	 */
8898 	obj = NULL;
8899 	result = named_config_get(maps, "tcp-listen-queue", &obj);
8900 	INSIST(result == ISC_R_SUCCESS);
8901 	backlog = cfg_obj_asuint32(obj);
8902 	if ((backlog > 0) && (backlog < 10)) {
8903 		backlog = 10;
8904 	}
8905 	ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
8906 
8907 	/*
8908 	 * Configure the interface manager according to the "listen-on"
8909 	 * statement.
8910 	 */
8911 	{
8912 		const cfg_obj_t *clistenon = NULL;
8913 		ns_listenlist_t *listenon = NULL;
8914 
8915 		clistenon = NULL;
8916 		/*
8917 		 * Even though listen-on is present in the default
8918 		 * configuration, this way is easier.
8919 		 */
8920 		if (options != NULL) {
8921 			(void)cfg_map_get(options, "listen-on", &clistenon);
8922 		}
8923 		if (clistenon != NULL) {
8924 			CHECK(listenlist_fromconfig(
8925 				clistenon, config, named_g_aclconfctx,
8926 				named_g_mctx, AF_INET, &listenon));
8927 		} else {
8928 			/*
8929 			 * Not specified, use default.
8930 			 */
8931 			CHECK(ns_listenlist_default(named_g_mctx, listen_port,
8932 						    -1, true, &listenon));
8933 		}
8934 		if (listenon != NULL) {
8935 			ns_interfacemgr_setlistenon4(server->interfacemgr,
8936 						     listenon);
8937 			ns_listenlist_detach(&listenon);
8938 		}
8939 	}
8940 	/*
8941 	 * Ditto for IPv6.
8942 	 */
8943 	{
8944 		const cfg_obj_t *clistenon = NULL;
8945 		ns_listenlist_t *listenon = NULL;
8946 
8947 		if (options != NULL) {
8948 			(void)cfg_map_get(options, "listen-on-v6", &clistenon);
8949 		}
8950 		if (clistenon != NULL) {
8951 			CHECK(listenlist_fromconfig(
8952 				clistenon, config, named_g_aclconfctx,
8953 				named_g_mctx, AF_INET6, &listenon));
8954 		} else {
8955 			/*
8956 			 * Not specified, use default.
8957 			 */
8958 			CHECK(ns_listenlist_default(named_g_mctx, listen_port,
8959 						    -1, true, &listenon));
8960 		}
8961 		if (listenon != NULL) {
8962 			ns_interfacemgr_setlistenon6(server->interfacemgr,
8963 						     listenon);
8964 			ns_listenlist_detach(&listenon);
8965 		}
8966 	}
8967 
8968 	/*
8969 	 * Rescan the interface list to pick up changes in the
8970 	 * listen-on option.  It's important that we do this before we try
8971 	 * to configure the query source, since the dispatcher we use might
8972 	 * be shared with an interface.
8973 	 */
8974 	result = ns_interfacemgr_scan(server->interfacemgr, true);
8975 
8976 	/*
8977 	 * Check that named is able to TCP listen on at least one
8978 	 * interface. Otherwise, another named process could be running
8979 	 * and we should fail.
8980 	 */
8981 	if (first_time && (result == ISC_R_ADDRINUSE)) {
8982 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8983 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8984 			      "unable to listen on any configured interfaces");
8985 		result = ISC_R_FAILURE;
8986 		goto cleanup;
8987 	}
8988 
8989 	/*
8990 	 * Arrange for further interface scanning to occur periodically
8991 	 * as specified by the "interface-interval" option.
8992 	 */
8993 	obj = NULL;
8994 	result = named_config_get(maps, "interface-interval", &obj);
8995 	INSIST(result == ISC_R_SUCCESS);
8996 	interface_interval = cfg_obj_asduration(obj);
8997 	if (interface_interval == 0) {
8998 		CHECK(isc_timer_reset(server->interface_timer,
8999 				      isc_timertype_inactive, NULL, NULL,
9000 				      true));
9001 	} else if (server->interface_interval != interface_interval) {
9002 		isc_interval_set(&interval, interface_interval, 0);
9003 		CHECK(isc_timer_reset(server->interface_timer,
9004 				      isc_timertype_ticker, NULL, &interval,
9005 				      false));
9006 	}
9007 	server->interface_interval = interface_interval;
9008 
9009 	/*
9010 	 * Enable automatic interface scans.
9011 	 */
9012 	obj = NULL;
9013 	result = named_config_get(maps, "automatic-interface-scan", &obj);
9014 	INSIST(result == ISC_R_SUCCESS);
9015 	server->sctx->interface_auto = cfg_obj_asboolean(obj);
9016 
9017 	/*
9018 	 * Configure the dialup heartbeat timer.
9019 	 */
9020 	obj = NULL;
9021 	result = named_config_get(maps, "heartbeat-interval", &obj);
9022 	INSIST(result == ISC_R_SUCCESS);
9023 	heartbeat_interval = cfg_obj_asuint32(obj) * 60;
9024 	if (heartbeat_interval == 0) {
9025 		CHECK(isc_timer_reset(server->heartbeat_timer,
9026 				      isc_timertype_inactive, NULL, NULL,
9027 				      true));
9028 	} else if (server->heartbeat_interval != heartbeat_interval) {
9029 		isc_interval_set(&interval, heartbeat_interval, 0);
9030 		CHECK(isc_timer_reset(server->heartbeat_timer,
9031 				      isc_timertype_ticker, NULL, &interval,
9032 				      false));
9033 	}
9034 	server->heartbeat_interval = heartbeat_interval;
9035 
9036 	isc_interval_set(&interval, 1200, 0);
9037 	CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
9038 			      &interval, false));
9039 
9040 	isc_interval_set(&interval, named_g_tat_interval, 0);
9041 	CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker, NULL,
9042 			      &interval, false));
9043 
9044 	/*
9045 	 * Write the PID file.
9046 	 */
9047 	obj = NULL;
9048 	if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) {
9049 		if (cfg_obj_isvoid(obj)) {
9050 			named_os_writepidfile(NULL, first_time);
9051 		} else {
9052 			named_os_writepidfile(cfg_obj_asstring(obj),
9053 					      first_time);
9054 		}
9055 	} else {
9056 		named_os_writepidfile(named_g_defaultpidfile, first_time);
9057 	}
9058 
9059 	/*
9060 	 * Configure the server-wide session key.  This must be done before
9061 	 * configure views because zone configuration may need to know
9062 	 * session-keyname.
9063 	 *
9064 	 * Failure of session key generation isn't fatal at this time; if it
9065 	 * turns out that a session key is really needed but doesn't exist,
9066 	 * we'll treat it as a fatal error then.
9067 	 */
9068 	(void)configure_session_key(maps, server, named_g_mctx, first_time);
9069 
9070 	/*
9071 	 * Create the DNSSEC key and signing policies (KASP).
9072 	 */
9073 	kasps = NULL;
9074 	(void)cfg_map_get(config, "dnssec-policy", &kasps);
9075 	for (element = cfg_list_first(kasps); element != NULL;
9076 	     element = cfg_list_next(element))
9077 	{
9078 		cfg_obj_t *kconfig = cfg_listelt_value(element);
9079 		kasp = NULL;
9080 		CHECK(cfg_kasp_fromconfig(kconfig, NULL, named_g_mctx,
9081 					  named_g_lctx, &kasplist, &kasp));
9082 		INSIST(kasp != NULL);
9083 		dns_kasp_freeze(kasp);
9084 		dns_kasp_detach(&kasp);
9085 	}
9086 	/*
9087 	 * Create the built-in kasp policies ("default", "insecure").
9088 	 */
9089 	kasp = NULL;
9090 	CHECK(cfg_kasp_fromconfig(NULL, "default", named_g_mctx, named_g_lctx,
9091 				  &kasplist, &kasp));
9092 	INSIST(kasp != NULL);
9093 	dns_kasp_freeze(kasp);
9094 	dns_kasp_detach(&kasp);
9095 
9096 	kasp = NULL;
9097 	CHECK(cfg_kasp_fromconfig(NULL, "insecure", named_g_mctx, named_g_lctx,
9098 				  &kasplist, &kasp));
9099 	INSIST(kasp != NULL);
9100 	dns_kasp_freeze(kasp);
9101 	dns_kasp_detach(&kasp);
9102 
9103 	tmpkasplist = server->kasplist;
9104 	server->kasplist = kasplist;
9105 	kasplist = tmpkasplist;
9106 
9107 	/*
9108 	 * Configure the views.
9109 	 */
9110 	views = NULL;
9111 	(void)cfg_map_get(config, "view", &views);
9112 
9113 	/*
9114 	 * Create the views and count all the configured zones in
9115 	 * order to correctly size the zone manager's task table.
9116 	 * (We only count zones for configured views; the built-in
9117 	 * "bind" view can be ignored as it only adds a negligible
9118 	 * number of zones.)
9119 	 *
9120 	 * If we're allowing new zones, we need to be able to find the
9121 	 * new zone file and count those as well.  So we setup the new
9122 	 * zone configuration context, but otherwise view configuration
9123 	 * waits until after the zone manager's task list has been sized.
9124 	 */
9125 	for (element = cfg_list_first(views); element != NULL;
9126 	     element = cfg_list_next(element))
9127 	{
9128 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9129 		const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
9130 		int nzf_num_zones;
9131 
9132 		view = NULL;
9133 
9134 		CHECK(create_view(vconfig, &viewlist, &view));
9135 		INSIST(view != NULL);
9136 
9137 		num_zones += count_zones(voptions);
9138 
9139 		CHECK(setup_newzones(view, config, vconfig, conf_parser,
9140 				     named_g_aclconfctx, &nzf_num_zones));
9141 		num_zones += nzf_num_zones;
9142 
9143 		dns_view_detach(&view);
9144 	}
9145 
9146 	/*
9147 	 * If there were no explicit views then we do the default
9148 	 * view here.
9149 	 */
9150 	if (views == NULL) {
9151 		int nzf_num_zones;
9152 
9153 		CHECK(create_view(NULL, &viewlist, &view));
9154 		INSIST(view != NULL);
9155 
9156 		num_zones = count_zones(config);
9157 
9158 		CHECK(setup_newzones(view, config, NULL, conf_parser,
9159 				     named_g_aclconfctx, &nzf_num_zones));
9160 		num_zones += nzf_num_zones;
9161 
9162 		dns_view_detach(&view);
9163 	}
9164 
9165 	/*
9166 	 * Zones have been counted; set the zone manager task pool size.
9167 	 */
9168 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9169 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9170 		      "sizing zone task pool based on %d zones", num_zones);
9171 	CHECK(dns_zonemgr_setsize(named_g_server->zonemgr, num_zones));
9172 
9173 	/*
9174 	 * Configure and freeze all explicit views.  Explicit
9175 	 * views that have zones were already created at parsing
9176 	 * time, but views with no zones must be created here.
9177 	 */
9178 	for (element = cfg_list_first(views); element != NULL;
9179 	     element = cfg_list_next(element))
9180 	{
9181 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9182 
9183 		view = NULL;
9184 		CHECK(find_view(vconfig, &viewlist, &view));
9185 		CHECK(configure_view(view, &viewlist, config, vconfig,
9186 				     &cachelist, &server->kasplist, bindkeys,
9187 				     named_g_mctx, named_g_aclconfctx, true));
9188 		dns_view_freeze(view);
9189 		dns_view_detach(&view);
9190 	}
9191 
9192 	/*
9193 	 * Make sure we have a default view if and only if there
9194 	 * were no explicit views.
9195 	 */
9196 	if (views == NULL) {
9197 		view = NULL;
9198 		CHECK(find_view(NULL, &viewlist, &view));
9199 		CHECK(configure_view(view, &viewlist, config, NULL, &cachelist,
9200 				     &server->kasplist, bindkeys, named_g_mctx,
9201 				     named_g_aclconfctx, true));
9202 		dns_view_freeze(view);
9203 		dns_view_detach(&view);
9204 	}
9205 
9206 	/*
9207 	 * Create (or recreate) the built-in views.
9208 	 */
9209 	builtin_views = NULL;
9210 	RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) ==
9211 		      ISC_R_SUCCESS);
9212 	for (element = cfg_list_first(builtin_views); element != NULL;
9213 	     element = cfg_list_next(element))
9214 	{
9215 		cfg_obj_t *vconfig = cfg_listelt_value(element);
9216 
9217 		CHECK(create_view(vconfig, &builtin_viewlist, &view));
9218 		CHECK(configure_view(view, &viewlist, config, vconfig,
9219 				     &cachelist, &server->kasplist, bindkeys,
9220 				     named_g_mctx, named_g_aclconfctx, false));
9221 		dns_view_freeze(view);
9222 		dns_view_detach(&view);
9223 		view = NULL;
9224 	}
9225 
9226 	/* Now combine the two viewlists into one */
9227 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9228 
9229 	/*
9230 	 * Commit any dns_zone_setview() calls on all zones in the new
9231 	 * view.
9232 	 */
9233 	for (view = ISC_LIST_HEAD(viewlist); view != NULL;
9234 	     view = ISC_LIST_NEXT(view, link))
9235 	{
9236 		dns_view_setviewcommit(view);
9237 	}
9238 
9239 	/* Swap our new view list with the production one. */
9240 	tmpviewlist = server->viewlist;
9241 	server->viewlist = viewlist;
9242 	viewlist = tmpviewlist;
9243 
9244 	/* Make the view list available to each of the views */
9245 	view = ISC_LIST_HEAD(server->viewlist);
9246 	while (view != NULL) {
9247 		view->viewlist = &server->viewlist;
9248 		view = ISC_LIST_NEXT(view, link);
9249 	}
9250 
9251 	/* Swap our new cache list with the production one. */
9252 	tmpcachelist = server->cachelist;
9253 	server->cachelist = cachelist;
9254 	cachelist = tmpcachelist;
9255 
9256 	/* Load the TKEY information from the configuration. */
9257 	if (options != NULL) {
9258 		dns_tkeyctx_t *t = NULL;
9259 		CHECKM(named_tkeyctx_fromconfig(options, named_g_mctx, &t),
9260 		       "configuring TKEY");
9261 		if (server->sctx->tkeyctx != NULL) {
9262 			dns_tkeyctx_destroy(&server->sctx->tkeyctx);
9263 		}
9264 		server->sctx->tkeyctx = t;
9265 	}
9266 
9267 	/*
9268 	 * Bind the control port(s).
9269 	 */
9270 	CHECKM(named_controls_configure(named_g_server->controls, config,
9271 					named_g_aclconfctx),
9272 	       "binding control channel(s)");
9273 
9274 #ifdef HAVE_LMDB
9275 	/*
9276 	 * If we're using LMDB, we may have created newzones databases
9277 	 * as root, making it impossible to reopen them later after
9278 	 * switching to a new userid. We close them now, and reopen
9279 	 * after relinquishing privileges them.
9280 	 */
9281 	if (first_time) {
9282 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9283 		     view = ISC_LIST_NEXT(view, link))
9284 		{
9285 			nzd_env_close(view);
9286 		}
9287 	}
9288 #endif /* HAVE_LMDB */
9289 
9290 	/*
9291 	 * Relinquish root privileges.
9292 	 */
9293 	if (first_time) {
9294 		named_os_changeuser();
9295 	}
9296 
9297 	/*
9298 	 * Check that the working directory is writable.
9299 	 */
9300 	if (!isc_file_isdirwritable(".")) {
9301 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9302 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9303 			      "the working directory is not writable");
9304 		result = ISC_R_NOPERM;
9305 		goto cleanup;
9306 	}
9307 
9308 #ifdef HAVE_LMDB
9309 	/*
9310 	 * Reopen NZD databases.
9311 	 */
9312 	if (first_time) {
9313 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9314 		     view = ISC_LIST_NEXT(view, link))
9315 		{
9316 			nzd_env_reopen(view);
9317 		}
9318 	}
9319 #endif /* HAVE_LMDB */
9320 
9321 	/*
9322 	 * Configure the logging system.
9323 	 *
9324 	 * Do this after changing UID to make sure that any log
9325 	 * files specified in named.conf get created by the
9326 	 * unprivileged user, not root.
9327 	 */
9328 	if (named_g_logstderr) {
9329 		const cfg_obj_t *logobj = NULL;
9330 
9331 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9332 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9333 			      "not using config file logging "
9334 			      "statement for logging due to "
9335 			      "-g option");
9336 
9337 		(void)cfg_map_get(config, "logging", &logobj);
9338 		if (logobj != NULL) {
9339 			result = named_logconfig(NULL, logobj);
9340 			if (result != ISC_R_SUCCESS) {
9341 				isc_log_write(
9342 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9343 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9344 					"checking logging configuration "
9345 					"failed: %s",
9346 					isc_result_totext(result));
9347 				goto cleanup;
9348 			}
9349 		}
9350 	} else {
9351 		const cfg_obj_t *logobj = NULL;
9352 
9353 		isc_logconfig_create(named_g_lctx, &logc);
9354 
9355 		logobj = NULL;
9356 		(void)cfg_map_get(config, "logging", &logobj);
9357 		if (logobj != NULL) {
9358 			CHECKM(named_logconfig(logc, logobj), "configuring "
9359 							      "logging");
9360 		} else {
9361 			named_log_setdefaultchannels(logc);
9362 			CHECKM(named_log_setunmatchedcategory(logc),
9363 			       "setting up default 'category unmatched'");
9364 			CHECKM(named_log_setdefaultcategory(logc),
9365 			       "setting up default 'category default'");
9366 		}
9367 
9368 		isc_logconfig_use(named_g_lctx, logc);
9369 		logc = NULL;
9370 
9371 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9372 			      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9373 			      "now using logging configuration from "
9374 			      "config file");
9375 	}
9376 
9377 	/*
9378 	 * Set the default value of the query logging flag depending
9379 	 * whether a "queries" category has been defined.  This is
9380 	 * a disgusting hack, but we need to do this for BIND 8
9381 	 * compatibility.
9382 	 */
9383 	if (first_time) {
9384 		const cfg_obj_t *logobj = NULL;
9385 		const cfg_obj_t *categories = NULL;
9386 
9387 		obj = NULL;
9388 		if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
9389 			ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES,
9390 					    cfg_obj_asboolean(obj));
9391 		} else {
9392 			(void)cfg_map_get(config, "logging", &logobj);
9393 			if (logobj != NULL) {
9394 				(void)cfg_map_get(logobj, "category",
9395 						  &categories);
9396 			}
9397 			if (categories != NULL) {
9398 				for (element = cfg_list_first(categories);
9399 				     element != NULL;
9400 				     element = cfg_list_next(element))
9401 				{
9402 					const cfg_obj_t *catobj;
9403 					const char *str;
9404 
9405 					obj = cfg_listelt_value(element);
9406 					catobj = cfg_tuple_get(obj, "name");
9407 					str = cfg_obj_asstring(catobj);
9408 					if (strcasecmp(str, "queries") == 0) {
9409 						ns_server_setoption(
9410 							server->sctx,
9411 							NS_SERVER_LOGQUERIES,
9412 							true);
9413 					}
9414 				}
9415 			}
9416 		}
9417 	}
9418 
9419 	obj = NULL;
9420 	if (options != NULL &&
9421 	    cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
9422 	{
9423 		named_g_memstatistics = cfg_obj_asboolean(obj);
9424 	} else {
9425 		named_g_memstatistics =
9426 			((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
9427 	}
9428 
9429 	obj = NULL;
9430 	if (named_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
9431 	{
9432 		named_main_setmemstats(cfg_obj_asstring(obj));
9433 	} else if (named_g_memstatistics) {
9434 		named_main_setmemstats("named.memstats");
9435 	} else {
9436 		named_main_setmemstats(NULL);
9437 	}
9438 
9439 	obj = NULL;
9440 	result = named_config_get(maps, "statistics-file", &obj);
9441 	INSIST(result == ISC_R_SUCCESS);
9442 	CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
9443 	       "strdup");
9444 
9445 	obj = NULL;
9446 	result = named_config_get(maps, "dump-file", &obj);
9447 	INSIST(result == ISC_R_SUCCESS);
9448 	CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
9449 	       "strdup");
9450 
9451 	obj = NULL;
9452 	result = named_config_get(maps, "secroots-file", &obj);
9453 	INSIST(result == ISC_R_SUCCESS);
9454 	CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
9455 	       "strdup");
9456 
9457 	obj = NULL;
9458 	result = named_config_get(maps, "recursing-file", &obj);
9459 	INSIST(result == ISC_R_SUCCESS);
9460 	CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
9461 	       "strdup");
9462 
9463 	obj = NULL;
9464 	result = named_config_get(maps, "version", &obj);
9465 	if (result == ISC_R_SUCCESS) {
9466 		CHECKM(setoptstring(server, &server->version, obj), "strdup");
9467 		server->version_set = true;
9468 	} else {
9469 		server->version_set = false;
9470 	}
9471 
9472 	obj = NULL;
9473 	result = named_config_get(maps, "hostname", &obj);
9474 	if (result == ISC_R_SUCCESS) {
9475 		CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
9476 		server->hostname_set = true;
9477 	} else {
9478 		server->hostname_set = false;
9479 	}
9480 
9481 	obj = NULL;
9482 	result = named_config_get(maps, "server-id", &obj);
9483 	server->sctx->gethostname = NULL;
9484 	if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
9485 		/* The parser translates "hostname" to true */
9486 		server->sctx->gethostname = named_os_gethostname;
9487 		result = ns_server_setserverid(server->sctx, NULL);
9488 	} else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
9489 		/* Found a quoted string */
9490 		result = ns_server_setserverid(server->sctx,
9491 					       cfg_obj_asstring(obj));
9492 	} else {
9493 		result = ns_server_setserverid(server->sctx, NULL);
9494 	}
9495 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9496 
9497 	obj = NULL;
9498 	result = named_config_get(maps, "flush-zones-on-shutdown", &obj);
9499 	if (result == ISC_R_SUCCESS) {
9500 		server->flushonshutdown = cfg_obj_asboolean(obj);
9501 	} else {
9502 		server->flushonshutdown = false;
9503 	}
9504 
9505 	obj = NULL;
9506 	result = named_config_get(maps, "answer-cookie", &obj);
9507 	INSIST(result == ISC_R_SUCCESS);
9508 	server->sctx->answercookie = cfg_obj_asboolean(obj);
9509 
9510 	obj = NULL;
9511 	result = named_config_get(maps, "cookie-algorithm", &obj);
9512 	INSIST(result == ISC_R_SUCCESS);
9513 	if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
9514 		server->sctx->cookiealg = ns_cookiealg_siphash24;
9515 	} else if (strcasecmp(cfg_obj_asstring(obj), "aes") == 0) {
9516 		server->sctx->cookiealg = ns_cookiealg_aes;
9517 	} else {
9518 		INSIST(0);
9519 		ISC_UNREACHABLE();
9520 	}
9521 
9522 	obj = NULL;
9523 	result = named_config_get(maps, "cookie-secret", &obj);
9524 	if (result == ISC_R_SUCCESS) {
9525 		const char *str;
9526 		bool first = true;
9527 		isc_buffer_t b;
9528 		unsigned int usedlength;
9529 		unsigned int expectedlength;
9530 
9531 		for (element = cfg_list_first(obj); element != NULL;
9532 		     element = cfg_list_next(element))
9533 		{
9534 			obj = cfg_listelt_value(element);
9535 			str = cfg_obj_asstring(obj);
9536 
9537 			if (first) {
9538 				memset(server->sctx->secret, 0,
9539 				       sizeof(server->sctx->secret));
9540 				isc_buffer_init(&b, server->sctx->secret,
9541 						sizeof(server->sctx->secret));
9542 				result = isc_hex_decodestring(str, &b);
9543 				if (result != ISC_R_SUCCESS &&
9544 				    result != ISC_R_NOSPACE) {
9545 					goto cleanup;
9546 				}
9547 				first = false;
9548 			} else {
9549 				altsecret = isc_mem_get(server->sctx->mctx,
9550 							sizeof(*altsecret));
9551 				isc_buffer_init(&b, altsecret->secret,
9552 						sizeof(altsecret->secret));
9553 				result = isc_hex_decodestring(str, &b);
9554 				if (result != ISC_R_SUCCESS &&
9555 				    result != ISC_R_NOSPACE) {
9556 					isc_mem_put(server->sctx->mctx,
9557 						    altsecret,
9558 						    sizeof(*altsecret));
9559 					goto cleanup;
9560 				}
9561 				ISC_LIST_INITANDAPPEND(altsecrets, altsecret,
9562 						       link);
9563 			}
9564 
9565 			usedlength = isc_buffer_usedlength(&b);
9566 			switch (server->sctx->cookiealg) {
9567 			case ns_cookiealg_siphash24:
9568 				expectedlength = ISC_SIPHASH24_KEY_LENGTH;
9569 				if (usedlength != expectedlength) {
9570 					CHECKM(ISC_R_RANGE, "SipHash-2-4 "
9571 							    "cookie-secret "
9572 							    "must be 128 bits");
9573 				}
9574 				break;
9575 			case ns_cookiealg_aes:
9576 				expectedlength = ISC_AES128_KEYLENGTH;
9577 				if (usedlength != expectedlength) {
9578 					CHECKM(ISC_R_RANGE, "AES cookie-secret "
9579 							    "must be 128 bits");
9580 				}
9581 				break;
9582 			}
9583 		}
9584 	} else {
9585 		isc_nonce_buf(server->sctx->secret,
9586 			      sizeof(server->sctx->secret));
9587 	}
9588 
9589 	/*
9590 	 * Swap altsecrets lists.
9591 	 */
9592 	tmpaltsecrets = server->sctx->altsecrets;
9593 	server->sctx->altsecrets = altsecrets;
9594 	altsecrets = tmpaltsecrets;
9595 
9596 	(void)named_server_loadnta(server);
9597 
9598 #ifdef USE_DNSRPS
9599 	/*
9600 	 * Start and connect to the DNS Response Policy Service
9601 	 * daemon, dnsrpzd, for each view that uses DNSRPS.
9602 	 */
9603 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9604 	     view = ISC_LIST_NEXT(view, link))
9605 	{
9606 		result = dns_dnsrps_connect(view->rpzs);
9607 		if (result != ISC_R_SUCCESS) {
9608 			view = NULL;
9609 			goto cleanup;
9610 		}
9611 	}
9612 #endif /* ifdef USE_DNSRPS */
9613 
9614 	result = ISC_R_SUCCESS;
9615 
9616 cleanup:
9617 	if (logc != NULL) {
9618 		isc_logconfig_destroy(&logc);
9619 	}
9620 
9621 	if (v4portset != NULL) {
9622 		isc_portset_destroy(named_g_mctx, &v4portset);
9623 	}
9624 
9625 	if (v6portset != NULL) {
9626 		isc_portset_destroy(named_g_mctx, &v6portset);
9627 	}
9628 
9629 	if (conf_parser != NULL) {
9630 		if (config != NULL) {
9631 			cfg_obj_destroy(conf_parser, &config);
9632 		}
9633 		cfg_parser_destroy(&conf_parser);
9634 	}
9635 
9636 	if (bindkeys_parser != NULL) {
9637 		if (bindkeys != NULL) {
9638 			cfg_obj_destroy(bindkeys_parser, &bindkeys);
9639 		}
9640 		cfg_parser_destroy(&bindkeys_parser);
9641 	}
9642 
9643 	if (view != NULL) {
9644 		dns_view_detach(&view);
9645 	}
9646 
9647 	if (kasp != NULL) {
9648 		dns_kasp_detach(&kasp);
9649 	}
9650 
9651 	ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9652 
9653 	/*
9654 	 * This cleans up either the old production view list
9655 	 * or our temporary list depending on whether they
9656 	 * were swapped above or not.
9657 	 */
9658 	for (view = ISC_LIST_HEAD(viewlist); view != NULL; view = view_next) {
9659 		view_next = ISC_LIST_NEXT(view, link);
9660 		ISC_LIST_UNLINK(viewlist, view, link);
9661 		if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
9662 		{
9663 			dns_view_setviewrevert(view);
9664 			(void)dns_zt_apply(view->zonetable, false, NULL,
9665 					   removed, view);
9666 		}
9667 		dns_view_detach(&view);
9668 	}
9669 
9670 	/*
9671 	 * Same cleanup for kasp list.
9672 	 */
9673 	for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
9674 		kasp_next = ISC_LIST_NEXT(kasp, link);
9675 		ISC_LIST_UNLINK(kasplist, kasp, link);
9676 		dns_kasp_detach(&kasp);
9677 	}
9678 
9679 	/* Same cleanup for cache list. */
9680 	while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
9681 		ISC_LIST_UNLINK(cachelist, nsc, link);
9682 		dns_cache_detach(&nsc->cache);
9683 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9684 	}
9685 
9686 	/* Cleanup for altsecrets list. */
9687 	while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) {
9688 		ISC_LIST_UNLINK(altsecrets, altsecret, link);
9689 		isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret));
9690 	}
9691 
9692 	/*
9693 	 * Record the time of most recent configuration
9694 	 */
9695 	tresult = isc_time_now(&named_g_configtime);
9696 	if (tresult != ISC_R_SUCCESS) {
9697 		named_main_earlyfatal("isc_time_now() failed: %s",
9698 				      isc_result_totext(result));
9699 	}
9700 
9701 	/* Relinquish exclusive access to configuration data. */
9702 	if (exclusive) {
9703 		isc_task_endexclusive(server->task);
9704 	}
9705 
9706 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9707 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9708 		      "load_configuration: %s", isc_result_totext(result));
9709 
9710 	return (result);
9711 }
9712 
9713 static isc_result_t
view_loaded(void * arg)9714 view_loaded(void *arg) {
9715 	isc_result_t result;
9716 	ns_zoneload_t *zl = (ns_zoneload_t *)arg;
9717 
9718 	/*
9719 	 * Force zone maintenance.  Do this after loading
9720 	 * so that we know when we need to force AXFR of
9721 	 * slave zones whose master files are missing.
9722 	 *
9723 	 * We use the zoneload reference counter to let us
9724 	 * know when all views are finished.
9725 	 */
9726 	if (isc_refcount_decrement(&zl->refs) == 1) {
9727 		named_server_t *server = zl->server;
9728 		bool reconfig = zl->reconfig;
9729 
9730 		isc_refcount_destroy(&zl->refs);
9731 		isc_mem_put(server->mctx, zl, sizeof(*zl));
9732 
9733 		/*
9734 		 * To maintain compatibility with log parsing tools that might
9735 		 * be looking for this string after "rndc reconfig", we keep it
9736 		 * as it is
9737 		 */
9738 		if (reconfig) {
9739 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9740 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9741 				      "any newly configured zones are now "
9742 				      "loaded");
9743 		} else {
9744 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9745 				      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9746 				      "all zones loaded");
9747 		}
9748 
9749 		CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
9750 			   "forcing zone maintenance");
9751 
9752 		named_os_started();
9753 
9754 #ifdef HAVE_FIPS_MODE
9755 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9756 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9757 			      "FIPS mode is %s",
9758 			      FIPS_mode() ? "enabled" : "disabled");
9759 #endif /* ifdef HAVE_FIPS_MODE */
9760 		atomic_store(&server->reload_status, NAMED_RELOAD_DONE);
9761 
9762 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9763 			      NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9764 			      "running");
9765 	}
9766 
9767 	return (ISC_R_SUCCESS);
9768 }
9769 
9770 static isc_result_t
load_zones(named_server_t * server,bool init,bool reconfig)9771 load_zones(named_server_t *server, bool init, bool reconfig) {
9772 	isc_result_t result;
9773 	isc_taskmgr_t *taskmgr = dns_zonemgr_gettaskmgr(server->zonemgr);
9774 	ns_zoneload_t *zl = NULL;
9775 	dns_view_t *view = NULL;
9776 
9777 	zl = isc_mem_get(server->mctx, sizeof(*zl));
9778 	zl->server = server;
9779 	zl->reconfig = reconfig;
9780 
9781 	result = isc_task_beginexclusive(server->task);
9782 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9783 
9784 	isc_refcount_init(&zl->refs, 1);
9785 
9786 	/*
9787 	 * Schedule zones to be loaded from disk.
9788 	 */
9789 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9790 	     view = ISC_LIST_NEXT(view, link))
9791 	{
9792 		if (view->managed_keys != NULL) {
9793 			result = dns_zone_load(view->managed_keys, false);
9794 			if (result != ISC_R_SUCCESS &&
9795 			    result != DNS_R_UPTODATE &&
9796 			    result != DNS_R_CONTINUE)
9797 			{
9798 				goto cleanup;
9799 			}
9800 		}
9801 		if (view->redirect != NULL) {
9802 			result = dns_zone_load(view->redirect, false);
9803 			if (result != ISC_R_SUCCESS &&
9804 			    result != DNS_R_UPTODATE &&
9805 			    result != DNS_R_CONTINUE)
9806 			{
9807 				goto cleanup;
9808 			}
9809 		}
9810 
9811 		/*
9812 		 * 'dns_view_asyncload' calls view_loaded if there are no
9813 		 * zones.
9814 		 */
9815 		isc_refcount_increment(&zl->refs);
9816 		result = dns_view_asyncload(view, reconfig, view_loaded, zl);
9817 		if (result != ISC_R_SUCCESS) {
9818 			isc_refcount_decrement1(&zl->refs);
9819 			goto cleanup;
9820 		}
9821 	}
9822 
9823 cleanup:
9824 	if (isc_refcount_decrement(&zl->refs) == 1) {
9825 		isc_refcount_destroy(&zl->refs);
9826 		isc_mem_put(server->mctx, zl, sizeof(*zl));
9827 	}
9828 
9829 	if (init) {
9830 		/*
9831 		 * If we're setting up the server for the first time, set
9832 		 * the task manager into privileged mode; this ensures
9833 		 * that no other tasks will begin to run until after zone
9834 		 * loading is complete. We won't return from exclusive mode
9835 		 * until the loading is finished; we can then drop out of
9836 		 * privileged mode.
9837 		 *
9838 		 * We do *not* want to do this in the case of reload or
9839 		 * reconfig, as loading a large zone could cause the server
9840 		 * to be inactive for too long a time.
9841 		 */
9842 		isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
9843 		isc_task_endexclusive(server->task);
9844 		isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal);
9845 	} else {
9846 		isc_task_endexclusive(server->task);
9847 	}
9848 
9849 	return (result);
9850 }
9851 
9852 static void
run_server(isc_task_t * task,isc_event_t * event)9853 run_server(isc_task_t *task, isc_event_t *event) {
9854 	isc_result_t result;
9855 	named_server_t *server = (named_server_t *)event->ev_arg;
9856 	dns_geoip_databases_t *geoip;
9857 
9858 	INSIST(task == server->task);
9859 
9860 	isc_event_free(&event);
9861 
9862 	CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_netmgr,
9863 					  &named_g_dispatchmgr),
9864 		   "creating dispatch manager");
9865 
9866 	dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
9867 
9868 #if defined(HAVE_GEOIP2)
9869 	geoip = named_g_geoip;
9870 #else  /* if defined(HAVE_GEOIP2) */
9871 	geoip = NULL;
9872 #endif /* if defined(HAVE_GEOIP2) */
9873 
9874 	CHECKFATAL(ns_interfacemgr_create(
9875 			   named_g_mctx, server->sctx, named_g_taskmgr,
9876 			   named_g_timermgr, named_g_socketmgr, named_g_netmgr,
9877 			   named_g_dispatchmgr, server->task, geoip,
9878 			   named_g_cpus, &server->interfacemgr),
9879 		   "creating interface manager");
9880 
9881 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9882 				    NULL, NULL, server->task,
9883 				    interface_timer_tick, server,
9884 				    &server->interface_timer),
9885 		   "creating interface timer");
9886 
9887 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9888 				    NULL, NULL, server->task,
9889 				    heartbeat_timer_tick, server,
9890 				    &server->heartbeat_timer),
9891 		   "creating heartbeat timer");
9892 
9893 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9894 				    NULL, NULL, server->task, tat_timer_tick,
9895 				    server, &server->tat_timer),
9896 		   "creating trust anchor telemetry timer");
9897 
9898 	CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9899 				    NULL, NULL, server->task, pps_timer_tick,
9900 				    server, &server->pps_timer),
9901 		   "creating pps timer");
9902 
9903 	CHECKFATAL(
9904 		cfg_parser_create(named_g_mctx, named_g_lctx, &named_g_parser),
9905 		"creating default configuration parser");
9906 
9907 	CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx,
9908 				     &named_g_addparser),
9909 		   "creating additional configuration parser");
9910 
9911 	CHECKFATAL(load_configuration(named_g_conffile, server, true),
9912 		   "loading configuration");
9913 
9914 	CHECKFATAL(load_zones(server, true, false), "loading zones");
9915 #ifdef ENABLE_AFL
9916 	named_g_run_done = true;
9917 #endif /* ifdef ENABLE_AFL */
9918 }
9919 
9920 void
named_server_flushonshutdown(named_server_t * server,bool flush)9921 named_server_flushonshutdown(named_server_t *server, bool flush) {
9922 	REQUIRE(NAMED_SERVER_VALID(server));
9923 
9924 	server->flushonshutdown = flush;
9925 }
9926 
9927 static void
shutdown_server(isc_task_t * task,isc_event_t * event)9928 shutdown_server(isc_task_t *task, isc_event_t *event) {
9929 	isc_result_t result;
9930 	dns_view_t *view, *view_next = NULL;
9931 	dns_kasp_t *kasp, *kasp_next = NULL;
9932 	named_server_t *server = (named_server_t *)event->ev_arg;
9933 	bool flush = server->flushonshutdown;
9934 	named_cache_t *nsc;
9935 
9936 	UNUSED(task);
9937 	INSIST(task == server->task);
9938 
9939 	/*
9940 	 * We need to shutdown the interface before going
9941 	 * exclusive (which would pause the netmgr).
9942 	 */
9943 	ns_interfacemgr_shutdown(server->interfacemgr);
9944 
9945 	result = isc_task_beginexclusive(server->task);
9946 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
9947 
9948 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9949 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "shutting down%s",
9950 		      flush ? ": flushing changes" : "");
9951 
9952 	named_statschannels_shutdown(server);
9953 	named_controls_shutdown(server->controls);
9954 	end_reserved_dispatches(server, true);
9955 	cleanup_session_key(server, server->mctx);
9956 
9957 	if (named_g_aclconfctx != NULL) {
9958 		cfg_aclconfctx_detach(&named_g_aclconfctx);
9959 	}
9960 
9961 	cfg_obj_destroy(named_g_parser, &named_g_config);
9962 	cfg_parser_destroy(&named_g_parser);
9963 	cfg_parser_destroy(&named_g_addparser);
9964 
9965 	(void)named_server_saventa(server);
9966 
9967 	for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL;
9968 	     kasp = kasp_next) {
9969 		kasp_next = ISC_LIST_NEXT(kasp, link);
9970 		ISC_LIST_UNLINK(server->kasplist, kasp, link);
9971 		dns_kasp_detach(&kasp);
9972 	}
9973 
9974 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9975 	     view = view_next) {
9976 		view_next = ISC_LIST_NEXT(view, link);
9977 		ISC_LIST_UNLINK(server->viewlist, view, link);
9978 		if (flush) {
9979 			dns_view_flushanddetach(&view);
9980 		} else {
9981 			dns_view_detach(&view);
9982 		}
9983 	}
9984 
9985 	/*
9986 	 * Shut down all dyndb instances.
9987 	 */
9988 	dns_dyndb_cleanup(true);
9989 
9990 	while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
9991 		ISC_LIST_UNLINK(server->cachelist, nsc, link);
9992 		dns_cache_detach(&nsc->cache);
9993 		isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9994 	}
9995 
9996 	isc_timer_detach(&server->interface_timer);
9997 	isc_timer_detach(&server->heartbeat_timer);
9998 	isc_timer_detach(&server->pps_timer);
9999 	isc_timer_detach(&server->tat_timer);
10000 
10001 	ns_interfacemgr_detach(&server->interfacemgr);
10002 
10003 	dns_dispatchmgr_detach(&named_g_dispatchmgr);
10004 
10005 	dns_zonemgr_shutdown(server->zonemgr);
10006 
10007 	if (named_g_sessionkey != NULL) {
10008 		dns_tsigkey_detach(&named_g_sessionkey);
10009 		dns_name_free(&named_g_sessionkeyname, server->mctx);
10010 	}
10011 #if defined(HAVE_GEOIP2)
10012 	named_geoip_shutdown();
10013 #endif /* HAVE_GEOIP2 */
10014 
10015 	dns_db_detach(&server->in_roothints);
10016 
10017 	isc_task_endexclusive(server->task);
10018 
10019 	isc_task_detach(&server->task);
10020 
10021 	isc_event_free(&event);
10022 }
10023 
10024 /*%
10025  * Find a view that matches the source and destination addresses of a query.
10026  */
10027 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)10028 get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
10029 		  dns_message_t *message, dns_aclenv_t *env,
10030 		  isc_result_t *sigresult, dns_view_t **viewp) {
10031 	dns_view_t *view;
10032 
10033 	REQUIRE(message != NULL);
10034 	REQUIRE(sigresult != NULL);
10035 	REQUIRE(viewp != NULL && *viewp == NULL);
10036 
10037 	for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
10038 	     view = ISC_LIST_NEXT(view, link))
10039 	{
10040 		if (message->rdclass == view->rdclass ||
10041 		    message->rdclass == dns_rdataclass_any) {
10042 			const dns_name_t *tsig = NULL;
10043 
10044 			*sigresult = dns_message_rechecksig(message, view);
10045 			if (*sigresult == ISC_R_SUCCESS) {
10046 				dns_tsigkey_t *tsigkey;
10047 
10048 				tsigkey = message->tsigkey;
10049 				tsig = dns_tsigkey_identity(tsigkey);
10050 			}
10051 
10052 			if (dns_acl_allowed(srcaddr, tsig, view->matchclients,
10053 					    env) &&
10054 			    dns_acl_allowed(destaddr, tsig,
10055 					    view->matchdestinations, env) &&
10056 			    !(view->matchrecursiveonly &&
10057 			      (message->flags & DNS_MESSAGEFLAG_RD) == 0))
10058 			{
10059 				dns_view_attach(view, viewp);
10060 				return (ISC_R_SUCCESS);
10061 			}
10062 		}
10063 	}
10064 
10065 	return (ISC_R_NOTFOUND);
10066 }
10067 
10068 void
named_server_create(isc_mem_t * mctx,named_server_t ** serverp)10069 named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
10070 	isc_result_t result;
10071 	named_server_t *server = isc_mem_get(mctx, sizeof(*server));
10072 
10073 	if (server == NULL) {
10074 		fatal(server, "allocating server object", ISC_R_NOMEMORY);
10075 	}
10076 
10077 	server->mctx = mctx;
10078 	server->task = NULL;
10079 	server->zonemgr = NULL;
10080 
10081 #ifdef USE_DNSRPS
10082 	CHECKFATAL(dns_dnsrps_server_create(), "initializing RPZ service "
10083 					       "interface");
10084 #endif /* ifdef USE_DNSRPS */
10085 
10086 	/* Initialize server data structures. */
10087 	server->interfacemgr = NULL;
10088 	ISC_LIST_INIT(server->kasplist);
10089 	ISC_LIST_INIT(server->viewlist);
10090 	server->in_roothints = NULL;
10091 
10092 	/* Must be first. */
10093 	CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine), "initializing "
10094 							       "DST");
10095 
10096 	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
10097 				     &server->in_roothints),
10098 		   "setting up root hints");
10099 
10100 	atomic_init(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10101 
10102 	/*
10103 	 * Setup the server task, which is responsible for coordinating
10104 	 * startup and shutdown of the server, as well as all exclusive
10105 	 * tasks.
10106 	 */
10107 	CHECKFATAL(isc_task_create_bound(named_g_taskmgr, 0, &server->task, 0),
10108 		   "creating server task");
10109 	isc_task_setname(server->task, "server", server);
10110 	isc_taskmgr_setexcltask(named_g_taskmgr, server->task);
10111 
10112 	server->sctx = NULL;
10113 	CHECKFATAL(ns_server_create(mctx, get_matching_view, &server->sctx),
10114 		   "creating server context");
10115 
10116 #if defined(HAVE_GEOIP2)
10117 	/*
10118 	 * GeoIP must be initialized before the interface
10119 	 * manager (which includes the ACL environment)
10120 	 * is created.
10121 	 */
10122 	named_geoip_init();
10123 #endif /* HAVE_GEOIP2 */
10124 
10125 #ifdef ENABLE_AFL
10126 	server->sctx->fuzztype = named_g_fuzz_type;
10127 	server->sctx->fuzznotify = named_fuzz_notify;
10128 #endif /* ifdef ENABLE_AFL */
10129 
10130 	CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
10131 		   "isc_task_onshutdown");
10132 	CHECKFATAL(
10133 		isc_app_onrun(named_g_mctx, server->task, run_server, server),
10134 		"isc_app_onrun");
10135 
10136 	server->interface_timer = NULL;
10137 	server->heartbeat_timer = NULL;
10138 	server->pps_timer = NULL;
10139 	server->tat_timer = NULL;
10140 
10141 	server->interface_interval = 0;
10142 	server->heartbeat_interval = 0;
10143 
10144 	CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr,
10145 				      named_g_timermgr, named_g_netmgr,
10146 				      &server->zonemgr),
10147 		   "dns_zonemgr_create");
10148 	CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_"
10149 							       "setsize");
10150 
10151 	server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
10152 	CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
10153 		   "isc_mem_strdup");
10154 
10155 	server->bindkeysfile = isc_mem_strdup(server->mctx,
10156 					      named_g_defaultbindkeys);
10157 	CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY
10158 						: ISC_R_SUCCESS,
10159 		   "isc_mem_strdup");
10160 
10161 	server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
10162 	CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
10163 		   "isc_mem_strdup");
10164 
10165 	server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots");
10166 	CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY
10167 						: ISC_R_SUCCESS,
10168 		   "isc_mem_strdup");
10169 
10170 	server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
10171 	CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
10172 		   "isc_mem_strdup");
10173 
10174 	server->hostname_set = false;
10175 	server->hostname = NULL;
10176 	server->version_set = false;
10177 	server->version = NULL;
10178 
10179 	server->zonestats = NULL;
10180 	server->resolverstats = NULL;
10181 	server->sockstats = NULL;
10182 	CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
10183 				    isc_sockstatscounter_max),
10184 		   "isc_stats_create");
10185 	isc_socketmgr_setstats(named_g_socketmgr, server->sockstats);
10186 	isc_nm_setstats(named_g_netmgr, server->sockstats);
10187 
10188 	CHECKFATAL(isc_stats_create(named_g_mctx, &server->zonestats,
10189 				    dns_zonestatscounter_max),
10190 		   "dns_stats_create (zone)");
10191 
10192 	CHECKFATAL(isc_stats_create(named_g_mctx, &server->resolverstats,
10193 				    dns_resstatscounter_max),
10194 		   "dns_stats_create (resolver)");
10195 
10196 	server->flushonshutdown = false;
10197 
10198 	server->controls = NULL;
10199 	CHECKFATAL(named_controls_create(server, &server->controls),
10200 		   "named_controls_create");
10201 	server->dispatchgen = 0;
10202 	ISC_LIST_INIT(server->dispatches);
10203 
10204 	ISC_LIST_INIT(server->statschannels);
10205 
10206 	ISC_LIST_INIT(server->cachelist);
10207 
10208 	server->sessionkey = NULL;
10209 	server->session_keyfile = NULL;
10210 	server->session_keyname = NULL;
10211 	server->session_keyalg = DST_ALG_UNKNOWN;
10212 	server->session_keybits = 0;
10213 
10214 	server->lockfile = NULL;
10215 
10216 	server->dtenv = NULL;
10217 
10218 	server->magic = NAMED_SERVER_MAGIC;
10219 	*serverp = server;
10220 }
10221 
10222 void
named_server_destroy(named_server_t ** serverp)10223 named_server_destroy(named_server_t **serverp) {
10224 	named_server_t *server = *serverp;
10225 	REQUIRE(NAMED_SERVER_VALID(server));
10226 
10227 #ifdef HAVE_DNSTAP
10228 	if (server->dtenv != NULL) {
10229 		dns_dt_detach(&server->dtenv);
10230 	}
10231 #endif /* HAVE_DNSTAP */
10232 
10233 #ifdef USE_DNSRPS
10234 	dns_dnsrps_server_destroy();
10235 #endif /* ifdef USE_DNSRPS */
10236 
10237 	named_controls_destroy(&server->controls);
10238 
10239 	isc_stats_detach(&server->zonestats);
10240 	isc_stats_detach(&server->sockstats);
10241 	isc_stats_detach(&server->resolverstats);
10242 
10243 	if (server->sctx != NULL) {
10244 		ns_server_detach(&server->sctx);
10245 	}
10246 
10247 	isc_mem_free(server->mctx, server->statsfile);
10248 	isc_mem_free(server->mctx, server->bindkeysfile);
10249 	isc_mem_free(server->mctx, server->dumpfile);
10250 	isc_mem_free(server->mctx, server->secrootsfile);
10251 	isc_mem_free(server->mctx, server->recfile);
10252 
10253 	if (server->version != NULL) {
10254 		isc_mem_free(server->mctx, server->version);
10255 	}
10256 	if (server->hostname != NULL) {
10257 		isc_mem_free(server->mctx, server->hostname);
10258 	}
10259 	if (server->lockfile != NULL) {
10260 		isc_mem_free(server->mctx, server->lockfile);
10261 	}
10262 
10263 	if (server->zonemgr != NULL) {
10264 		dns_zonemgr_detach(&server->zonemgr);
10265 	}
10266 
10267 	dst_lib_destroy();
10268 
10269 	INSIST(ISC_LIST_EMPTY(server->kasplist));
10270 	INSIST(ISC_LIST_EMPTY(server->viewlist));
10271 	INSIST(ISC_LIST_EMPTY(server->cachelist));
10272 
10273 	server->magic = 0;
10274 	isc_mem_put(server->mctx, server, sizeof(*server));
10275 	*serverp = NULL;
10276 }
10277 
10278 static void
fatal(named_server_t * server,const char * msg,isc_result_t result)10279 fatal(named_server_t *server, const char *msg, isc_result_t result) {
10280 	if (server != NULL && server->task != NULL) {
10281 		/*
10282 		 * Prevent races between the OpenSSL on_exit registered
10283 		 * function and any other OpenSSL calls from other tasks
10284 		 * by requesting exclusive access to the task manager.
10285 		 */
10286 		(void)isc_task_beginexclusive(server->task);
10287 	}
10288 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10289 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, "%s: %s", msg,
10290 		      isc_result_totext(result));
10291 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10292 		      NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
10293 		      "exiting (due to fatal error)");
10294 	named_os_shutdown();
10295 	exit(1);
10296 }
10297 
10298 static void
start_reserved_dispatches(named_server_t * server)10299 start_reserved_dispatches(named_server_t *server) {
10300 	REQUIRE(NAMED_SERVER_VALID(server));
10301 
10302 	server->dispatchgen++;
10303 }
10304 
10305 static void
end_reserved_dispatches(named_server_t * server,bool all)10306 end_reserved_dispatches(named_server_t *server, bool all) {
10307 	named_dispatch_t *dispatch, *nextdispatch;
10308 
10309 	REQUIRE(NAMED_SERVER_VALID(server));
10310 
10311 	for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10312 	     dispatch = nextdispatch)
10313 	{
10314 		nextdispatch = ISC_LIST_NEXT(dispatch, link);
10315 		if (!all && server->dispatchgen == dispatch->dispatchgen) {
10316 			continue;
10317 		}
10318 		ISC_LIST_UNLINK(server->dispatches, dispatch, link);
10319 		dns_dispatch_detach(&dispatch->dispatch);
10320 		isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10321 	}
10322 }
10323 
10324 void
named_add_reserved_dispatch(named_server_t * server,const isc_sockaddr_t * addr)10325 named_add_reserved_dispatch(named_server_t *server,
10326 			    const isc_sockaddr_t *addr) {
10327 	named_dispatch_t *dispatch;
10328 	in_port_t port;
10329 	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
10330 	isc_result_t result;
10331 
10332 	REQUIRE(NAMED_SERVER_VALID(server));
10333 
10334 	port = isc_sockaddr_getport(addr);
10335 	if (port == 0 || port >= 1024) {
10336 		return;
10337 	}
10338 
10339 	for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10340 	     dispatch = ISC_LIST_NEXT(dispatch, link))
10341 	{
10342 		if (isc_sockaddr_equal(&dispatch->addr, addr)) {
10343 			break;
10344 		}
10345 	}
10346 	if (dispatch != NULL) {
10347 		dispatch->dispatchgen = server->dispatchgen;
10348 		return;
10349 	}
10350 
10351 	dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
10352 
10353 	dispatch->addr = *addr;
10354 	dispatch->dispatchgen = server->dispatchgen;
10355 	dispatch->dispatch = NULL;
10356 
10357 	result = dns_dispatch_createudp(named_g_dispatchmgr, &dispatch->addr,
10358 					&dispatch->dispatch);
10359 	if (result != ISC_R_SUCCESS) {
10360 		goto cleanup;
10361 	}
10362 
10363 	ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
10364 
10365 	return;
10366 
10367 cleanup:
10368 	isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10369 	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
10370 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10371 		      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
10372 		      "unable to create dispatch for reserved port %s: %s",
10373 		      addrbuf, isc_result_totext(result));
10374 }
10375 
10376 static isc_result_t
loadconfig(named_server_t * server)10377 loadconfig(named_server_t *server) {
10378 	isc_result_t result;
10379 	start_reserved_dispatches(server);
10380 	result = load_configuration(named_g_conffile, server, false);
10381 	if (result == ISC_R_SUCCESS) {
10382 		end_reserved_dispatches(server, false);
10383 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10384 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10385 			      "reloading configuration succeeded");
10386 	} else {
10387 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10388 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10389 			      "reloading configuration failed: %s",
10390 			      isc_result_totext(result));
10391 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10392 	}
10393 
10394 	return (result);
10395 }
10396 
10397 static isc_result_t
reload(named_server_t * server)10398 reload(named_server_t *server) {
10399 	isc_result_t result;
10400 
10401 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10402 
10403 	CHECK(loadconfig(server));
10404 
10405 	result = load_zones(server, false, false);
10406 	if (result == ISC_R_SUCCESS) {
10407 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10408 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10409 			      "reloading zones succeeded");
10410 	} else {
10411 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10412 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10413 			      "reloading zones failed: %s",
10414 			      isc_result_totext(result));
10415 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10416 	}
10417 cleanup:
10418 	return (result);
10419 }
10420 
10421 /*
10422  * Handle a reload event (from SIGHUP).
10423  */
10424 static void
named_server_reload(isc_task_t * task,isc_event_t * event)10425 named_server_reload(isc_task_t *task, isc_event_t *event) {
10426 	named_server_t *server = (named_server_t *)event->ev_sender;
10427 
10428 	INSIST(task == server->task);
10429 	UNUSED(task);
10430 
10431 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10432 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10433 		      "received SIGHUP signal to reload zones");
10434 	(void)reload(server);
10435 
10436 	isc_event_free(&event);
10437 }
10438 
10439 void
named_server_reloadwanted(named_server_t * server)10440 named_server_reloadwanted(named_server_t *server) {
10441 	isc_event_t *event = isc_event_allocate(
10442 		named_g_mctx, server, NAMED_EVENT_RELOAD, named_server_reload,
10443 		NULL, sizeof(isc_event_t));
10444 	isc_task_send(server->task, &event);
10445 }
10446 
10447 void
named_server_scan_interfaces(named_server_t * server)10448 named_server_scan_interfaces(named_server_t *server) {
10449 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10450 		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
10451 		      "automatic interface rescan");
10452 
10453 	ns_interfacemgr_scan(server->interfacemgr, true);
10454 }
10455 
10456 /*
10457  * Get the next token from lexer 'lex'.
10458  *
10459  * NOTE: the token value for string tokens always uses the same pointer
10460  * value.  Multiple calls to this function on the same lexer will always
10461  * return either that value (lex->data) or NULL. It is necessary to copy
10462  * the token into local storage if it needs to be referenced after the next
10463  * call to next_token().
10464  */
10465 static char *
next_token(isc_lex_t * lex,isc_buffer_t ** text)10466 next_token(isc_lex_t *lex, isc_buffer_t **text) {
10467 	isc_result_t result;
10468 	isc_token_t token;
10469 
10470 	token.type = isc_tokentype_unknown;
10471 	result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING,
10472 				  &token);
10473 
10474 	switch (result) {
10475 	case ISC_R_NOMORE:
10476 		(void)isc_lex_close(lex);
10477 		break;
10478 	case ISC_R_SUCCESS:
10479 		if (token.type == isc_tokentype_eof) {
10480 			(void)isc_lex_close(lex);
10481 		}
10482 		break;
10483 	case ISC_R_NOSPACE:
10484 		if (text != NULL) {
10485 			(void)putstr(text, "token too large");
10486 			(void)putnull(text);
10487 		}
10488 		return (NULL);
10489 	default:
10490 		if (text != NULL) {
10491 			(void)putstr(text, isc_result_totext(result));
10492 			(void)putnull(text);
10493 		}
10494 		return (NULL);
10495 	}
10496 
10497 	if (token.type == isc_tokentype_string ||
10498 	    token.type == isc_tokentype_qstring) {
10499 		return (token.value.as_textregion.base);
10500 	}
10501 
10502 	return (NULL);
10503 }
10504 
10505 /*
10506  * Find the zone specified in the control channel command, if any.
10507  * If a zone is specified, point '*zonep' at it, otherwise
10508  * set '*zonep' to NULL, and f 'zonename' is not NULL, copy
10509  * the zone name into it (N.B. 'zonename' must have space to hold
10510  * a full DNS name).
10511  *
10512  * If 'zonetxt' is set, the caller has already pulled a token
10513  * off the command line that is to be used as the zone name. (This
10514  * is sometimes done when it's necessary to check for an optional
10515  * argument before the zone name, as in "rndc sync [-clean] zone".)
10516  */
10517 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)10518 zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
10519 	       dns_zone_t **zonep, char *zonename, isc_buffer_t **text,
10520 	       bool skip) {
10521 	char *ptr;
10522 	char *classtxt;
10523 	const char *viewtxt = NULL;
10524 	dns_fixedname_t fname;
10525 	dns_name_t *name;
10526 	isc_result_t result;
10527 	dns_view_t *view = NULL;
10528 	dns_rdataclass_t rdclass;
10529 	char problem[DNS_NAME_FORMATSIZE + 500] = "";
10530 	char zonebuf[DNS_NAME_FORMATSIZE];
10531 	bool redirect = false;
10532 
10533 	REQUIRE(zonep != NULL && *zonep == NULL);
10534 
10535 	if (skip) {
10536 		/* Skip the command name. */
10537 		ptr = next_token(lex, text);
10538 		if (ptr == NULL) {
10539 			return (ISC_R_UNEXPECTEDEND);
10540 		}
10541 	}
10542 
10543 	/* Look for the zone name. */
10544 	if (zonetxt == NULL) {
10545 		zonetxt = next_token(lex, text);
10546 	}
10547 	if (zonetxt == NULL) {
10548 		return (ISC_R_SUCCESS);
10549 	}
10550 
10551 	/* Copy zonetxt because it'll be overwritten by next_token() */
10552 	/* To locate a zone named "-redirect" use "-redirect." */
10553 	if (strcmp(zonetxt, "-redirect") == 0) {
10554 		redirect = true;
10555 		strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE);
10556 	} else {
10557 		strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE);
10558 	}
10559 	if (zonename != NULL) {
10560 		strlcpy(zonename, redirect ? "." : zonetxt,
10561 			DNS_NAME_FORMATSIZE);
10562 	}
10563 
10564 	name = dns_fixedname_initname(&fname);
10565 	CHECK(dns_name_fromstring(name, zonebuf, 0, NULL));
10566 
10567 	/* Look for the optional class name. */
10568 	classtxt = next_token(lex, text);
10569 	if (classtxt != NULL) {
10570 		isc_textregion_t r;
10571 		r.base = classtxt;
10572 		r.length = strlen(classtxt);
10573 		CHECK(dns_rdataclass_fromtext(&rdclass, &r));
10574 
10575 		/* Look for the optional view name. */
10576 		viewtxt = next_token(lex, text);
10577 	} else {
10578 		rdclass = dns_rdataclass_in;
10579 	}
10580 
10581 	if (viewtxt == NULL) {
10582 		if (redirect) {
10583 			result = dns_viewlist_find(&server->viewlist,
10584 						   "_default",
10585 						   dns_rdataclass_in, &view);
10586 			if (result != ISC_R_SUCCESS || view->redirect == NULL) {
10587 				result = ISC_R_NOTFOUND;
10588 				snprintf(problem, sizeof(problem),
10589 					 "redirect zone not found in "
10590 					 "_default view");
10591 			} else {
10592 				dns_zone_attach(view->redirect, zonep);
10593 				result = ISC_R_SUCCESS;
10594 			}
10595 		} else {
10596 			result = dns_viewlist_findzone(&server->viewlist, name,
10597 						       (classtxt == NULL),
10598 						       rdclass, zonep);
10599 			if (result == ISC_R_NOTFOUND) {
10600 				snprintf(problem, sizeof(problem),
10601 					 "no matching zone '%s' in any view",
10602 					 zonebuf);
10603 			} else if (result == ISC_R_MULTIPLE) {
10604 				snprintf(problem, sizeof(problem),
10605 					 "zone '%s' was found in multiple "
10606 					 "views",
10607 					 zonebuf);
10608 			}
10609 		}
10610 	} else {
10611 		result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass,
10612 					   &view);
10613 		if (result != ISC_R_SUCCESS) {
10614 			snprintf(problem, sizeof(problem),
10615 				 "no matching view '%s'", viewtxt);
10616 			goto report;
10617 		}
10618 
10619 		if (redirect) {
10620 			if (view->redirect != NULL) {
10621 				dns_zone_attach(view->redirect, zonep);
10622 				result = ISC_R_SUCCESS;
10623 			} else {
10624 				result = ISC_R_NOTFOUND;
10625 			}
10626 		} else {
10627 			result = dns_zt_find(view->zonetable, name, 0, NULL,
10628 					     zonep);
10629 		}
10630 		if (result != ISC_R_SUCCESS) {
10631 			snprintf(problem, sizeof(problem),
10632 				 "no matching zone '%s' in view '%s'", zonebuf,
10633 				 viewtxt);
10634 		}
10635 	}
10636 
10637 	/* Partial match? */
10638 	if (result != ISC_R_SUCCESS && *zonep != NULL) {
10639 		dns_zone_detach(zonep);
10640 	}
10641 	if (result == DNS_R_PARTIALMATCH) {
10642 		result = ISC_R_NOTFOUND;
10643 	}
10644 report:
10645 	if (result != ISC_R_SUCCESS) {
10646 		isc_result_t tresult;
10647 
10648 		tresult = putstr(text, problem);
10649 		if (tresult == ISC_R_SUCCESS) {
10650 			(void)putnull(text);
10651 		}
10652 	}
10653 
10654 cleanup:
10655 	if (view != NULL) {
10656 		dns_view_detach(&view);
10657 	}
10658 
10659 	return (result);
10660 }
10661 
10662 /*
10663  * Act on a "retransfer" command from the command channel.
10664  */
10665 isc_result_t
named_server_retransfercommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10666 named_server_retransfercommand(named_server_t *server, isc_lex_t *lex,
10667 			       isc_buffer_t **text) {
10668 	isc_result_t result;
10669 	dns_zone_t *zone = NULL;
10670 	dns_zone_t *raw = NULL;
10671 	dns_zonetype_t type;
10672 
10673 	REQUIRE(text != NULL);
10674 
10675 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10676 	if (result != ISC_R_SUCCESS) {
10677 		return (result);
10678 	}
10679 	if (zone == NULL) {
10680 		return (ISC_R_UNEXPECTEDEND);
10681 	}
10682 	dns_zone_getraw(zone, &raw);
10683 	if (raw != NULL) {
10684 		dns_zone_detach(&zone);
10685 		dns_zone_attach(raw, &zone);
10686 		dns_zone_detach(&raw);
10687 	}
10688 	type = dns_zone_gettype(zone);
10689 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
10690 	    type == dns_zone_stub ||
10691 	    (type == dns_zone_redirect &&
10692 	     dns_zone_getredirecttype(zone) == dns_zone_secondary))
10693 	{
10694 		dns_zone_forcereload(zone);
10695 	} else {
10696 		(void)putstr(text, "retransfer: inappropriate zone type: ");
10697 		(void)putstr(text, dns_zonetype_name(type));
10698 		if (type == dns_zone_redirect) {
10699 			type = dns_zone_getredirecttype(zone);
10700 			(void)putstr(text, "(");
10701 			(void)putstr(text, dns_zonetype_name(type));
10702 			(void)putstr(text, ")");
10703 		}
10704 		(void)putnull(text);
10705 		result = ISC_R_FAILURE;
10706 	}
10707 	dns_zone_detach(&zone);
10708 	return (result);
10709 }
10710 
10711 /*
10712  * Act on a "reload" command from the command channel.
10713  */
10714 isc_result_t
named_server_reloadcommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10715 named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
10716 			   isc_buffer_t **text) {
10717 	isc_result_t result;
10718 	dns_zone_t *zone = NULL;
10719 	dns_zonetype_t type;
10720 	const char *msg = NULL;
10721 
10722 	REQUIRE(text != NULL);
10723 
10724 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10725 	if (result != ISC_R_SUCCESS) {
10726 		return (result);
10727 	}
10728 	if (zone == NULL) {
10729 		result = reload(server);
10730 		if (result == ISC_R_SUCCESS) {
10731 			msg = "server reload successful";
10732 		}
10733 	} else {
10734 		type = dns_zone_gettype(zone);
10735 		if (type == dns_zone_secondary || type == dns_zone_mirror ||
10736 		    type == dns_zone_stub)
10737 		{
10738 			dns_zone_refresh(zone);
10739 			dns_zone_detach(&zone);
10740 			msg = "zone refresh queued";
10741 		} else {
10742 			result = dns_zone_load(zone, false);
10743 			dns_zone_detach(&zone);
10744 			switch (result) {
10745 			case ISC_R_SUCCESS:
10746 				msg = "zone reload successful";
10747 				break;
10748 			case DNS_R_CONTINUE:
10749 				msg = "zone reload queued";
10750 				result = ISC_R_SUCCESS;
10751 				break;
10752 			case DNS_R_UPTODATE:
10753 				msg = "zone reload up-to-date";
10754 				result = ISC_R_SUCCESS;
10755 				break;
10756 			default:
10757 				/* failure message will be generated by rndc */
10758 				break;
10759 			}
10760 		}
10761 	}
10762 	if (msg != NULL) {
10763 		(void)putstr(text, msg);
10764 		(void)putnull(text);
10765 	}
10766 	return (result);
10767 }
10768 
10769 /*
10770  * Act on a "reconfig" command from the command channel.
10771  */
10772 isc_result_t
named_server_reconfigcommand(named_server_t * server)10773 named_server_reconfigcommand(named_server_t *server) {
10774 	isc_result_t result;
10775 	atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10776 
10777 	CHECK(loadconfig(server));
10778 
10779 	result = load_zones(server, false, true);
10780 	if (result == ISC_R_SUCCESS) {
10781 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10782 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10783 			      "scheduled loading new zones");
10784 	} else {
10785 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10786 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10787 			      "loading new zones failed: %s",
10788 			      isc_result_totext(result));
10789 		atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10790 	}
10791 cleanup:
10792 	return (result);
10793 }
10794 
10795 /*
10796  * Act on a "notify" command from the command channel.
10797  */
10798 isc_result_t
named_server_notifycommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10799 named_server_notifycommand(named_server_t *server, isc_lex_t *lex,
10800 			   isc_buffer_t **text) {
10801 	isc_result_t result;
10802 	dns_zone_t *zone = NULL;
10803 	const char msg[] = "zone notify queued";
10804 
10805 	REQUIRE(text != NULL);
10806 
10807 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10808 	if (result != ISC_R_SUCCESS) {
10809 		return (result);
10810 	}
10811 	if (zone == NULL) {
10812 		return (ISC_R_UNEXPECTEDEND);
10813 	}
10814 
10815 	dns_zone_notify(zone);
10816 	dns_zone_detach(&zone);
10817 	(void)putstr(text, msg);
10818 	(void)putnull(text);
10819 
10820 	return (ISC_R_SUCCESS);
10821 }
10822 
10823 /*
10824  * Act on a "refresh" command from the command channel.
10825  */
10826 isc_result_t
named_server_refreshcommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10827 named_server_refreshcommand(named_server_t *server, isc_lex_t *lex,
10828 			    isc_buffer_t **text) {
10829 	isc_result_t result;
10830 	dns_zone_t *zone = NULL, *raw = NULL;
10831 	const char msg1[] = "zone refresh queued";
10832 	const char msg2[] = "not a slave, mirror, or stub zone";
10833 	dns_zonetype_t type;
10834 
10835 	REQUIRE(text != NULL);
10836 
10837 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10838 	if (result != ISC_R_SUCCESS) {
10839 		return (result);
10840 	}
10841 	if (zone == NULL) {
10842 		return (ISC_R_UNEXPECTEDEND);
10843 	}
10844 
10845 	dns_zone_getraw(zone, &raw);
10846 	if (raw != NULL) {
10847 		dns_zone_detach(&zone);
10848 		dns_zone_attach(raw, &zone);
10849 		dns_zone_detach(&raw);
10850 	}
10851 
10852 	type = dns_zone_gettype(zone);
10853 	if (type == dns_zone_secondary || type == dns_zone_mirror ||
10854 	    type == dns_zone_stub)
10855 	{
10856 		dns_zone_refresh(zone);
10857 		dns_zone_detach(&zone);
10858 		(void)putstr(text, msg1);
10859 		(void)putnull(text);
10860 		return (ISC_R_SUCCESS);
10861 	}
10862 
10863 	dns_zone_detach(&zone);
10864 	(void)putstr(text, msg2);
10865 	(void)putnull(text);
10866 	return (ISC_R_FAILURE);
10867 }
10868 
10869 isc_result_t
named_server_togglequerylog(named_server_t * server,isc_lex_t * lex)10870 named_server_togglequerylog(named_server_t *server, isc_lex_t *lex) {
10871 	bool prev, value;
10872 	char *ptr;
10873 
10874 	/* Skip the command name. */
10875 	ptr = next_token(lex, NULL);
10876 	if (ptr == NULL) {
10877 		return (ISC_R_UNEXPECTEDEND);
10878 	}
10879 
10880 	prev = ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES);
10881 
10882 	ptr = next_token(lex, NULL);
10883 	if (ptr == NULL) {
10884 		value = !prev;
10885 	} else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
10886 		   !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
10887 	{
10888 		value = true;
10889 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
10890 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
10891 	{
10892 		value = false;
10893 	} else {
10894 		return (DNS_R_SYNTAX);
10895 	}
10896 
10897 	if (value == prev) {
10898 		return (ISC_R_SUCCESS);
10899 	}
10900 
10901 	ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES, value);
10902 
10903 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10904 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10905 		      "query logging is now %s", value ? "on" : "off");
10906 	return (ISC_R_SUCCESS);
10907 }
10908 
10909 static isc_result_t
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)10910 listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
10911 		      cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
10912 		      ns_listenlist_t **target) {
10913 	isc_result_t result;
10914 	const cfg_listelt_t *element;
10915 	ns_listenlist_t *dlist = NULL;
10916 
10917 	REQUIRE(target != NULL && *target == NULL);
10918 
10919 	result = ns_listenlist_create(mctx, &dlist);
10920 	if (result != ISC_R_SUCCESS) {
10921 		return (result);
10922 	}
10923 
10924 	for (element = cfg_list_first(listenlist); element != NULL;
10925 	     element = cfg_list_next(element))
10926 	{
10927 		ns_listenelt_t *delt = NULL;
10928 		const cfg_obj_t *listener = cfg_listelt_value(element);
10929 		result = listenelt_fromconfig(listener, config, actx, mctx,
10930 					      family, &delt);
10931 		if (result != ISC_R_SUCCESS) {
10932 			goto cleanup;
10933 		}
10934 		ISC_LIST_APPEND(dlist->elts, delt, link);
10935 	}
10936 	*target = dlist;
10937 	return (ISC_R_SUCCESS);
10938 
10939 cleanup:
10940 	ns_listenlist_detach(&dlist);
10941 	return (result);
10942 }
10943 
10944 static const cfg_obj_t *
find_maplist(const cfg_obj_t * config,const char * listname,const char * name)10945 find_maplist(const cfg_obj_t *config, const char *listname, const char *name) {
10946 	isc_result_t result;
10947 	const cfg_obj_t *maplist = NULL;
10948 	const cfg_listelt_t *elt = NULL;
10949 
10950 	REQUIRE(config != NULL);
10951 	REQUIRE(name != NULL);
10952 
10953 	result = cfg_map_get(config, listname, &maplist);
10954 	if (result != ISC_R_SUCCESS) {
10955 		return (NULL);
10956 	}
10957 
10958 	for (elt = cfg_list_first(maplist); elt != NULL;
10959 	     elt = cfg_list_next(elt)) {
10960 		const cfg_obj_t *map = cfg_listelt_value(elt);
10961 		if (strcasecmp(cfg_obj_asstring(cfg_map_getname(map)), name) ==
10962 		    0) {
10963 			return (map);
10964 		}
10965 	}
10966 
10967 	return (NULL);
10968 }
10969 
10970 /*
10971  * Create a listen list from the corresponding configuration
10972  * data structure.
10973  */
10974 static isc_result_t
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)10975 listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
10976 		     cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
10977 		     ns_listenelt_t **target) {
10978 	isc_result_t result;
10979 	const cfg_obj_t *ltup = NULL;
10980 	const cfg_obj_t *tlsobj = NULL, *httpobj = NULL;
10981 	const cfg_obj_t *portobj = NULL, *dscpobj = NULL;
10982 	const cfg_obj_t *http_server = NULL;
10983 	in_port_t port = 0;
10984 	isc_dscp_t dscp = -1;
10985 	const char *key = NULL, *cert = NULL, *dhparam_file = NULL,
10986 		   *ciphers = NULL;
10987 	bool tls_prefer_server_ciphers = false,
10988 	     tls_prefer_server_ciphers_set = false;
10989 	bool tls_session_tickets = false, tls_session_tickets_set = false;
10990 	bool do_tls = false, no_tls = false, http = false;
10991 	ns_listenelt_t *delt = NULL;
10992 	uint32_t tls_protos = 0;
10993 	ns_listen_tls_params_t tls_params = { 0 };
10994 
10995 	REQUIRE(target != NULL && *target == NULL);
10996 
10997 	ltup = cfg_tuple_get(listener, "tuple");
10998 	RUNTIME_CHECK(ltup != NULL);
10999 
11000 	tlsobj = cfg_tuple_get(ltup, "tls");
11001 	if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) {
11002 		const char *tlsname = cfg_obj_asstring(tlsobj);
11003 
11004 		if (strcasecmp(tlsname, "none") == 0) {
11005 			no_tls = true;
11006 		} else if (strcasecmp(tlsname, "ephemeral") == 0) {
11007 			do_tls = true;
11008 		} else {
11009 			const cfg_obj_t *keyobj = NULL, *certobj = NULL,
11010 					*dhparam_obj = NULL;
11011 			const cfg_obj_t *tlsmap = NULL;
11012 			const cfg_obj_t *tls_proto_list = NULL;
11013 			const cfg_obj_t *ciphers_obj = NULL;
11014 			const cfg_obj_t *prefer_server_ciphers_obj = NULL;
11015 			const cfg_obj_t *session_tickets_obj = NULL;
11016 
11017 			do_tls = true;
11018 
11019 			tlsmap = find_maplist(config, "tls", tlsname);
11020 			if (tlsmap == NULL) {
11021 				cfg_obj_log(tlsobj, named_g_lctx, ISC_LOG_ERROR,
11022 					    "tls '%s' is not defined",
11023 					    cfg_obj_asstring(tlsobj));
11024 				return (ISC_R_FAILURE);
11025 			}
11026 
11027 			CHECK(cfg_map_get(tlsmap, "key-file", &keyobj));
11028 			key = cfg_obj_asstring(keyobj);
11029 
11030 			CHECK(cfg_map_get(tlsmap, "cert-file", &certobj));
11031 			cert = cfg_obj_asstring(certobj);
11032 
11033 			if (cfg_map_get(tlsmap, "protocols", &tls_proto_list) ==
11034 			    ISC_R_SUCCESS) {
11035 				const cfg_listelt_t *proto = NULL;
11036 				INSIST(tls_proto_list != NULL);
11037 				for (proto = cfg_list_first(tls_proto_list);
11038 				     proto != 0; proto = cfg_list_next(proto))
11039 				{
11040 					const cfg_obj_t *tls_proto_obj =
11041 						cfg_listelt_value(proto);
11042 					const char *tls_sver =
11043 						cfg_obj_asstring(tls_proto_obj);
11044 					const isc_tls_protocol_version_t ver =
11045 						isc_tls_protocol_name_to_version(
11046 							tls_sver);
11047 
11048 					INSIST(ver !=
11049 					       ISC_TLS_PROTO_VER_UNDEFINED);
11050 					INSIST(isc_tls_protocol_supported(ver));
11051 					tls_protos |= ver;
11052 				}
11053 			}
11054 
11055 			if (cfg_map_get(tlsmap, "dhparam-file", &dhparam_obj) ==
11056 			    ISC_R_SUCCESS) {
11057 				dhparam_file = cfg_obj_asstring(dhparam_obj);
11058 			}
11059 
11060 			if (cfg_map_get(tlsmap, "ciphers", &ciphers_obj) ==
11061 			    ISC_R_SUCCESS) {
11062 				ciphers = cfg_obj_asstring(ciphers_obj);
11063 			}
11064 
11065 			if (cfg_map_get(tlsmap, "prefer-server-ciphers",
11066 					&prefer_server_ciphers_obj) ==
11067 			    ISC_R_SUCCESS)
11068 			{
11069 				tls_prefer_server_ciphers = cfg_obj_asboolean(
11070 					prefer_server_ciphers_obj);
11071 				tls_prefer_server_ciphers_set = true;
11072 			}
11073 
11074 			if (cfg_map_get(tlsmap, "session-tickets",
11075 					&session_tickets_obj) == ISC_R_SUCCESS)
11076 			{
11077 				tls_session_tickets =
11078 					cfg_obj_asboolean(session_tickets_obj);
11079 				tls_session_tickets_set = true;
11080 			}
11081 		}
11082 	}
11083 
11084 	tls_params = (ns_listen_tls_params_t){
11085 		.key = key,
11086 		.cert = cert,
11087 		.protocols = tls_protos,
11088 		.dhparam_file = dhparam_file,
11089 		.ciphers = ciphers,
11090 		.prefer_server_ciphers = tls_prefer_server_ciphers,
11091 		.prefer_server_ciphers_set = tls_prefer_server_ciphers_set,
11092 		.session_tickets = tls_session_tickets,
11093 		.session_tickets_set = tls_session_tickets_set
11094 	};
11095 
11096 	httpobj = cfg_tuple_get(ltup, "http");
11097 	if (httpobj != NULL && cfg_obj_isstring(httpobj)) {
11098 		const char *httpname = cfg_obj_asstring(httpobj);
11099 
11100 		if (!do_tls && !no_tls) {
11101 			return (ISC_R_FAILURE);
11102 		}
11103 
11104 		http_server = find_maplist(config, "http", httpname);
11105 		if (http_server == NULL && strcasecmp(httpname, "default") != 0)
11106 		{
11107 			cfg_obj_log(httpobj, named_g_lctx, ISC_LOG_ERROR,
11108 				    "http '%s' is not defined",
11109 				    cfg_obj_asstring(httpobj));
11110 			return (ISC_R_FAILURE);
11111 		}
11112 
11113 		http = true;
11114 	}
11115 
11116 	portobj = cfg_tuple_get(ltup, "port");
11117 	if (!cfg_obj_isuint32(portobj)) {
11118 		if (http && do_tls) {
11119 			if (named_g_httpsport != 0) {
11120 				port = named_g_httpsport;
11121 			} else {
11122 				result = named_config_getport(
11123 					config, "https-port", &port);
11124 				if (result != ISC_R_SUCCESS) {
11125 					return (result);
11126 				}
11127 			}
11128 		} else if (http && !do_tls) {
11129 			if (named_g_httpport != 0) {
11130 				port = named_g_httpport;
11131 			} else {
11132 				result = named_config_getport(
11133 					config, "http-port", &port);
11134 				if (result != ISC_R_SUCCESS) {
11135 					return (result);
11136 				}
11137 			}
11138 		} else if (do_tls) {
11139 			if (named_g_tlsport != 0) {
11140 				port = named_g_tlsport;
11141 			} else {
11142 				result = named_config_getport(
11143 					config, "tls-port", &port);
11144 				if (result != ISC_R_SUCCESS) {
11145 					return (result);
11146 				}
11147 			}
11148 		} else {
11149 			if (named_g_port != 0) {
11150 				port = named_g_port;
11151 			} else {
11152 				result = named_config_getport(config, "port",
11153 							      &port);
11154 				if (result != ISC_R_SUCCESS) {
11155 					return (result);
11156 				}
11157 			}
11158 		}
11159 	} else {
11160 		if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
11161 			return (ISC_R_RANGE);
11162 		}
11163 		port = (in_port_t)cfg_obj_asuint32(portobj);
11164 	}
11165 
11166 	dscpobj = cfg_tuple_get(ltup, "dscp");
11167 	if (!cfg_obj_isuint32(dscpobj)) {
11168 		dscp = named_g_dscp;
11169 	} else {
11170 		if (cfg_obj_asuint32(dscpobj) > 63) {
11171 			return (ISC_R_RANGE);
11172 		}
11173 		dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
11174 	}
11175 
11176 #ifdef HAVE_LIBNGHTTP2
11177 	if (http) {
11178 		CHECK(listenelt_http(http_server, do_tls, &tls_params, port,
11179 				     mctx, &delt));
11180 	}
11181 #endif /* HAVE_LIBNGHTTP2 */
11182 
11183 	if (!http) {
11184 		CHECK(ns_listenelt_create(mctx, port, dscp, NULL, do_tls,
11185 					  &tls_params, &delt));
11186 	}
11187 
11188 	result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"), config,
11189 				     named_g_lctx, actx, mctx, 0, family,
11190 				     &delt->acl);
11191 	if (result != ISC_R_SUCCESS) {
11192 		ns_listenelt_destroy(delt);
11193 		return (result);
11194 	}
11195 	*target = delt;
11196 
11197 cleanup:
11198 	return (result);
11199 }
11200 
11201 #ifdef HAVE_LIBNGHTTP2
11202 static isc_result_t
listenelt_http(const cfg_obj_t * http,bool tls,const ns_listen_tls_params_t * tls_params,in_port_t port,isc_mem_t * mctx,ns_listenelt_t ** target)11203 listenelt_http(const cfg_obj_t *http, bool tls,
11204 	       const ns_listen_tls_params_t *tls_params, in_port_t port,
11205 	       isc_mem_t *mctx, ns_listenelt_t **target) {
11206 	isc_result_t result = ISC_R_SUCCESS;
11207 	ns_listenelt_t *delt = NULL;
11208 	char **endpoints = NULL;
11209 	const cfg_obj_t *eplist = NULL;
11210 	const cfg_listelt_t *elt = NULL;
11211 	size_t len = 1, i = 0;
11212 	uint32_t max_clients = named_g_http_listener_clients;
11213 	uint32_t max_streams = named_g_http_streams_per_conn;
11214 	ns_server_t *server = NULL;
11215 	isc_quota_t *quota = NULL;
11216 
11217 	REQUIRE(target != NULL && *target == NULL);
11218 
11219 	if (tls) {
11220 		INSIST(tls_params != NULL);
11221 		INSIST((tls_params->key == NULL) == (tls_params->cert == NULL));
11222 	}
11223 
11224 	if (port == 0) {
11225 		port = tls ? named_g_httpsport : named_g_httpport;
11226 	}
11227 
11228 	/*
11229 	 * If "default" was used, we set up the default endpoint
11230 	 * of "/dns-query".
11231 	 */
11232 	if (http != NULL) {
11233 		const cfg_obj_t *cfg_max_clients = NULL;
11234 		const cfg_obj_t *cfg_max_streams = NULL;
11235 
11236 		if (cfg_map_get(http, "endpoints", &eplist) == ISC_R_SUCCESS) {
11237 			INSIST(eplist != NULL);
11238 			len = cfg_list_length(eplist, false);
11239 		}
11240 
11241 		if (cfg_map_get(http, "listener-clients", &cfg_max_clients) ==
11242 		    ISC_R_SUCCESS) {
11243 			INSIST(cfg_max_clients != NULL);
11244 			max_clients = cfg_obj_asuint32(cfg_max_clients);
11245 		}
11246 
11247 		if (cfg_map_get(http, "streams-per-connection",
11248 				&cfg_max_streams) == ISC_R_SUCCESS)
11249 		{
11250 			INSIST(cfg_max_streams != NULL);
11251 			max_streams = cfg_obj_asuint32(cfg_max_streams);
11252 		}
11253 	}
11254 
11255 	endpoints = isc_mem_allocate(mctx, sizeof(endpoints[0]) * len);
11256 
11257 	if (http != NULL && eplist != NULL) {
11258 		for (elt = cfg_list_first(eplist); elt != NULL;
11259 		     elt = cfg_list_next(elt)) {
11260 			const cfg_obj_t *ep = cfg_listelt_value(elt);
11261 			const char *path = cfg_obj_asstring(ep);
11262 			endpoints[i++] = isc_mem_strdup(mctx, path);
11263 		}
11264 	} else {
11265 		endpoints[i++] = isc_mem_strdup(mctx, ISC_NM_HTTP_DEFAULT_PATH);
11266 	}
11267 
11268 	INSIST(i == len);
11269 
11270 	INSIST(named_g_server != NULL);
11271 	ns_server_attach(named_g_server->sctx, &server);
11272 	if (max_clients > 0) {
11273 		quota = isc_mem_get(mctx, sizeof(isc_quota_t));
11274 		isc_quota_init(quota, max_clients);
11275 	}
11276 	result = ns_listenelt_create_http(mctx, port, named_g_dscp, NULL, tls,
11277 					  tls_params, endpoints, len, quota,
11278 					  max_streams, &delt);
11279 	if (result != ISC_R_SUCCESS) {
11280 		goto error;
11281 	}
11282 
11283 	if (quota != NULL) {
11284 		ISC_LIST_APPEND(server->http_quotas, quota, link);
11285 	}
11286 	ns_server_detach(&server);
11287 
11288 	*target = delt;
11289 
11290 	return (result);
11291 error:
11292 	if (delt != NULL) {
11293 		ns_listenelt_destroy(delt);
11294 	}
11295 	if (quota != NULL) {
11296 		isc_quota_destroy(quota);
11297 		isc_mem_put(mctx, quota, sizeof(*quota));
11298 	}
11299 
11300 	if (server != NULL) {
11301 		ns_server_detach(&server);
11302 	}
11303 	return (result);
11304 }
11305 #endif /* HAVE_LIBNGHTTP2 */
11306 
11307 isc_result_t
named_server_dumpstats(named_server_t * server)11308 named_server_dumpstats(named_server_t *server) {
11309 	isc_result_t result;
11310 	FILE *fp = NULL;
11311 
11312 	CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
11313 		"could not open statistics dump file", server->statsfile);
11314 
11315 	result = named_stats_dump(server, fp);
11316 
11317 cleanup:
11318 	if (fp != NULL) {
11319 		(void)isc_stdio_close(fp);
11320 	}
11321 	if (result == ISC_R_SUCCESS) {
11322 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11323 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11324 			      "dumpstats complete");
11325 	} else {
11326 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11327 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11328 			      "dumpstats failed: %s",
11329 			      isc_result_totext(result));
11330 	}
11331 	return (result);
11332 }
11333 
11334 static isc_result_t
add_zone_tolist(dns_zone_t * zone,void * uap)11335 add_zone_tolist(dns_zone_t *zone, void *uap) {
11336 	struct dumpcontext *dctx = uap;
11337 	struct zonelistentry *zle;
11338 
11339 	zle = isc_mem_get(dctx->mctx, sizeof *zle);
11340 	zle->zone = NULL;
11341 	dns_zone_attach(zone, &zle->zone);
11342 	ISC_LINK_INIT(zle, link);
11343 	ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
11344 	return (ISC_R_SUCCESS);
11345 }
11346 
11347 static isc_result_t
add_view_tolist(struct dumpcontext * dctx,dns_view_t * view)11348 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
11349 	struct viewlistentry *vle;
11350 	isc_result_t result = ISC_R_SUCCESS;
11351 
11352 	/*
11353 	 * Prevent duplicate views.
11354 	 */
11355 	for (vle = ISC_LIST_HEAD(dctx->viewlist); vle != NULL;
11356 	     vle = ISC_LIST_NEXT(vle, link))
11357 	{
11358 		if (vle->view == view) {
11359 			return (ISC_R_SUCCESS);
11360 		}
11361 	}
11362 
11363 	vle = isc_mem_get(dctx->mctx, sizeof *vle);
11364 	vle->view = NULL;
11365 	dns_view_attach(view, &vle->view);
11366 	ISC_LINK_INIT(vle, link);
11367 	ISC_LIST_INIT(vle->zonelist);
11368 	ISC_LIST_APPEND(dctx->viewlist, vle, link);
11369 	if (dctx->dumpzones) {
11370 		result = dns_zt_apply(view->zonetable, true, NULL,
11371 				      add_zone_tolist, dctx);
11372 	}
11373 	return (result);
11374 }
11375 
11376 static void
dumpcontext_destroy(struct dumpcontext * dctx)11377 dumpcontext_destroy(struct dumpcontext *dctx) {
11378 	struct viewlistentry *vle;
11379 	struct zonelistentry *zle;
11380 
11381 	vle = ISC_LIST_HEAD(dctx->viewlist);
11382 	while (vle != NULL) {
11383 		ISC_LIST_UNLINK(dctx->viewlist, vle, link);
11384 		zle = ISC_LIST_HEAD(vle->zonelist);
11385 		while (zle != NULL) {
11386 			ISC_LIST_UNLINK(vle->zonelist, zle, link);
11387 			dns_zone_detach(&zle->zone);
11388 			isc_mem_put(dctx->mctx, zle, sizeof *zle);
11389 			zle = ISC_LIST_HEAD(vle->zonelist);
11390 		}
11391 		dns_view_detach(&vle->view);
11392 		isc_mem_put(dctx->mctx, vle, sizeof *vle);
11393 		vle = ISC_LIST_HEAD(dctx->viewlist);
11394 	}
11395 	if (dctx->version != NULL) {
11396 		dns_db_closeversion(dctx->db, &dctx->version, false);
11397 	}
11398 	if (dctx->db != NULL) {
11399 		dns_db_detach(&dctx->db);
11400 	}
11401 	if (dctx->cache != NULL) {
11402 		dns_db_detach(&dctx->cache);
11403 	}
11404 	if (dctx->task != NULL) {
11405 		isc_task_detach(&dctx->task);
11406 	}
11407 	if (dctx->fp != NULL) {
11408 		(void)isc_stdio_close(dctx->fp);
11409 	}
11410 	if (dctx->mdctx != NULL) {
11411 		dns_dumpctx_detach(&dctx->mdctx);
11412 	}
11413 	isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
11414 }
11415 
11416 static void
dumpdone(void * arg,isc_result_t result)11417 dumpdone(void *arg, isc_result_t result) {
11418 	struct dumpcontext *dctx = arg;
11419 	char buf[1024 + 32];
11420 	const dns_master_style_t *style;
11421 
11422 	if (result != ISC_R_SUCCESS) {
11423 		goto cleanup;
11424 	}
11425 	if (dctx->mdctx != NULL) {
11426 		dns_dumpctx_detach(&dctx->mdctx);
11427 	}
11428 	if (dctx->view == NULL) {
11429 		dctx->view = ISC_LIST_HEAD(dctx->viewlist);
11430 		if (dctx->view == NULL) {
11431 			goto done;
11432 		}
11433 		INSIST(dctx->zone == NULL);
11434 	} else {
11435 		goto resume;
11436 	}
11437 nextview:
11438 	fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
11439 resume:
11440 	if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
11441 		fprintf(dctx->fp, ";\n; Cache of view '%s' is shared as '%s'\n",
11442 			dctx->view->view->name,
11443 			dns_cache_getname(dctx->view->view->cache));
11444 	} else if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache)
11445 	{
11446 		if (dctx->dumpexpired) {
11447 			style = &dns_master_style_cache_with_expired;
11448 		} else {
11449 			style = &dns_master_style_cache;
11450 		}
11451 		/* start cache dump */
11452 		if (dctx->view->view->cachedb != NULL) {
11453 			dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11454 		}
11455 		if (dctx->cache != NULL) {
11456 			fprintf(dctx->fp,
11457 				";\n; Cache dump of view '%s' (cache %s)\n;\n",
11458 				dctx->view->view->name,
11459 				dns_cache_getname(dctx->view->view->cache));
11460 			result = dns_master_dumptostreamasync(
11461 				dctx->mctx, dctx->cache, NULL, style, dctx->fp,
11462 				dctx->task, dumpdone, dctx, &dctx->mdctx);
11463 			if (result == DNS_R_CONTINUE) {
11464 				return;
11465 			}
11466 			if (result == ISC_R_NOTIMPLEMENTED) {
11467 				fprintf(dctx->fp, "; %s\n",
11468 					isc_result_totext(result));
11469 			} else if (result != ISC_R_SUCCESS) {
11470 				goto cleanup;
11471 			}
11472 		}
11473 	}
11474 
11475 	if ((dctx->dumpadb || dctx->dumpbad || dctx->dumpfail) &&
11476 	    dctx->cache == NULL && dctx->view->view->cachedb != NULL)
11477 	{
11478 		dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11479 	}
11480 
11481 	if (dctx->cache != NULL) {
11482 		if (dctx->dumpadb) {
11483 			dns_adb_dump(dctx->view->view->adb, dctx->fp);
11484 		}
11485 		if (dctx->dumpbad) {
11486 			dns_resolver_printbadcache(dctx->view->view->resolver,
11487 						   dctx->fp);
11488 		}
11489 		if (dctx->dumpfail) {
11490 			dns_badcache_print(dctx->view->view->failcache,
11491 					   "SERVFAIL cache", dctx->fp);
11492 		}
11493 		dns_db_detach(&dctx->cache);
11494 	}
11495 	if (dctx->dumpzones) {
11496 		style = &dns_master_style_full;
11497 	nextzone:
11498 		if (dctx->version != NULL) {
11499 			dns_db_closeversion(dctx->db, &dctx->version, false);
11500 		}
11501 		if (dctx->db != NULL) {
11502 			dns_db_detach(&dctx->db);
11503 		}
11504 		if (dctx->zone == NULL) {
11505 			dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
11506 		} else {
11507 			dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
11508 		}
11509 		if (dctx->zone != NULL) {
11510 			/* start zone dump */
11511 			dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
11512 			fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
11513 			result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
11514 			if (result != ISC_R_SUCCESS) {
11515 				fprintf(dctx->fp, "; %s\n",
11516 					isc_result_totext(result));
11517 				goto nextzone;
11518 			}
11519 			dns_db_currentversion(dctx->db, &dctx->version);
11520 			result = dns_master_dumptostreamasync(
11521 				dctx->mctx, dctx->db, dctx->version, style,
11522 				dctx->fp, dctx->task, dumpdone, dctx,
11523 				&dctx->mdctx);
11524 			if (result == DNS_R_CONTINUE) {
11525 				return;
11526 			}
11527 			if (result == ISC_R_NOTIMPLEMENTED) {
11528 				fprintf(dctx->fp, "; %s\n",
11529 					isc_result_totext(result));
11530 				result = ISC_R_SUCCESS;
11531 				POST(result);
11532 				goto nextzone;
11533 			}
11534 			if (result != ISC_R_SUCCESS) {
11535 				goto cleanup;
11536 			}
11537 		}
11538 	}
11539 	if (dctx->view != NULL) {
11540 		dctx->view = ISC_LIST_NEXT(dctx->view, link);
11541 		if (dctx->view != NULL) {
11542 			goto nextview;
11543 		}
11544 	}
11545 done:
11546 	fprintf(dctx->fp, "; Dump complete\n");
11547 	result = isc_stdio_flush(dctx->fp);
11548 	if (result == ISC_R_SUCCESS) {
11549 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11550 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11551 			      "dumpdb complete");
11552 	}
11553 cleanup:
11554 	if (result != ISC_R_SUCCESS) {
11555 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11556 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11557 			      "dumpdb failed: %s", isc_result_totext(result));
11558 	}
11559 	dumpcontext_destroy(dctx);
11560 }
11561 
11562 isc_result_t
named_server_dumpdb(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)11563 named_server_dumpdb(named_server_t *server, isc_lex_t *lex,
11564 		    isc_buffer_t **text) {
11565 	struct dumpcontext *dctx = NULL;
11566 	dns_view_t *view;
11567 	isc_result_t result;
11568 	char *ptr;
11569 	const char *sep;
11570 	bool found;
11571 
11572 	REQUIRE(text != NULL);
11573 
11574 	/* Skip the command name. */
11575 	ptr = next_token(lex, NULL);
11576 	if (ptr == NULL) {
11577 		return (ISC_R_UNEXPECTEDEND);
11578 	}
11579 
11580 	dctx = isc_mem_get(server->mctx, sizeof(*dctx));
11581 
11582 	dctx->mctx = server->mctx;
11583 	dctx->dumpcache = true;
11584 	dctx->dumpadb = true;
11585 	dctx->dumpbad = true;
11586 	dctx->dumpexpired = false;
11587 	dctx->dumpfail = true;
11588 	dctx->dumpzones = false;
11589 	dctx->fp = NULL;
11590 	ISC_LIST_INIT(dctx->viewlist);
11591 	dctx->view = NULL;
11592 	dctx->zone = NULL;
11593 	dctx->cache = NULL;
11594 	dctx->mdctx = NULL;
11595 	dctx->db = NULL;
11596 	dctx->cache = NULL;
11597 	dctx->task = NULL;
11598 	dctx->version = NULL;
11599 	isc_task_attach(server->task, &dctx->task);
11600 
11601 	CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
11602 		"could not open dump file", server->dumpfile);
11603 
11604 	ptr = next_token(lex, NULL);
11605 	sep = (ptr == NULL) ? "" : ": ";
11606 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11607 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11608 		      "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : "");
11609 
11610 	if (ptr != NULL && strcmp(ptr, "-all") == 0) {
11611 		/* also dump zones */
11612 		dctx->dumpzones = true;
11613 		ptr = next_token(lex, NULL);
11614 	} else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
11615 		/* this is the default */
11616 		ptr = next_token(lex, NULL);
11617 	} else if (ptr != NULL && strcmp(ptr, "-expired") == 0) {
11618 		/* this is the same as -cache but includes expired data */
11619 		dctx->dumpexpired = true;
11620 		ptr = next_token(lex, NULL);
11621 	} else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
11622 		/* only dump zones, suppress caches */
11623 		dctx->dumpadb = false;
11624 		dctx->dumpbad = false;
11625 		dctx->dumpcache = false;
11626 		dctx->dumpfail = false;
11627 		dctx->dumpzones = true;
11628 		ptr = next_token(lex, NULL);
11629 	} else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
11630 		/* only dump adb, suppress other caches */
11631 		dctx->dumpbad = false;
11632 		dctx->dumpcache = false;
11633 		dctx->dumpfail = false;
11634 		ptr = next_token(lex, NULL);
11635 	} else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
11636 		/* only dump badcache, suppress other caches */
11637 		dctx->dumpadb = false;
11638 		dctx->dumpcache = false;
11639 		dctx->dumpfail = false;
11640 		ptr = next_token(lex, NULL);
11641 	} else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
11642 		/* only dump servfail cache, suppress other caches */
11643 		dctx->dumpadb = false;
11644 		dctx->dumpbad = false;
11645 		dctx->dumpcache = false;
11646 		ptr = next_token(lex, NULL);
11647 	}
11648 
11649 nextview:
11650 	found = false;
11651 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11652 	     view = ISC_LIST_NEXT(view, link))
11653 	{
11654 		if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11655 			continue;
11656 		}
11657 		found = true;
11658 		CHECK(add_view_tolist(dctx, view));
11659 	}
11660 	if (ptr != NULL) {
11661 		if (!found) {
11662 			CHECK(putstr(text, "view '"));
11663 			CHECK(putstr(text, ptr));
11664 			CHECK(putstr(text, "' not found"));
11665 			CHECK(putnull(text));
11666 			result = ISC_R_NOTFOUND;
11667 			dumpdone(dctx, result);
11668 			return (result);
11669 		}
11670 		ptr = next_token(lex, NULL);
11671 		if (ptr != NULL) {
11672 			goto nextview;
11673 		}
11674 	}
11675 	dumpdone(dctx, ISC_R_SUCCESS);
11676 	return (ISC_R_SUCCESS);
11677 
11678 cleanup:
11679 	dumpcontext_destroy(dctx);
11680 	return (result);
11681 }
11682 
11683 isc_result_t
named_server_dumpsecroots(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)11684 named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex,
11685 			  isc_buffer_t **text) {
11686 	dns_view_t *view;
11687 	dns_keytable_t *secroots = NULL;
11688 	dns_ntatable_t *ntatable = NULL;
11689 	isc_result_t result;
11690 	char *ptr;
11691 	FILE *fp = NULL;
11692 	isc_time_t now;
11693 	char tbuf[64];
11694 	unsigned int used = isc_buffer_usedlength(*text);
11695 	bool first = true;
11696 
11697 	REQUIRE(text != NULL);
11698 
11699 	/* Skip the command name. */
11700 	ptr = next_token(lex, text);
11701 	if (ptr == NULL) {
11702 		return (ISC_R_UNEXPECTEDEND);
11703 	}
11704 
11705 	/* "-" here means print the output instead of dumping to file */
11706 	ptr = next_token(lex, text);
11707 	if (ptr != NULL && strcmp(ptr, "-") == 0) {
11708 		ptr = next_token(lex, text);
11709 	} else {
11710 		result = isc_stdio_open(server->secrootsfile, "w", &fp);
11711 		if (result != ISC_R_SUCCESS) {
11712 			(void)putstr(text, "could not open ");
11713 			(void)putstr(text, server->secrootsfile);
11714 			CHECKMF(result, "could not open secroots dump file",
11715 				server->secrootsfile);
11716 		}
11717 	}
11718 
11719 	TIME_NOW(&now);
11720 	isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
11721 	CHECK(putstr(text, "secure roots as of "));
11722 	CHECK(putstr(text, tbuf));
11723 	CHECK(putstr(text, ":\n"));
11724 	used = isc_buffer_usedlength(*text);
11725 
11726 	do {
11727 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11728 		     view = ISC_LIST_NEXT(view, link))
11729 		{
11730 			if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11731 				continue;
11732 			}
11733 			if (secroots != NULL) {
11734 				dns_keytable_detach(&secroots);
11735 			}
11736 			result = dns_view_getsecroots(view, &secroots);
11737 			if (result == ISC_R_NOTFOUND) {
11738 				result = ISC_R_SUCCESS;
11739 				continue;
11740 			}
11741 			if (first || used != isc_buffer_usedlength(*text)) {
11742 				CHECK(putstr(text, "\n"));
11743 				first = false;
11744 			}
11745 			CHECK(putstr(text, " Start view "));
11746 			CHECK(putstr(text, view->name));
11747 			CHECK(putstr(text, "\n   Secure roots:\n\n"));
11748 			used = isc_buffer_usedlength(*text);
11749 			CHECK(dns_keytable_totext(secroots, text));
11750 
11751 			if (ntatable != NULL) {
11752 				dns_ntatable_detach(&ntatable);
11753 			}
11754 			result = dns_view_getntatable(view, &ntatable);
11755 			if (result == ISC_R_NOTFOUND) {
11756 				result = ISC_R_SUCCESS;
11757 				continue;
11758 			}
11759 			if (used != isc_buffer_usedlength(*text)) {
11760 				CHECK(putstr(text, "\n"));
11761 			}
11762 			CHECK(putstr(text, "   Negative trust anchors:\n\n"));
11763 			used = isc_buffer_usedlength(*text);
11764 			CHECK(dns_ntatable_totext(ntatable, NULL, text));
11765 		}
11766 
11767 		if (ptr != NULL) {
11768 			ptr = next_token(lex, text);
11769 		}
11770 	} while (ptr != NULL);
11771 
11772 cleanup:
11773 	if (secroots != NULL) {
11774 		dns_keytable_detach(&secroots);
11775 	}
11776 	if (ntatable != NULL) {
11777 		dns_ntatable_detach(&ntatable);
11778 	}
11779 
11780 	if (fp != NULL) {
11781 		if (used != isc_buffer_usedlength(*text)) {
11782 			(void)putstr(text, "\n");
11783 		}
11784 		fprintf(fp, "%.*s", (int)isc_buffer_usedlength(*text),
11785 			(char *)isc_buffer_base(*text));
11786 		isc_buffer_clear(*text);
11787 		(void)isc_stdio_close(fp);
11788 	} else if (isc_buffer_usedlength(*text) > 0) {
11789 		(void)putnull(text);
11790 	}
11791 
11792 	if (result == ISC_R_SUCCESS) {
11793 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11794 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11795 			      "dumpsecroots complete");
11796 	} else {
11797 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11798 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11799 			      "dumpsecroots failed: %s",
11800 			      isc_result_totext(result));
11801 	}
11802 	return (result);
11803 }
11804 
11805 isc_result_t
named_server_dumprecursing(named_server_t * server)11806 named_server_dumprecursing(named_server_t *server) {
11807 	FILE *fp = NULL;
11808 	dns_view_t *view;
11809 	isc_result_t result;
11810 
11811 	CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
11812 		"could not open dump file", server->recfile);
11813 	fprintf(fp, ";\n; Recursing Queries\n;\n");
11814 	ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
11815 
11816 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11817 	     view = ISC_LIST_NEXT(view, link))
11818 	{
11819 		fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
11820 			view->name);
11821 		dns_resolver_dumpfetches(view->resolver, isc_statsformat_file,
11822 					 fp);
11823 	}
11824 
11825 	fprintf(fp, "; Dump complete\n");
11826 
11827 cleanup:
11828 	if (fp != NULL) {
11829 		result = isc_stdio_close(fp);
11830 	}
11831 	if (result == ISC_R_SUCCESS) {
11832 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11833 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11834 			      "dumprecursing complete");
11835 	} else {
11836 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11837 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11838 			      "dumprecursing failed: %s",
11839 			      isc_result_totext(result));
11840 	}
11841 	return (result);
11842 }
11843 
11844 isc_result_t
named_server_setdebuglevel(named_server_t * server,isc_lex_t * lex)11845 named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
11846 	char *ptr;
11847 	char *endp;
11848 	long newlevel;
11849 
11850 	UNUSED(server);
11851 
11852 	/* Skip the command name. */
11853 	ptr = next_token(lex, NULL);
11854 	if (ptr == NULL) {
11855 		return (ISC_R_UNEXPECTEDEND);
11856 	}
11857 
11858 	/* Look for the new level name. */
11859 	ptr = next_token(lex, NULL);
11860 	if (ptr == NULL) {
11861 		if (named_g_debuglevel < 99) {
11862 			named_g_debuglevel++;
11863 		}
11864 	} else {
11865 		newlevel = strtol(ptr, &endp, 10);
11866 		if (*endp != '\0' || newlevel < 0 || newlevel > 99) {
11867 			return (ISC_R_RANGE);
11868 		}
11869 		named_g_debuglevel = (unsigned int)newlevel;
11870 	}
11871 	isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel);
11872 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11873 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11874 		      "debug level is now %u", named_g_debuglevel);
11875 	return (ISC_R_SUCCESS);
11876 }
11877 
11878 isc_result_t
named_server_validation(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)11879 named_server_validation(named_server_t *server, isc_lex_t *lex,
11880 			isc_buffer_t **text) {
11881 	char *ptr;
11882 	dns_view_t *view;
11883 	bool changed = false;
11884 	isc_result_t result;
11885 	bool enable = true, set = true, first = true;
11886 
11887 	REQUIRE(text != NULL);
11888 
11889 	/* Skip the command name. */
11890 	ptr = next_token(lex, text);
11891 	if (ptr == NULL) {
11892 		return (ISC_R_UNEXPECTEDEND);
11893 	}
11894 
11895 	/* Find out what we are to do. */
11896 	ptr = next_token(lex, text);
11897 	if (ptr == NULL) {
11898 		return (ISC_R_UNEXPECTEDEND);
11899 	}
11900 
11901 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
11902 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
11903 	{
11904 		enable = true;
11905 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
11906 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
11907 	{
11908 		enable = false;
11909 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
11910 		set = false;
11911 	} else {
11912 		return (DNS_R_SYNTAX);
11913 	}
11914 
11915 	/* Look for the view name. */
11916 	ptr = next_token(lex, text);
11917 
11918 	result = isc_task_beginexclusive(server->task);
11919 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
11920 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11921 	     view = ISC_LIST_NEXT(view, link))
11922 	{
11923 		if ((ptr != NULL && strcasecmp(ptr, view->name) != 0) ||
11924 		    strcasecmp("_bind", view->name) == 0)
11925 		{
11926 			continue;
11927 		}
11928 
11929 		if (set) {
11930 			CHECK(dns_view_flushcache(view, false));
11931 			view->enablevalidation = enable;
11932 			changed = true;
11933 		} else {
11934 			if (!first) {
11935 				CHECK(putstr(text, "\n"));
11936 			}
11937 			CHECK(putstr(text, "DNSSEC validation is "));
11938 			CHECK(putstr(text, view->enablevalidation
11939 						   ? "enabled"
11940 						   : "disabled"));
11941 			CHECK(putstr(text, " (view "));
11942 			CHECK(putstr(text, view->name));
11943 			CHECK(putstr(text, ")"));
11944 			first = false;
11945 		}
11946 	}
11947 	CHECK(putnull(text));
11948 
11949 	if (!set) {
11950 		result = ISC_R_SUCCESS;
11951 	} else if (changed) {
11952 		result = ISC_R_SUCCESS;
11953 	} else {
11954 		result = ISC_R_FAILURE;
11955 	}
11956 cleanup:
11957 	isc_task_endexclusive(server->task);
11958 	return (result);
11959 }
11960 
11961 isc_result_t
named_server_flushcache(named_server_t * server,isc_lex_t * lex)11962 named_server_flushcache(named_server_t *server, isc_lex_t *lex) {
11963 	char *ptr;
11964 	dns_view_t *view;
11965 	bool flushed;
11966 	bool found;
11967 	isc_result_t result;
11968 	named_cache_t *nsc;
11969 
11970 	/* Skip the command name. */
11971 	ptr = next_token(lex, NULL);
11972 	if (ptr == NULL) {
11973 		return (ISC_R_UNEXPECTEDEND);
11974 	}
11975 
11976 	/* Look for the view name. */
11977 	ptr = next_token(lex, NULL);
11978 
11979 	result = isc_task_beginexclusive(server->task);
11980 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
11981 	flushed = true;
11982 	found = false;
11983 
11984 	/*
11985 	 * Flushing a cache is tricky when caches are shared by multiple views.
11986 	 * We first identify which caches should be flushed in the local cache
11987 	 * list, flush these caches, and then update other views that refer to
11988 	 * the flushed cache DB.
11989 	 */
11990 	if (ptr != NULL) {
11991 		/*
11992 		 * Mark caches that need to be flushed.  This is an O(#view^2)
11993 		 * operation in the very worst case, but should be normally
11994 		 * much more lightweight because only a few (most typically just
11995 		 * one) views will match.
11996 		 */
11997 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11998 		     view = ISC_LIST_NEXT(view, link))
11999 		{
12000 			if (strcasecmp(ptr, view->name) != 0) {
12001 				continue;
12002 			}
12003 			found = true;
12004 			for (nsc = ISC_LIST_HEAD(server->cachelist);
12005 			     nsc != NULL; nsc = ISC_LIST_NEXT(nsc, link))
12006 			{
12007 				if (nsc->cache == view->cache) {
12008 					break;
12009 				}
12010 			}
12011 			INSIST(nsc != NULL);
12012 			nsc->needflush = true;
12013 		}
12014 	} else {
12015 		found = true;
12016 	}
12017 
12018 	/* Perform flush */
12019 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12020 	     nsc = ISC_LIST_NEXT(nsc, link))
12021 	{
12022 		if (ptr != NULL && !nsc->needflush) {
12023 			continue;
12024 		}
12025 		nsc->needflush = true;
12026 		result = dns_view_flushcache(nsc->primaryview, false);
12027 		if (result != ISC_R_SUCCESS) {
12028 			flushed = false;
12029 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12030 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12031 				      "flushing cache in view '%s' failed: %s",
12032 				      nsc->primaryview->name,
12033 				      isc_result_totext(result));
12034 		}
12035 	}
12036 
12037 	/*
12038 	 * Fix up views that share a flushed cache: let the views update the
12039 	 * cache DB they're referring to.  This could also be an expensive
12040 	 * operation, but should typically be marginal: the inner loop is only
12041 	 * necessary for views that share a cache, and if there are many such
12042 	 * views the number of shared cache should normally be small.
12043 	 * A worst case is that we have n views and n/2 caches, each shared by
12044 	 * two views.  Then this will be a O(n^2/4) operation.
12045 	 */
12046 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12047 	     view = ISC_LIST_NEXT(view, link))
12048 	{
12049 		if (!dns_view_iscacheshared(view)) {
12050 			continue;
12051 		}
12052 		for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12053 		     nsc = ISC_LIST_NEXT(nsc, link))
12054 		{
12055 			if (!nsc->needflush || nsc->cache != view->cache) {
12056 				continue;
12057 			}
12058 			result = dns_view_flushcache(view, true);
12059 			if (result != ISC_R_SUCCESS) {
12060 				flushed = false;
12061 				isc_log_write(
12062 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12063 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12064 					"fixing cache in view '%s' "
12065 					"failed: %s",
12066 					view->name, isc_result_totext(result));
12067 			}
12068 		}
12069 	}
12070 
12071 	/* Cleanup the cache list. */
12072 	for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
12073 	     nsc = ISC_LIST_NEXT(nsc, link))
12074 	{
12075 		nsc->needflush = false;
12076 	}
12077 
12078 	if (flushed && found) {
12079 		if (ptr != NULL) {
12080 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12081 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12082 				      "flushing cache in view '%s' succeeded",
12083 				      ptr);
12084 		} else {
12085 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12086 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12087 				      "flushing caches in all views succeeded");
12088 		}
12089 		result = ISC_R_SUCCESS;
12090 	} else {
12091 		if (!found) {
12092 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12093 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12094 				      "flushing cache in view '%s' failed: "
12095 				      "view not found",
12096 				      ptr);
12097 			result = ISC_R_NOTFOUND;
12098 		} else {
12099 			result = ISC_R_FAILURE;
12100 		}
12101 	}
12102 	isc_task_endexclusive(server->task);
12103 	return (result);
12104 }
12105 
12106 isc_result_t
named_server_flushnode(named_server_t * server,isc_lex_t * lex,bool tree)12107 named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) {
12108 	char *ptr, *viewname;
12109 	char target[DNS_NAME_FORMATSIZE];
12110 	dns_view_t *view;
12111 	bool flushed;
12112 	bool found;
12113 	isc_result_t result;
12114 	isc_buffer_t b;
12115 	dns_fixedname_t fixed;
12116 	dns_name_t *name;
12117 
12118 	/* Skip the command name. */
12119 	ptr = next_token(lex, NULL);
12120 	if (ptr == NULL) {
12121 		return (ISC_R_UNEXPECTEDEND);
12122 	}
12123 
12124 	/* Find the domain name to flush. */
12125 	ptr = next_token(lex, NULL);
12126 	if (ptr == NULL) {
12127 		return (ISC_R_UNEXPECTEDEND);
12128 	}
12129 
12130 	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
12131 	isc_buffer_constinit(&b, target, strlen(target));
12132 	isc_buffer_add(&b, strlen(target));
12133 	name = dns_fixedname_initname(&fixed);
12134 	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
12135 	if (result != ISC_R_SUCCESS) {
12136 		return (result);
12137 	}
12138 
12139 	/* Look for the view name. */
12140 	viewname = next_token(lex, NULL);
12141 
12142 	result = isc_task_beginexclusive(server->task);
12143 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12144 	flushed = true;
12145 	found = false;
12146 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12147 	     view = ISC_LIST_NEXT(view, link))
12148 	{
12149 		if (viewname != NULL && strcasecmp(viewname, view->name) != 0) {
12150 			continue;
12151 		}
12152 		found = true;
12153 		/*
12154 		 * It's a little inefficient to try flushing name for all views
12155 		 * if some of the views share a single cache.  But since the
12156 		 * operation is lightweight we prefer simplicity here.
12157 		 */
12158 		result = dns_view_flushnode(view, name, tree);
12159 		if (result != ISC_R_SUCCESS) {
12160 			flushed = false;
12161 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12162 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12163 				      "flushing %s '%s' in cache view '%s' "
12164 				      "failed: %s",
12165 				      tree ? "tree" : "name", target,
12166 				      view->name, isc_result_totext(result));
12167 		}
12168 	}
12169 	if (flushed && found) {
12170 		if (viewname != NULL) {
12171 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12172 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12173 				      "flushing %s '%s' in cache view '%s' "
12174 				      "succeeded",
12175 				      tree ? "tree" : "name", target, viewname);
12176 		} else {
12177 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12178 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12179 				      "flushing %s '%s' in all cache views "
12180 				      "succeeded",
12181 				      tree ? "tree" : "name", target);
12182 		}
12183 		result = ISC_R_SUCCESS;
12184 	} else {
12185 		if (!found) {
12186 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12187 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12188 				      "flushing %s '%s' in cache view '%s' "
12189 				      "failed: view not found",
12190 				      tree ? "tree" : "name", target, viewname);
12191 		}
12192 		result = ISC_R_FAILURE;
12193 	}
12194 	isc_task_endexclusive(server->task);
12195 	return (result);
12196 }
12197 
12198 isc_result_t
named_server_status(named_server_t * server,isc_buffer_t ** text)12199 named_server_status(named_server_t *server, isc_buffer_t **text) {
12200 	isc_result_t result;
12201 	unsigned int zonecount, xferrunning, xferdeferred, soaqueries;
12202 	unsigned int automatic;
12203 	const char *ob = "", *cb = "", *alt = "";
12204 	char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
12205 	char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
12206 	char line[1024], hostname[256];
12207 	named_reload_t reload_status;
12208 
12209 	REQUIRE(text != NULL);
12210 
12211 	if (named_g_server->version_set) {
12212 		ob = " (";
12213 		cb = ")";
12214 		if (named_g_server->version == NULL) {
12215 			alt = "version.bind/txt/ch disabled";
12216 		} else {
12217 			alt = named_g_server->version;
12218 		}
12219 	}
12220 	zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
12221 	xferrunning = dns_zonemgr_getcount(server->zonemgr,
12222 					   DNS_ZONESTATE_XFERRUNNING);
12223 	xferdeferred = dns_zonemgr_getcount(server->zonemgr,
12224 					    DNS_ZONESTATE_XFERDEFERRED);
12225 	soaqueries = dns_zonemgr_getcount(server->zonemgr,
12226 					  DNS_ZONESTATE_SOAQUERY);
12227 	automatic = dns_zonemgr_getcount(server->zonemgr,
12228 					 DNS_ZONESTATE_AUTOMATIC);
12229 
12230 	isc_time_formathttptimestamp(&named_g_boottime, boottime,
12231 				     sizeof(boottime));
12232 	isc_time_formathttptimestamp(&named_g_configtime, configtime,
12233 				     sizeof(configtime));
12234 
12235 	snprintf(line, sizeof(line), "version: %s%s <id:%s>%s%s%s\n",
12236 		 PACKAGE_STRING, PACKAGE_DESCRIPTION, PACKAGE_SRCID, ob, alt,
12237 		 cb);
12238 	CHECK(putstr(text, line));
12239 
12240 	result = named_os_gethostname(hostname, sizeof(hostname));
12241 	if (result != ISC_R_SUCCESS) {
12242 		strlcpy(hostname, "localhost", sizeof(hostname));
12243 	}
12244 	snprintf(line, sizeof(line), "running on %s: %s\n", hostname,
12245 		 named_os_uname());
12246 	CHECK(putstr(text, line));
12247 
12248 	snprintf(line, sizeof(line), "boot time: %s\n", boottime);
12249 	CHECK(putstr(text, line));
12250 
12251 	snprintf(line, sizeof(line), "last configured: %s\n", configtime);
12252 	CHECK(putstr(text, line));
12253 
12254 	if (named_g_chrootdir != NULL) {
12255 		snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n",
12256 			 named_g_conffile, named_g_chrootdir, named_g_conffile);
12257 	} else {
12258 		snprintf(line, sizeof(line), "configuration file: %s\n",
12259 			 named_g_conffile);
12260 	}
12261 	CHECK(putstr(text, line));
12262 
12263 	snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected);
12264 	CHECK(putstr(text, line));
12265 
12266 	snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
12267 	CHECK(putstr(text, line));
12268 
12269 	snprintf(line, sizeof(line), "UDP listeners per interface: %u\n",
12270 		 named_g_udpdisp);
12271 	CHECK(putstr(text, line));
12272 
12273 	snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
12274 		 zonecount, automatic);
12275 	CHECK(putstr(text, line));
12276 
12277 	snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel);
12278 	CHECK(putstr(text, line));
12279 
12280 	snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
12281 	CHECK(putstr(text, line));
12282 
12283 	snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
12284 	CHECK(putstr(text, line));
12285 
12286 	snprintf(line, sizeof(line), "soa queries in progress: %u\n",
12287 		 soaqueries);
12288 	CHECK(putstr(text, line));
12289 
12290 	snprintf(line, sizeof(line), "query logging is %s\n",
12291 		 ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES)
12292 			 ? "ON"
12293 			 : "OFF");
12294 	CHECK(putstr(text, line));
12295 
12296 	snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
12297 		 isc_quota_getused(&server->sctx->recursionquota),
12298 		 isc_quota_getsoft(&server->sctx->recursionquota),
12299 		 isc_quota_getmax(&server->sctx->recursionquota));
12300 	CHECK(putstr(text, line));
12301 
12302 	snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
12303 		 isc_quota_getused(&server->sctx->tcpquota),
12304 		 isc_quota_getmax(&server->sctx->tcpquota));
12305 	CHECK(putstr(text, line));
12306 
12307 	snprintf(line, sizeof(line), "TCP high-water: %u\n",
12308 		 (unsigned)ns_stats_get_counter(server->sctx->nsstats,
12309 						ns_statscounter_tcphighwater));
12310 	CHECK(putstr(text, line));
12311 
12312 	reload_status = atomic_load(&server->reload_status);
12313 	if (reload_status != NAMED_RELOAD_DONE) {
12314 		snprintf(line, sizeof(line), "reload/reconfig %s\n",
12315 			 (reload_status == NAMED_RELOAD_FAILED
12316 				  ? "failed"
12317 				  : "in progress"));
12318 		CHECK(putstr(text, line));
12319 	}
12320 
12321 	CHECK(putstr(text, "server is up and running"));
12322 	CHECK(putnull(text));
12323 
12324 	return (ISC_R_SUCCESS);
12325 cleanup:
12326 	return (result);
12327 }
12328 
12329 isc_result_t
named_server_testgen(isc_lex_t * lex,isc_buffer_t ** text)12330 named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) {
12331 	isc_result_t result;
12332 	char *ptr;
12333 	unsigned long count;
12334 	unsigned long i;
12335 	const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
12336 
12337 	REQUIRE(text != NULL);
12338 
12339 	/* Skip the command name. */
12340 	ptr = next_token(lex, text);
12341 	if (ptr == NULL) {
12342 		return (ISC_R_UNEXPECTEDEND);
12343 	}
12344 
12345 	ptr = next_token(lex, text);
12346 	if (ptr == NULL) {
12347 		count = 26;
12348 	} else {
12349 		count = strtoul(ptr, NULL, 10);
12350 	}
12351 
12352 	CHECK(isc_buffer_reserve(text, count));
12353 	for (i = 0; i < count; i++) {
12354 		CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
12355 	}
12356 
12357 	CHECK(putnull(text));
12358 
12359 cleanup:
12360 	return (result);
12361 }
12362 
12363 static isc_result_t
delete_keynames(dns_tsig_keyring_t * ring,char * target,unsigned int * foundkeys)12364 delete_keynames(dns_tsig_keyring_t *ring, char *target,
12365 		unsigned int *foundkeys) {
12366 	char namestr[DNS_NAME_FORMATSIZE];
12367 	isc_result_t result;
12368 	dns_rbtnodechain_t chain;
12369 	dns_name_t foundname;
12370 	dns_fixedname_t fixedorigin;
12371 	dns_name_t *origin;
12372 	dns_rbtnode_t *node;
12373 	dns_tsigkey_t *tkey;
12374 
12375 	dns_name_init(&foundname, NULL);
12376 	origin = dns_fixedname_initname(&fixedorigin);
12377 
12378 again:
12379 	dns_rbtnodechain_init(&chain);
12380 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12381 	if (result == ISC_R_NOTFOUND) {
12382 		dns_rbtnodechain_invalidate(&chain);
12383 		return (ISC_R_SUCCESS);
12384 	}
12385 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12386 		dns_rbtnodechain_invalidate(&chain);
12387 		return (result);
12388 	}
12389 
12390 	for (;;) {
12391 		node = NULL;
12392 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12393 		tkey = node->data;
12394 
12395 		if (tkey != NULL) {
12396 			if (!tkey->generated) {
12397 				goto nextkey;
12398 			}
12399 
12400 			dns_name_format(&tkey->name, namestr, sizeof(namestr));
12401 			if (strcmp(namestr, target) == 0) {
12402 				(*foundkeys)++;
12403 				dns_rbtnodechain_invalidate(&chain);
12404 				(void)dns_rbt_deletename(ring->keys,
12405 							 &tkey->name, false);
12406 				goto again;
12407 			}
12408 		}
12409 
12410 	nextkey:
12411 		result = dns_rbtnodechain_next(&chain, &foundname, origin);
12412 		if (result == ISC_R_NOMORE) {
12413 			break;
12414 		}
12415 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12416 			dns_rbtnodechain_invalidate(&chain);
12417 			return (result);
12418 		}
12419 	}
12420 
12421 	return (ISC_R_SUCCESS);
12422 }
12423 
12424 isc_result_t
named_server_tsigdelete(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)12425 named_server_tsigdelete(named_server_t *server, isc_lex_t *lex,
12426 			isc_buffer_t **text) {
12427 	isc_result_t result;
12428 	dns_view_t *view;
12429 	unsigned int foundkeys = 0;
12430 	char *ptr, *viewname;
12431 	char target[DNS_NAME_FORMATSIZE];
12432 	char fbuf[16];
12433 
12434 	REQUIRE(text != NULL);
12435 
12436 	(void)next_token(lex, text); /* skip command name */
12437 
12438 	ptr = next_token(lex, text);
12439 	if (ptr == NULL) {
12440 		return (ISC_R_UNEXPECTEDEND);
12441 	}
12442 	strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
12443 
12444 	viewname = next_token(lex, text);
12445 
12446 	result = isc_task_beginexclusive(server->task);
12447 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12448 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12449 	     view = ISC_LIST_NEXT(view, link))
12450 	{
12451 		if (viewname == NULL || strcmp(view->name, viewname) == 0) {
12452 			RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
12453 			result = delete_keynames(view->dynamickeys, target,
12454 						 &foundkeys);
12455 			RWUNLOCK(&view->dynamickeys->lock,
12456 				 isc_rwlocktype_write);
12457 			if (result != ISC_R_SUCCESS) {
12458 				isc_task_endexclusive(server->task);
12459 				return (result);
12460 			}
12461 		}
12462 	}
12463 	isc_task_endexclusive(server->task);
12464 
12465 	snprintf(fbuf, sizeof(fbuf), "%u", foundkeys);
12466 
12467 	CHECK(putstr(text, fbuf));
12468 	CHECK(putstr(text, " tsig keys deleted."));
12469 	CHECK(putnull(text));
12470 
12471 cleanup:
12472 	return (result);
12473 }
12474 
12475 static isc_result_t
list_keynames(dns_view_t * view,dns_tsig_keyring_t * ring,isc_buffer_t ** text,unsigned int * foundkeys)12476 list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t **text,
12477 	      unsigned int *foundkeys) {
12478 	char namestr[DNS_NAME_FORMATSIZE];
12479 	char creatorstr[DNS_NAME_FORMATSIZE];
12480 	isc_result_t result;
12481 	dns_rbtnodechain_t chain;
12482 	dns_name_t foundname;
12483 	dns_fixedname_t fixedorigin;
12484 	dns_name_t *origin;
12485 	dns_rbtnode_t *node;
12486 	dns_tsigkey_t *tkey;
12487 	const char *viewname;
12488 
12489 	if (view != NULL) {
12490 		viewname = view->name;
12491 	} else {
12492 		viewname = "(global)";
12493 	}
12494 
12495 	dns_name_init(&foundname, NULL);
12496 	origin = dns_fixedname_initname(&fixedorigin);
12497 	dns_rbtnodechain_init(&chain);
12498 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12499 	if (result == ISC_R_NOTFOUND) {
12500 		dns_rbtnodechain_invalidate(&chain);
12501 		return (ISC_R_SUCCESS);
12502 	}
12503 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12504 		dns_rbtnodechain_invalidate(&chain);
12505 		return (result);
12506 	}
12507 
12508 	for (;;) {
12509 		node = NULL;
12510 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12511 		tkey = node->data;
12512 
12513 		if (tkey != NULL) {
12514 			dns_name_format(&tkey->name, namestr, sizeof(namestr));
12515 			if (tkey->generated) {
12516 				dns_name_format(tkey->creator, creatorstr,
12517 						sizeof(creatorstr));
12518 				if (*foundkeys != 0) {
12519 					CHECK(putstr(text, "\n"));
12520 				}
12521 				CHECK(putstr(text, "view \""));
12522 				CHECK(putstr(text, viewname));
12523 				CHECK(putstr(text, "\"; type \"dynamic\"; key "
12524 						   "\""));
12525 				CHECK(putstr(text, namestr));
12526 				CHECK(putstr(text, "\"; creator \""));
12527 				CHECK(putstr(text, creatorstr));
12528 				CHECK(putstr(text, "\";"));
12529 			} else {
12530 				if (*foundkeys != 0) {
12531 					CHECK(putstr(text, "\n"));
12532 				}
12533 				CHECK(putstr(text, "view \""));
12534 				CHECK(putstr(text, viewname));
12535 				CHECK(putstr(text, "\"; type \"static\"; key "
12536 						   "\""));
12537 				CHECK(putstr(text, namestr));
12538 				CHECK(putstr(text, "\";"));
12539 			}
12540 			(*foundkeys)++;
12541 		}
12542 		result = dns_rbtnodechain_next(&chain, &foundname, origin);
12543 		if (result == ISC_R_NOMORE || result == DNS_R_NEWORIGIN) {
12544 			break;
12545 		}
12546 	}
12547 
12548 	return (ISC_R_SUCCESS);
12549 cleanup:
12550 	dns_rbtnodechain_invalidate(&chain);
12551 	return (result);
12552 }
12553 
12554 isc_result_t
named_server_tsiglist(named_server_t * server,isc_buffer_t ** text)12555 named_server_tsiglist(named_server_t *server, isc_buffer_t **text) {
12556 	isc_result_t result = ISC_R_SUCCESS;
12557 	dns_view_t *view;
12558 	unsigned int foundkeys = 0;
12559 
12560 	REQUIRE(text != NULL);
12561 
12562 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12563 	     view = ISC_LIST_NEXT(view, link))
12564 	{
12565 		RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12566 		result = list_keynames(view, view->statickeys, text,
12567 				       &foundkeys);
12568 		RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12569 		if (result != ISC_R_SUCCESS) {
12570 			return (result);
12571 		}
12572 		RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12573 		result = list_keynames(view, view->dynamickeys, text,
12574 				       &foundkeys);
12575 		RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12576 		if (result != ISC_R_SUCCESS) {
12577 			return (result);
12578 		}
12579 	}
12580 
12581 	if (foundkeys == 0) {
12582 		CHECK(putstr(text, "no tsig keys found."));
12583 	}
12584 
12585 	if (isc_buffer_usedlength(*text) > 0) {
12586 		CHECK(putnull(text));
12587 	}
12588 
12589 cleanup:
12590 	return (result);
12591 }
12592 
12593 /*
12594  * Act on a "sign" or "loadkeys" command from the command channel.
12595  */
12596 isc_result_t
named_server_rekey(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)12597 named_server_rekey(named_server_t *server, isc_lex_t *lex,
12598 		   isc_buffer_t **text) {
12599 	isc_result_t result;
12600 	dns_zone_t *zone = NULL;
12601 	dns_zonetype_t type;
12602 	uint16_t keyopts;
12603 	bool fullsign = false;
12604 	char *ptr;
12605 
12606 	REQUIRE(text != NULL);
12607 
12608 	ptr = next_token(lex, text);
12609 	if (ptr == NULL) {
12610 		return (ISC_R_UNEXPECTEDEND);
12611 	}
12612 
12613 	if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0) {
12614 		fullsign = true;
12615 	}
12616 
12617 	REQUIRE(text != NULL);
12618 
12619 	result = zone_from_args(server, lex, NULL, &zone, NULL, text, false);
12620 	if (result != ISC_R_SUCCESS) {
12621 		return (result);
12622 	}
12623 	if (zone == NULL) {
12624 		return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */
12625 	}
12626 
12627 	type = dns_zone_gettype(zone);
12628 	if (type != dns_zone_primary) {
12629 		dns_zone_detach(&zone);
12630 		return (DNS_R_NOTMASTER);
12631 	}
12632 
12633 	keyopts = dns_zone_getkeyopts(zone);
12634 
12635 	/*
12636 	 * "rndc loadkeys" requires "auto-dnssec maintain"
12637 	 * or a "dnssec-policy".
12638 	 */
12639 	if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) {
12640 		result = ISC_R_NOPERM;
12641 	} else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) {
12642 		result = ISC_R_NOPERM;
12643 	} else {
12644 		dns_zone_rekey(zone, fullsign);
12645 	}
12646 
12647 	dns_zone_detach(&zone);
12648 	return (result);
12649 }
12650 
12651 /*
12652  * Act on a "sync" command from the command channel.
12653  */
12654 static isc_result_t
synczone(dns_zone_t * zone,void * uap)12655 synczone(dns_zone_t *zone, void *uap) {
12656 	bool cleanup = *(bool *)uap;
12657 	isc_result_t result;
12658 	dns_zone_t *raw = NULL;
12659 	char *journal;
12660 
12661 	dns_zone_getraw(zone, &raw);
12662 	if (raw != NULL) {
12663 		synczone(raw, uap);
12664 		dns_zone_detach(&raw);
12665 	}
12666 
12667 	result = dns_zone_flush(zone);
12668 	if (result != ISC_R_SUCCESS) {
12669 		cleanup = false;
12670 	}
12671 	if (cleanup) {
12672 		journal = dns_zone_getjournal(zone);
12673 		if (journal != NULL) {
12674 			(void)isc_file_remove(journal);
12675 		}
12676 	}
12677 
12678 	return (result);
12679 }
12680 
12681 isc_result_t
named_server_sync(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)12682 named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
12683 	isc_result_t result, tresult;
12684 	dns_view_t *view;
12685 	dns_zone_t *zone = NULL;
12686 	char classstr[DNS_RDATACLASS_FORMATSIZE];
12687 	char zonename[DNS_NAME_FORMATSIZE];
12688 	const char *vname, *sep, *arg;
12689 	bool cleanup = false;
12690 
12691 	REQUIRE(text != NULL);
12692 
12693 	(void)next_token(lex, text);
12694 
12695 	arg = next_token(lex, text);
12696 	if (arg != NULL &&
12697 	    (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) {
12698 		cleanup = true;
12699 		arg = next_token(lex, text);
12700 	}
12701 
12702 	REQUIRE(text != NULL);
12703 
12704 	result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
12705 	if (result != ISC_R_SUCCESS) {
12706 		return (result);
12707 	}
12708 
12709 	if (zone == NULL) {
12710 		result = isc_task_beginexclusive(server->task);
12711 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
12712 		tresult = ISC_R_SUCCESS;
12713 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12714 		     view = ISC_LIST_NEXT(view, link))
12715 		{
12716 			result = dns_zt_apply(view->zonetable, false, NULL,
12717 					      synczone, &cleanup);
12718 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12719 			{
12720 				tresult = result;
12721 			}
12722 		}
12723 		isc_task_endexclusive(server->task);
12724 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12725 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12726 			      "dumping all zones%s: %s",
12727 			      cleanup ? ", removing journal files" : "",
12728 			      isc_result_totext(result));
12729 		return (tresult);
12730 	}
12731 
12732 	result = isc_task_beginexclusive(server->task);
12733 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12734 	result = synczone(zone, &cleanup);
12735 	isc_task_endexclusive(server->task);
12736 
12737 	view = dns_zone_getview(zone);
12738 	if (strcmp(view->name, "_default") == 0 ||
12739 	    strcmp(view->name, "_bind") == 0) {
12740 		vname = "";
12741 		sep = "";
12742 	} else {
12743 		vname = view->name;
12744 		sep = " ";
12745 	}
12746 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
12747 			      sizeof(classstr));
12748 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
12749 	isc_log_write(
12750 		named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12751 		ISC_LOG_INFO, "sync: dumping zone '%s/%s'%s%s%s: %s", zonename,
12752 		classstr, sep, vname, cleanup ? ", removing journal file" : "",
12753 		isc_result_totext(result));
12754 	dns_zone_detach(&zone);
12755 	return (result);
12756 }
12757 
12758 /*
12759  * Act on a "freeze" or "thaw" command from the command channel.
12760  */
12761 isc_result_t
named_server_freeze(named_server_t * server,bool freeze,isc_lex_t * lex,isc_buffer_t ** text)12762 named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex,
12763 		    isc_buffer_t **text) {
12764 	isc_result_t result, tresult;
12765 	dns_zone_t *mayberaw = NULL, *raw = NULL;
12766 	dns_zonetype_t type;
12767 	char classstr[DNS_RDATACLASS_FORMATSIZE];
12768 	char zonename[DNS_NAME_FORMATSIZE];
12769 	dns_view_t *view;
12770 	const char *vname, *sep;
12771 	bool frozen;
12772 	const char *msg = NULL;
12773 
12774 	REQUIRE(text != NULL);
12775 
12776 	result = zone_from_args(server, lex, NULL, &mayberaw, NULL, text, true);
12777 	if (result != ISC_R_SUCCESS) {
12778 		return (result);
12779 	}
12780 	if (mayberaw == NULL) {
12781 		result = isc_task_beginexclusive(server->task);
12782 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
12783 		tresult = ISC_R_SUCCESS;
12784 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12785 		     view = ISC_LIST_NEXT(view, link))
12786 		{
12787 			result = dns_view_freezezones(view, freeze);
12788 			if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12789 			{
12790 				tresult = result;
12791 			}
12792 		}
12793 		isc_task_endexclusive(server->task);
12794 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12795 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12796 			      "%s all zones: %s",
12797 			      freeze ? "freezing" : "thawing",
12798 			      isc_result_totext(tresult));
12799 		return (tresult);
12800 	}
12801 	dns_zone_getraw(mayberaw, &raw);
12802 	if (raw != NULL) {
12803 		dns_zone_detach(&mayberaw);
12804 		dns_zone_attach(raw, &mayberaw);
12805 		dns_zone_detach(&raw);
12806 	}
12807 	type = dns_zone_gettype(mayberaw);
12808 	if (type != dns_zone_primary) {
12809 		dns_zone_detach(&mayberaw);
12810 		return (DNS_R_NOTMASTER);
12811 	}
12812 
12813 	if (freeze && !dns_zone_isdynamic(mayberaw, true)) {
12814 		dns_zone_detach(&mayberaw);
12815 		return (DNS_R_NOTDYNAMIC);
12816 	}
12817 
12818 	result = isc_task_beginexclusive(server->task);
12819 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
12820 	frozen = dns_zone_getupdatedisabled(mayberaw);
12821 	if (freeze) {
12822 		if (frozen) {
12823 			msg = "WARNING: The zone was already frozen.\n"
12824 			      "Someone else may be editing it or "
12825 			      "it may still be re-loading.";
12826 			result = DNS_R_FROZEN;
12827 		}
12828 		if (result == ISC_R_SUCCESS) {
12829 			result = dns_zone_flush(mayberaw);
12830 			if (result != ISC_R_SUCCESS) {
12831 				msg = "Flushing the zone updates to "
12832 				      "disk failed.";
12833 			}
12834 		}
12835 		if (result == ISC_R_SUCCESS) {
12836 			dns_zone_setupdatedisabled(mayberaw, freeze);
12837 		}
12838 	} else {
12839 		if (frozen) {
12840 			result = dns_zone_loadandthaw(mayberaw);
12841 			switch (result) {
12842 			case ISC_R_SUCCESS:
12843 			case DNS_R_UPTODATE:
12844 				msg = "The zone reload and thaw was "
12845 				      "successful.";
12846 				result = ISC_R_SUCCESS;
12847 				break;
12848 			case DNS_R_CONTINUE:
12849 				msg = "A zone reload and thaw was started.\n"
12850 				      "Check the logs to see the result.";
12851 				result = ISC_R_SUCCESS;
12852 				break;
12853 			default:
12854 				break;
12855 			}
12856 		}
12857 	}
12858 	isc_task_endexclusive(server->task);
12859 
12860 	if (msg != NULL) {
12861 		(void)putstr(text, msg);
12862 		(void)putnull(text);
12863 	}
12864 
12865 	view = dns_zone_getview(mayberaw);
12866 	if (strcmp(view->name, "_default") == 0 ||
12867 	    strcmp(view->name, "_bind") == 0) {
12868 		vname = "";
12869 		sep = "";
12870 	} else {
12871 		vname = view->name;
12872 		sep = " ";
12873 	}
12874 	dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr,
12875 			      sizeof(classstr));
12876 	dns_name_format(dns_zone_getorigin(mayberaw), zonename,
12877 			sizeof(zonename));
12878 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12879 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12880 		      "%s zone '%s/%s'%s%s: %s",
12881 		      freeze ? "freezing" : "thawing", zonename, classstr, sep,
12882 		      vname, isc_result_totext(result));
12883 	dns_zone_detach(&mayberaw);
12884 	return (result);
12885 }
12886 
12887 #ifdef HAVE_LIBSCF
12888 /*
12889  * This function adds a message for rndc to echo if named
12890  * is managed by smf and is also running chroot.
12891  */
12892 isc_result_t
named_smf_add_message(isc_buffer_t ** text)12893 named_smf_add_message(isc_buffer_t **text) {
12894 	REQUIRE(text != NULL);
12895 
12896 	return (putstr(text, "use svcadm(1M) to manage named"));
12897 }
12898 #endif /* HAVE_LIBSCF */
12899 
12900 #ifndef HAVE_LMDB
12901 
12902 /*
12903  * Emit a comment at the top of the nzf file containing the viewname
12904  * Expects the fp to already be open for writing
12905  */
12906 #define HEADER1 "# New zone file for view: "
12907 #define HEADER2                                                     \
12908 	"\n# This file contains configuration for zones added by\n" \
12909 	"# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
12910 static isc_result_t
add_comment(FILE * fp,const char * viewname)12911 add_comment(FILE *fp, const char *viewname) {
12912 	isc_result_t result;
12913 	CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
12914 	CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
12915 	CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
12916 cleanup:
12917 	return (result);
12918 }
12919 
12920 static void
dumpzone(void * arg,const char * buf,int len)12921 dumpzone(void *arg, const char *buf, int len) {
12922 	FILE *fp = arg;
12923 
12924 	(void)isc_stdio_write(buf, len, 1, fp, NULL);
12925 }
12926 
12927 static isc_result_t
nzf_append(dns_view_t * view,const cfg_obj_t * zconfig)12928 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
12929 	isc_result_t result;
12930 	off_t offset;
12931 	FILE *fp = NULL;
12932 	bool offsetok = false;
12933 
12934 	LOCK(&view->new_zone_lock);
12935 
12936 	CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
12937 	CHECK(isc_stdio_seek(fp, 0, SEEK_END));
12938 
12939 	CHECK(isc_stdio_tell(fp, &offset));
12940 	offsetok = true;
12941 	if (offset == 0) {
12942 		CHECK(add_comment(fp, view->name));
12943 	}
12944 
12945 	CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
12946 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
12947 	CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
12948 	CHECK(isc_stdio_flush(fp));
12949 	result = isc_stdio_close(fp);
12950 	fp = NULL;
12951 
12952 cleanup:
12953 	if (fp != NULL) {
12954 		(void)isc_stdio_close(fp);
12955 		if (offsetok) {
12956 			isc_result_t result2;
12957 
12958 			result2 = isc_file_truncate(view->new_zone_file,
12959 						    offset);
12960 			if (result2 != ISC_R_SUCCESS) {
12961 				isc_log_write(
12962 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12963 					NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12964 					"Error truncating NZF file '%s' "
12965 					"during rollback from append: "
12966 					"%s",
12967 					view->new_zone_file,
12968 					isc_result_totext(result2));
12969 			}
12970 		}
12971 	}
12972 	UNLOCK(&view->new_zone_lock);
12973 	return (result);
12974 }
12975 
12976 static isc_result_t
nzf_writeconf(const cfg_obj_t * config,dns_view_t * view)12977 nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
12978 	const cfg_obj_t *zl = NULL;
12979 	cfg_list_t *list;
12980 	const cfg_listelt_t *elt;
12981 
12982 	FILE *fp = NULL;
12983 	char tmp[1024];
12984 	isc_result_t result;
12985 
12986 	result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp,
12987 				   sizeof(tmp));
12988 	if (result == ISC_R_SUCCESS) {
12989 		result = isc_file_openunique(tmp, &fp);
12990 	}
12991 	if (result != ISC_R_SUCCESS) {
12992 		return (result);
12993 	}
12994 
12995 	cfg_map_get(config, "zone", &zl);
12996 	if (!cfg_obj_islist(zl)) {
12997 		CHECK(ISC_R_FAILURE);
12998 	}
12999 
13000 	DE_CONST(&zl->value.list, list);
13001 
13002 	CHECK(add_comment(fp, view->name)); /* force a comment */
13003 
13004 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13005 	     elt = ISC_LIST_NEXT(elt, link)) {
13006 		const cfg_obj_t *zconfig = cfg_listelt_value(elt);
13007 
13008 		CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
13009 		cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
13010 		CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
13011 	}
13012 
13013 	CHECK(isc_stdio_flush(fp));
13014 	result = isc_stdio_close(fp);
13015 	fp = NULL;
13016 	if (result != ISC_R_SUCCESS) {
13017 		goto cleanup;
13018 	}
13019 	CHECK(isc_file_rename(tmp, view->new_zone_file));
13020 	return (result);
13021 
13022 cleanup:
13023 	if (fp != NULL) {
13024 		(void)isc_stdio_close(fp);
13025 	}
13026 	(void)isc_file_remove(tmp);
13027 	return (result);
13028 }
13029 
13030 #else /* HAVE_LMDB */
13031 
13032 static void
nzd_setkey(MDB_val * key,dns_name_t * name,char * namebuf,size_t buflen)13033 nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
13034 	dns_fixedname_t fixed;
13035 
13036 	dns_fixedname_init(&fixed);
13037 	dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
13038 	dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
13039 
13040 	key->mv_data = namebuf;
13041 	key->mv_size = strlen(namebuf);
13042 }
13043 
13044 static void
dumpzone(void * arg,const char * buf,int len)13045 dumpzone(void *arg, const char *buf, int len) {
13046 	ns_dzarg_t *dzarg = arg;
13047 	isc_result_t result;
13048 
13049 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
13050 
13051 	result = putmem(dzarg->text, buf, len);
13052 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
13053 		dzarg->result = result;
13054 	}
13055 }
13056 
13057 static isc_result_t
nzd_save(MDB_txn ** txnp,MDB_dbi dbi,dns_zone_t * zone,const cfg_obj_t * zconfig)13058 nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
13059 	 const cfg_obj_t *zconfig) {
13060 	isc_result_t result;
13061 	int status;
13062 	dns_view_t *view;
13063 	bool commit = false;
13064 	isc_buffer_t *text = NULL;
13065 	char namebuf[1024];
13066 	MDB_val key, data;
13067 	ns_dzarg_t dzarg;
13068 
13069 	view = dns_zone_getview(zone);
13070 
13071 	nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
13072 
13073 	if (zconfig == NULL) {
13074 		/* We're deleting the zone from the database */
13075 		status = mdb_del(*txnp, dbi, &key, NULL);
13076 		if (status != MDB_SUCCESS && status != MDB_NOTFOUND) {
13077 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13078 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13079 				      "Error deleting zone %s "
13080 				      "from NZD database: %s",
13081 				      namebuf, mdb_strerror(status));
13082 			result = ISC_R_FAILURE;
13083 			goto cleanup;
13084 		} else if (status != MDB_NOTFOUND) {
13085 			commit = true;
13086 		}
13087 	} else {
13088 		/* We're creating or overwriting the zone */
13089 		const cfg_obj_t *zoptions;
13090 
13091 		isc_buffer_allocate(view->mctx, &text, 256);
13092 
13093 		zoptions = cfg_tuple_get(zconfig, "options");
13094 		if (zoptions == NULL) {
13095 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13096 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13097 				      "Unable to get options from config in "
13098 				      "nzd_save()");
13099 			result = ISC_R_FAILURE;
13100 			goto cleanup;
13101 		}
13102 
13103 		dzarg.magic = DZARG_MAGIC;
13104 		dzarg.text = &text;
13105 		dzarg.result = ISC_R_SUCCESS;
13106 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13107 		if (dzarg.result != ISC_R_SUCCESS) {
13108 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13109 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13110 				      "Error writing zone config to "
13111 				      "buffer in nzd_save(): %s",
13112 				      isc_result_totext(dzarg.result));
13113 			result = dzarg.result;
13114 			goto cleanup;
13115 		}
13116 
13117 		data.mv_data = isc_buffer_base(text);
13118 		data.mv_size = isc_buffer_usedlength(text);
13119 
13120 		status = mdb_put(*txnp, dbi, &key, &data, 0);
13121 		if (status != MDB_SUCCESS) {
13122 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13123 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13124 				      "Error inserting zone in "
13125 				      "NZD database: %s",
13126 				      mdb_strerror(status));
13127 			result = ISC_R_FAILURE;
13128 			goto cleanup;
13129 		}
13130 
13131 		commit = true;
13132 	}
13133 
13134 	result = ISC_R_SUCCESS;
13135 
13136 cleanup:
13137 	if (!commit || result != ISC_R_SUCCESS) {
13138 		(void)mdb_txn_abort(*txnp);
13139 	} else {
13140 		status = mdb_txn_commit(*txnp);
13141 		if (status != MDB_SUCCESS) {
13142 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13143 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13144 				      "Error committing "
13145 				      "NZD database: %s",
13146 				      mdb_strerror(status));
13147 			result = ISC_R_FAILURE;
13148 		}
13149 	}
13150 	*txnp = NULL;
13151 
13152 	if (text != NULL) {
13153 		isc_buffer_free(&text);
13154 	}
13155 
13156 	return (result);
13157 }
13158 
13159 /*
13160  * Check whether the new zone database for 'view' can be opened for writing.
13161  *
13162  * Caller must hold 'view->new_zone_lock'.
13163  */
13164 static isc_result_t
nzd_writable(dns_view_t * view)13165 nzd_writable(dns_view_t *view) {
13166 	isc_result_t result = ISC_R_SUCCESS;
13167 	int status;
13168 	MDB_dbi dbi;
13169 	MDB_txn *txn = NULL;
13170 
13171 	REQUIRE(view != NULL);
13172 
13173 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn);
13174 	if (status != MDB_SUCCESS) {
13175 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13176 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13177 			      "mdb_txn_begin: %s", mdb_strerror(status));
13178 		return (ISC_R_FAILURE);
13179 	}
13180 
13181 	status = mdb_dbi_open(txn, NULL, 0, &dbi);
13182 	if (status != MDB_SUCCESS) {
13183 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13184 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13185 			      "mdb_dbi_open: %s", mdb_strerror(status));
13186 		result = ISC_R_FAILURE;
13187 	}
13188 
13189 	mdb_txn_abort(txn);
13190 	return (result);
13191 }
13192 
13193 /*
13194  * Open the new zone database for 'view' and start a transaction for it.
13195  *
13196  * Caller must hold 'view->new_zone_lock'.
13197  */
13198 static isc_result_t
nzd_open(dns_view_t * view,unsigned int flags,MDB_txn ** txnp,MDB_dbi * dbi)13199 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
13200 	int status;
13201 	MDB_txn *txn = NULL;
13202 
13203 	REQUIRE(view != NULL);
13204 	REQUIRE(txnp != NULL && *txnp == NULL);
13205 	REQUIRE(dbi != NULL);
13206 
13207 	status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn);
13208 	if (status != MDB_SUCCESS) {
13209 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13210 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13211 			      "mdb_txn_begin: %s", mdb_strerror(status));
13212 		goto cleanup;
13213 	}
13214 
13215 	status = mdb_dbi_open(txn, NULL, 0, dbi);
13216 	if (status != MDB_SUCCESS) {
13217 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13218 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13219 			      "mdb_dbi_open: %s", mdb_strerror(status));
13220 		goto cleanup;
13221 	}
13222 
13223 	*txnp = txn;
13224 
13225 cleanup:
13226 	if (status != MDB_SUCCESS) {
13227 		if (txn != NULL) {
13228 			mdb_txn_abort(txn);
13229 		}
13230 		return (ISC_R_FAILURE);
13231 	}
13232 
13233 	return (ISC_R_SUCCESS);
13234 }
13235 
13236 /*
13237  * nzd_env_close() and nzd_env_reopen are a kluge to address the
13238  * problem of an NZD file possibly being created before we drop
13239  * root privileges.
13240  */
13241 static void
nzd_env_close(dns_view_t * view)13242 nzd_env_close(dns_view_t *view) {
13243 	const char *dbpath = NULL;
13244 	char dbpath_copy[PATH_MAX];
13245 	char lockpath[PATH_MAX];
13246 	int status, ret;
13247 
13248 	if (view->new_zone_dbenv == NULL) {
13249 		return;
13250 	}
13251 
13252 	status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
13253 	INSIST(status == MDB_SUCCESS);
13254 	snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
13255 	strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
13256 	mdb_env_close((MDB_env *)view->new_zone_dbenv);
13257 
13258 	/*
13259 	 * Database files must be owned by the eventual user, not by root.
13260 	 */
13261 	ret = chown(dbpath_copy, ns_os_uid(), -1);
13262 	UNUSED(ret);
13263 
13264 	/*
13265 	 * Some platforms need the lockfile not to exist when we reopen the
13266 	 * environment.
13267 	 */
13268 	(void)isc_file_remove(lockpath);
13269 
13270 	view->new_zone_dbenv = NULL;
13271 }
13272 
13273 static isc_result_t
nzd_env_reopen(dns_view_t * view)13274 nzd_env_reopen(dns_view_t *view) {
13275 	isc_result_t result;
13276 	MDB_env *env = NULL;
13277 	int status;
13278 
13279 	if (view->new_zone_db == NULL) {
13280 		return (ISC_R_SUCCESS);
13281 	}
13282 
13283 	nzd_env_close(view);
13284 
13285 	status = mdb_env_create(&env);
13286 	if (status != MDB_SUCCESS) {
13287 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13288 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13289 			      "mdb_env_create failed: %s",
13290 			      mdb_strerror(status));
13291 		CHECK(ISC_R_FAILURE);
13292 	}
13293 
13294 	if (view->new_zone_mapsize != 0ULL) {
13295 		status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
13296 		if (status != MDB_SUCCESS) {
13297 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13298 				      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13299 				      "mdb_env_set_mapsize failed: %s",
13300 				      mdb_strerror(status));
13301 			CHECK(ISC_R_FAILURE);
13302 		}
13303 	}
13304 
13305 	status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
13306 	if (status != MDB_SUCCESS) {
13307 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
13308 			      ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
13309 			      "mdb_env_open of '%s' failed: %s",
13310 			      view->new_zone_db, mdb_strerror(status));
13311 		CHECK(ISC_R_FAILURE);
13312 	}
13313 
13314 	view->new_zone_dbenv = env;
13315 	env = NULL;
13316 	result = ISC_R_SUCCESS;
13317 
13318 cleanup:
13319 	if (env != NULL) {
13320 		mdb_env_close(env);
13321 	}
13322 	return (result);
13323 }
13324 
13325 /*
13326  * If 'commit' is true, commit the new zone database transaction pointed to by
13327  * 'txnp'; otherwise, abort that transaction.
13328  *
13329  * Caller must hold 'view->new_zone_lock' for the view that the transaction
13330  * pointed to by 'txnp' was started for.
13331  */
13332 static isc_result_t
nzd_close(MDB_txn ** txnp,bool commit)13333 nzd_close(MDB_txn **txnp, bool commit) {
13334 	isc_result_t result = ISC_R_SUCCESS;
13335 	int status;
13336 
13337 	REQUIRE(txnp != NULL);
13338 
13339 	if (*txnp != NULL) {
13340 		if (commit) {
13341 			status = mdb_txn_commit(*txnp);
13342 			if (status != MDB_SUCCESS) {
13343 				result = ISC_R_FAILURE;
13344 			}
13345 		} else {
13346 			mdb_txn_abort(*txnp);
13347 		}
13348 		*txnp = NULL;
13349 	}
13350 
13351 	return (result);
13352 }
13353 
13354 /*
13355  * Count the zones configured in the new zone database for 'view' and store the
13356  * result in 'countp'.
13357  *
13358  * Caller must hold 'view->new_zone_lock'.
13359  */
13360 static isc_result_t
nzd_count(dns_view_t * view,int * countp)13361 nzd_count(dns_view_t *view, int *countp) {
13362 	isc_result_t result;
13363 	int status;
13364 	MDB_txn *txn = NULL;
13365 	MDB_dbi dbi;
13366 	MDB_stat statbuf;
13367 
13368 	REQUIRE(countp != NULL);
13369 
13370 	result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
13371 	if (result != ISC_R_SUCCESS) {
13372 		goto cleanup;
13373 	}
13374 
13375 	status = mdb_stat(txn, dbi, &statbuf);
13376 	if (status != MDB_SUCCESS) {
13377 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13378 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13379 			      "mdb_stat: %s", mdb_strerror(status));
13380 		result = ISC_R_FAILURE;
13381 		goto cleanup;
13382 	}
13383 
13384 	*countp = statbuf.ms_entries;
13385 
13386 cleanup:
13387 	(void)nzd_close(&txn, false);
13388 
13389 	return (result);
13390 }
13391 
13392 /*
13393  * Migrate zone configuration from an NZF file to an NZD database.
13394  * Caller must hold view->new_zone_lock.
13395  */
13396 static isc_result_t
migrate_nzf(dns_view_t * view)13397 migrate_nzf(dns_view_t *view) {
13398 	isc_result_t result;
13399 	cfg_obj_t *nzf_config = NULL;
13400 	int status, n;
13401 	isc_buffer_t *text = NULL;
13402 	bool commit = false;
13403 	const cfg_obj_t *zonelist;
13404 	const cfg_listelt_t *element;
13405 	char tempname[PATH_MAX];
13406 	MDB_txn *txn = NULL;
13407 	MDB_dbi dbi;
13408 	MDB_val key, data;
13409 	ns_dzarg_t dzarg;
13410 
13411 	/*
13412 	 * If NZF file doesn't exist, or NZD DB exists and already
13413 	 * has data, return without attempting migration.
13414 	 */
13415 	if (!isc_file_exists(view->new_zone_file)) {
13416 		result = ISC_R_SUCCESS;
13417 		goto cleanup;
13418 	}
13419 
13420 	result = nzd_count(view, &n);
13421 	if (result == ISC_R_SUCCESS && n > 0) {
13422 		result = ISC_R_SUCCESS;
13423 		goto cleanup;
13424 	}
13425 
13426 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13427 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13428 		      "Migrating zones from NZF file '%s' to "
13429 		      "NZD database '%s'",
13430 		      view->new_zone_file, view->new_zone_db);
13431 	/*
13432 	 * Instead of blindly copying lines, we parse the NZF file using
13433 	 * the configuration parser, because it validates it against the
13434 	 * config type, giving us a guarantee that valid configuration
13435 	 * will be written to DB.
13436 	 */
13437 	cfg_parser_reset(named_g_addparser);
13438 	result = cfg_parse_file(named_g_addparser, view->new_zone_file,
13439 				&cfg_type_addzoneconf, &nzf_config);
13440 	if (result != ISC_R_SUCCESS) {
13441 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13442 			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13443 			      "Error parsing NZF file '%s': %s",
13444 			      view->new_zone_file, isc_result_totext(result));
13445 		goto cleanup;
13446 	}
13447 
13448 	zonelist = NULL;
13449 	CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
13450 	if (!cfg_obj_islist(zonelist)) {
13451 		CHECK(ISC_R_FAILURE);
13452 	}
13453 
13454 	CHECK(nzd_open(view, 0, &txn, &dbi));
13455 
13456 	isc_buffer_allocate(view->mctx, &text, 256);
13457 
13458 	for (element = cfg_list_first(zonelist); element != NULL;
13459 	     element = cfg_list_next(element))
13460 	{
13461 		const cfg_obj_t *zconfig;
13462 		const cfg_obj_t *zoptions;
13463 		char zname[DNS_NAME_FORMATSIZE];
13464 		dns_fixedname_t fname;
13465 		dns_name_t *name;
13466 		const char *origin;
13467 		isc_buffer_t b;
13468 
13469 		zconfig = cfg_listelt_value(element);
13470 
13471 		origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
13472 		if (origin == NULL) {
13473 			result = ISC_R_FAILURE;
13474 			goto cleanup;
13475 		}
13476 
13477 		/* Normalize zone name */
13478 		isc_buffer_constinit(&b, origin, strlen(origin));
13479 		isc_buffer_add(&b, strlen(origin));
13480 		name = dns_fixedname_initname(&fname);
13481 		CHECK(dns_name_fromtext(name, &b, dns_rootname,
13482 					DNS_NAME_DOWNCASE, NULL));
13483 		dns_name_format(name, zname, sizeof(zname));
13484 
13485 		key.mv_data = zname;
13486 		key.mv_size = strlen(zname);
13487 
13488 		zoptions = cfg_tuple_get(zconfig, "options");
13489 		if (zoptions == NULL) {
13490 			result = ISC_R_FAILURE;
13491 			goto cleanup;
13492 		}
13493 
13494 		isc_buffer_clear(text);
13495 		dzarg.magic = DZARG_MAGIC;
13496 		dzarg.text = &text;
13497 		dzarg.result = ISC_R_SUCCESS;
13498 		cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13499 		if (dzarg.result != ISC_R_SUCCESS) {
13500 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13501 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13502 				      "Error writing zone config to "
13503 				      "buffer in migrate_nzf(): %s",
13504 				      isc_result_totext(result));
13505 			result = dzarg.result;
13506 			goto cleanup;
13507 		}
13508 
13509 		data.mv_data = isc_buffer_base(text);
13510 		data.mv_size = isc_buffer_usedlength(text);
13511 
13512 		status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
13513 		if (status != MDB_SUCCESS) {
13514 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13515 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13516 				      "Error inserting zone in "
13517 				      "NZD database: %s",
13518 				      mdb_strerror(status));
13519 			result = ISC_R_FAILURE;
13520 			goto cleanup;
13521 		}
13522 
13523 		commit = true;
13524 	}
13525 
13526 	result = ISC_R_SUCCESS;
13527 
13528 	/*
13529 	 * Leaving the NZF file in place is harmless as we won't use it
13530 	 * if an NZD database is found for the view. But we rename NZF file
13531 	 * to a backup name here.
13532 	 */
13533 	strlcpy(tempname, view->new_zone_file, sizeof(tempname));
13534 	if (strlen(tempname) < sizeof(tempname) - 1) {
13535 		strlcat(tempname, "~", sizeof(tempname));
13536 		isc_file_rename(view->new_zone_file, tempname);
13537 	}
13538 
13539 cleanup:
13540 	if (result != ISC_R_SUCCESS) {
13541 		(void)nzd_close(&txn, false);
13542 	} else {
13543 		result = nzd_close(&txn, commit);
13544 	}
13545 
13546 	if (text != NULL) {
13547 		isc_buffer_free(&text);
13548 	}
13549 
13550 	if (nzf_config != NULL) {
13551 		cfg_obj_destroy(named_g_addparser, &nzf_config);
13552 	}
13553 
13554 	return (result);
13555 }
13556 
13557 #endif /* HAVE_LMDB */
13558 
13559 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)13560 newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
13561 	      cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
13562 	      bool *redirectp, isc_buffer_t **text) {
13563 	isc_result_t result;
13564 	isc_buffer_t argbuf;
13565 	bool redirect = false;
13566 	cfg_obj_t *zoneconf = NULL;
13567 	const cfg_obj_t *zlist = NULL;
13568 	const cfg_obj_t *zoneobj = NULL;
13569 	const cfg_obj_t *zoptions = NULL;
13570 	const cfg_obj_t *obj = NULL;
13571 	const char *viewname = NULL;
13572 	dns_rdataclass_t rdclass;
13573 	dns_view_t *view = NULL;
13574 	const char *bn = NULL;
13575 
13576 	REQUIRE(viewp != NULL && *viewp == NULL);
13577 	REQUIRE(zoneobjp != NULL && *zoneobjp == NULL);
13578 	REQUIRE(zoneconfp != NULL && *zoneconfp == NULL);
13579 	REQUIRE(redirectp != NULL);
13580 
13581 	/* Try to parse the argument string */
13582 	isc_buffer_init(&argbuf, command, (unsigned int)strlen(command));
13583 	isc_buffer_add(&argbuf, strlen(command));
13584 
13585 	if (strncasecmp(command, "add", 3) == 0) {
13586 		bn = "addzone";
13587 	} else if (strncasecmp(command, "mod", 3) == 0) {
13588 		bn = "modzone";
13589 	} else {
13590 		INSIST(0);
13591 		ISC_UNREACHABLE();
13592 	}
13593 
13594 	/*
13595 	 * Convert the "addzone" or "modzone" to just "zone", for
13596 	 * the benefit of the parser
13597 	 */
13598 	isc_buffer_forward(&argbuf, 3);
13599 
13600 	cfg_parser_reset(named_g_addparser);
13601 	CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0,
13602 			       &cfg_type_addzoneconf, 0, &zoneconf));
13603 	CHECK(cfg_map_get(zoneconf, "zone", &zlist));
13604 	if (!cfg_obj_islist(zlist)) {
13605 		CHECK(ISC_R_FAILURE);
13606 	}
13607 
13608 	/* For now we only support adding one zone at a time */
13609 	zoneobj = cfg_listelt_value(cfg_list_first(zlist));
13610 
13611 	/* Check the zone type for ones that are not supported by addzone. */
13612 	zoptions = cfg_tuple_get(zoneobj, "options");
13613 
13614 	obj = NULL;
13615 	(void)cfg_map_get(zoptions, "type", &obj);
13616 	if (obj == NULL) {
13617 		(void)cfg_map_get(zoptions, "in-view", &obj);
13618 		if (obj != NULL) {
13619 			(void)putstr(text, "'in-view' zones not supported by ");
13620 			(void)putstr(text, bn);
13621 		} else {
13622 			(void)putstr(text, "zone type not specified");
13623 		}
13624 		CHECK(ISC_R_FAILURE);
13625 	}
13626 
13627 	if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
13628 	    strcasecmp(cfg_obj_asstring(obj), "forward") == 0 ||
13629 	    strcasecmp(cfg_obj_asstring(obj), "delegation-only") == 0)
13630 	{
13631 		(void)putstr(text, "'");
13632 		(void)putstr(text, cfg_obj_asstring(obj));
13633 		(void)putstr(text, "' zones not supported by ");
13634 		(void)putstr(text, bn);
13635 		CHECK(ISC_R_FAILURE);
13636 	}
13637 
13638 	if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0) {
13639 		redirect = true;
13640 	}
13641 
13642 	/* Make sense of optional class argument */
13643 	obj = cfg_tuple_get(zoneobj, "class");
13644 	CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass));
13645 
13646 	/* Make sense of optional view argument */
13647 	obj = cfg_tuple_get(zoneobj, "view");
13648 	if (obj && cfg_obj_isstring(obj)) {
13649 		viewname = cfg_obj_asstring(obj);
13650 	}
13651 	if (viewname == NULL || *viewname == '\0') {
13652 		viewname = "_default";
13653 	}
13654 	result = dns_viewlist_find(&server->viewlist, viewname, rdclass, &view);
13655 	if (result == ISC_R_NOTFOUND) {
13656 		(void)putstr(text, "no matching view found for '");
13657 		(void)putstr(text, viewname);
13658 		(void)putstr(text, "'");
13659 		goto cleanup;
13660 	} else if (result != ISC_R_SUCCESS) {
13661 		goto cleanup;
13662 	}
13663 
13664 	*viewp = view;
13665 	*zoneobjp = zoneobj;
13666 	*zoneconfp = zoneconf;
13667 	*redirectp = redirect;
13668 
13669 	return (ISC_R_SUCCESS);
13670 
13671 cleanup:
13672 	if (zoneconf != NULL) {
13673 		cfg_obj_destroy(named_g_addparser, &zoneconf);
13674 	}
13675 	if (view != NULL) {
13676 		dns_view_detach(&view);
13677 	}
13678 
13679 	return (result);
13680 }
13681 
13682 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)13683 delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config,
13684 		const dns_name_t *zname, nzfwriter_t nzfwriter) {
13685 	isc_result_t result = ISC_R_NOTFOUND;
13686 	const cfg_listelt_t *elt = NULL;
13687 	const cfg_obj_t *zl = NULL;
13688 	cfg_list_t *list;
13689 	dns_fixedname_t myfixed;
13690 	dns_name_t *myname;
13691 
13692 	REQUIRE(view != NULL);
13693 	REQUIRE(pctx != NULL);
13694 	REQUIRE(config != NULL);
13695 	REQUIRE(zname != NULL);
13696 
13697 	LOCK(&view->new_zone_lock);
13698 
13699 	cfg_map_get(config, "zone", &zl);
13700 
13701 	if (!cfg_obj_islist(zl)) {
13702 		CHECK(ISC_R_FAILURE);
13703 	}
13704 
13705 	DE_CONST(&zl->value.list, list);
13706 
13707 	myname = dns_fixedname_initname(&myfixed);
13708 
13709 	for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13710 	     elt = ISC_LIST_NEXT(elt, link)) {
13711 		const cfg_obj_t *zconf = cfg_listelt_value(elt);
13712 		const char *zn;
13713 		cfg_listelt_t *e;
13714 
13715 		zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
13716 		result = dns_name_fromstring(myname, zn, 0, NULL);
13717 		if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname)) {
13718 			continue;
13719 		}
13720 
13721 		DE_CONST(elt, e);
13722 		ISC_LIST_UNLINK(*list, e, link);
13723 		cfg_obj_destroy(pctx, &e->obj);
13724 		isc_mem_put(pctx->mctx, e, sizeof(*e));
13725 		result = ISC_R_SUCCESS;
13726 		break;
13727 	}
13728 
13729 	/*
13730 	 * Write config to NZF file if appropriate
13731 	 */
13732 	if (nzfwriter != NULL && view->new_zone_file != NULL) {
13733 		result = nzfwriter(config, view);
13734 	}
13735 
13736 cleanup:
13737 	UNLOCK(&view->new_zone_lock);
13738 	return (result);
13739 }
13740 
13741 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)13742 do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13743 	   dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
13744 	   bool redirect, isc_buffer_t **text) {
13745 	isc_result_t result, tresult;
13746 	dns_zone_t *zone = NULL;
13747 #ifndef HAVE_LMDB
13748 	FILE *fp = NULL;
13749 	bool cleanup_config = false;
13750 #else /* HAVE_LMDB */
13751 	MDB_txn *txn = NULL;
13752 	MDB_dbi dbi;
13753 	bool locked = false;
13754 
13755 	UNUSED(zoneconf);
13756 #endif
13757 
13758 	/* Zone shouldn't already exist */
13759 	if (redirect) {
13760 		result = (view->redirect != NULL) ? ISC_R_SUCCESS
13761 						  : ISC_R_NOTFOUND;
13762 	} else {
13763 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13764 	}
13765 	if (result == ISC_R_SUCCESS) {
13766 		result = ISC_R_EXISTS;
13767 		goto cleanup;
13768 	} else if (result == DNS_R_PARTIALMATCH) {
13769 		/* Create our sub-zone anyway */
13770 		dns_zone_detach(&zone);
13771 		zone = NULL;
13772 	} else if (result != ISC_R_NOTFOUND) {
13773 		goto cleanup;
13774 	}
13775 
13776 	result = isc_task_beginexclusive(server->task);
13777 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
13778 
13779 #ifndef HAVE_LMDB
13780 	/*
13781 	 * Make sure we can open the configuration save file
13782 	 */
13783 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
13784 	if (result != ISC_R_SUCCESS) {
13785 		isc_task_endexclusive(server->task);
13786 		TCHECK(putstr(text, "unable to create '"));
13787 		TCHECK(putstr(text, view->new_zone_file));
13788 		TCHECK(putstr(text, "': "));
13789 		TCHECK(putstr(text, isc_result_totext(result)));
13790 		goto cleanup;
13791 	}
13792 
13793 	(void)isc_stdio_close(fp);
13794 	fp = NULL;
13795 #else  /* HAVE_LMDB */
13796 	LOCK(&view->new_zone_lock);
13797 	locked = true;
13798 	/* Make sure we can open the NZD database */
13799 	result = nzd_writable(view);
13800 	if (result != ISC_R_SUCCESS) {
13801 		isc_task_endexclusive(server->task);
13802 		TCHECK(putstr(text, "unable to open NZD database for '"));
13803 		TCHECK(putstr(text, view->new_zone_db));
13804 		TCHECK(putstr(text, "'"));
13805 		result = ISC_R_FAILURE;
13806 		goto cleanup;
13807 	}
13808 #endif /* HAVE_LMDB */
13809 
13810 	/* Mark view unfrozen and configure zone */
13811 	dns_view_thaw(view);
13812 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
13813 				server->mctx, view, &server->viewlist,
13814 				&server->kasplist, cfg->actx, true, false,
13815 				false);
13816 	dns_view_freeze(view);
13817 
13818 	isc_task_endexclusive(server->task);
13819 
13820 	if (result != ISC_R_SUCCESS) {
13821 		TCHECK(putstr(text, "configure_zone failed: "));
13822 		TCHECK(putstr(text, isc_result_totext(result)));
13823 		goto cleanup;
13824 	}
13825 
13826 	/* Is it there yet? */
13827 	if (redirect) {
13828 		if (view->redirect == NULL) {
13829 			CHECK(ISC_R_NOTFOUND);
13830 		}
13831 		dns_zone_attach(view->redirect, &zone);
13832 	} else {
13833 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13834 		if (result != ISC_R_SUCCESS) {
13835 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13836 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13837 				      "added new zone was not found: %s",
13838 				      isc_result_totext(result));
13839 			goto cleanup;
13840 		}
13841 	}
13842 
13843 #ifndef HAVE_LMDB
13844 	/*
13845 	 * If there wasn't a previous newzone config, just save the one
13846 	 * we've created. If there was a previous one, merge the new
13847 	 * zone into it.
13848 	 */
13849 	if (cfg->nzf_config == NULL) {
13850 		cfg_obj_attach(zoneconf, &cfg->nzf_config);
13851 	} else {
13852 		cfg_obj_t *z;
13853 		DE_CONST(zoneobj, z);
13854 		CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z,
13855 					"zone"));
13856 	}
13857 	cleanup_config = true;
13858 #endif /* HAVE_LMDB */
13859 
13860 	/*
13861 	 * Load the zone from the master file.  If this fails, we'll
13862 	 * need to undo the configuration we've done already.
13863 	 */
13864 	result = dns_zone_load(zone, true);
13865 	if (result != ISC_R_SUCCESS) {
13866 		dns_db_t *dbp = NULL;
13867 
13868 		TCHECK(putstr(text, "dns_zone_loadnew failed: "));
13869 		TCHECK(putstr(text, isc_result_totext(result)));
13870 
13871 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13872 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13873 			      "addzone failed; reverting.");
13874 
13875 		/* If the zone loaded partially, unload it */
13876 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13877 			dns_db_detach(&dbp);
13878 			dns_zone_unload(zone);
13879 		}
13880 
13881 		/* Remove the zone from the zone table */
13882 		dns_zt_unmount(view->zonetable, zone);
13883 		goto cleanup;
13884 	}
13885 
13886 	/* Flag the zone as having been added at runtime */
13887 	dns_zone_setadded(zone, true);
13888 
13889 #ifdef HAVE_LMDB
13890 	/* Save the new zone configuration into the NZD */
13891 	CHECK(nzd_open(view, 0, &txn, &dbi));
13892 	CHECK(nzd_save(&txn, dbi, zone, zoneobj));
13893 #else  /* ifdef HAVE_LMDB */
13894 	/* Append the zone configuration to the NZF */
13895 	result = nzf_append(view, zoneobj);
13896 #endif /* HAVE_LMDB */
13897 
13898 cleanup:
13899 
13900 #ifndef HAVE_LMDB
13901 	if (fp != NULL) {
13902 		(void)isc_stdio_close(fp);
13903 	}
13904 	if (result != ISC_R_SUCCESS && cleanup_config) {
13905 		tresult = delete_zoneconf(view, cfg->add_parser,
13906 					  cfg->nzf_config, name, NULL);
13907 		RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
13908 	}
13909 #else  /* HAVE_LMDB */
13910 	if (txn != NULL) {
13911 		(void)nzd_close(&txn, false);
13912 	}
13913 	if (locked) {
13914 		UNLOCK(&view->new_zone_lock);
13915 	}
13916 #endif /* HAVE_LMDB */
13917 
13918 	if (zone != NULL) {
13919 		dns_zone_detach(&zone);
13920 	}
13921 
13922 	return (result);
13923 }
13924 
13925 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)13926 do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13927 	   dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
13928 	   bool redirect, isc_buffer_t **text) {
13929 	isc_result_t result, tresult;
13930 	dns_zone_t *zone = NULL;
13931 	bool added;
13932 	bool exclusive = false;
13933 #ifndef HAVE_LMDB
13934 	FILE *fp = NULL;
13935 	cfg_obj_t *z;
13936 #else  /* HAVE_LMDB */
13937 	MDB_txn *txn = NULL;
13938 	MDB_dbi dbi;
13939 	bool locked = false;
13940 #endif /* HAVE_LMDB */
13941 
13942 	/* Zone must already exist */
13943 	if (redirect) {
13944 		if (view->redirect != NULL) {
13945 			dns_zone_attach(view->redirect, &zone);
13946 			result = ISC_R_SUCCESS;
13947 		} else {
13948 			result = ISC_R_NOTFOUND;
13949 		}
13950 	} else {
13951 		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13952 	}
13953 	if (result != ISC_R_SUCCESS) {
13954 		goto cleanup;
13955 	}
13956 
13957 	added = dns_zone_getadded(zone);
13958 	dns_zone_detach(&zone);
13959 
13960 #ifndef HAVE_LMDB
13961 	cfg = (ns_cfgctx_t *)view->new_zone_config;
13962 	if (cfg == NULL) {
13963 		TCHECK(putstr(text, "new zone config is not set"));
13964 		CHECK(ISC_R_FAILURE);
13965 	}
13966 #endif /* ifndef HAVE_LMDB */
13967 
13968 	result = isc_task_beginexclusive(server->task);
13969 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
13970 	exclusive = true;
13971 
13972 #ifndef HAVE_LMDB
13973 	/* Make sure we can open the configuration save file */
13974 	result = isc_stdio_open(view->new_zone_file, "a", &fp);
13975 	if (result != ISC_R_SUCCESS) {
13976 		TCHECK(putstr(text, "unable to open '"));
13977 		TCHECK(putstr(text, view->new_zone_file));
13978 		TCHECK(putstr(text, "': "));
13979 		TCHECK(putstr(text, isc_result_totext(result)));
13980 		goto cleanup;
13981 	}
13982 	(void)isc_stdio_close(fp);
13983 	fp = NULL;
13984 #else  /* HAVE_LMDB */
13985 	LOCK(&view->new_zone_lock);
13986 	locked = true;
13987 	/* Make sure we can open the NZD database */
13988 	result = nzd_writable(view);
13989 	if (result != ISC_R_SUCCESS) {
13990 		TCHECK(putstr(text, "unable to open NZD database for '"));
13991 		TCHECK(putstr(text, view->new_zone_db));
13992 		TCHECK(putstr(text, "'"));
13993 		result = ISC_R_FAILURE;
13994 		goto cleanup;
13995 	}
13996 #endif /* HAVE_LMDB */
13997 
13998 	/* Reconfigure the zone */
13999 	dns_view_thaw(view);
14000 	result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
14001 				server->mctx, view, &server->viewlist,
14002 				&server->kasplist, cfg->actx, true, false,
14003 				true);
14004 	dns_view_freeze(view);
14005 
14006 	exclusive = false;
14007 	isc_task_endexclusive(server->task);
14008 
14009 	if (result != ISC_R_SUCCESS) {
14010 		TCHECK(putstr(text, "configure_zone failed: "));
14011 		TCHECK(putstr(text, isc_result_totext(result)));
14012 		goto cleanup;
14013 	}
14014 
14015 	/* Is it there yet? */
14016 	if (redirect) {
14017 		if (view->redirect == NULL) {
14018 			CHECK(ISC_R_NOTFOUND);
14019 		}
14020 		dns_zone_attach(view->redirect, &zone);
14021 	} else {
14022 		CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
14023 	}
14024 
14025 #ifndef HAVE_LMDB
14026 	/* Remove old zone from configuration (and NZF file if applicable) */
14027 	if (added) {
14028 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
14029 					 dns_zone_getorigin(zone),
14030 					 nzf_writeconf);
14031 		if (result != ISC_R_SUCCESS) {
14032 			TCHECK(putstr(text, "former zone configuration "
14033 					    "not deleted: "));
14034 			TCHECK(putstr(text, isc_result_totext(result)));
14035 			goto cleanup;
14036 		}
14037 	}
14038 #endif /* HAVE_LMDB */
14039 
14040 	if (!added) {
14041 		if (cfg->vconfig == NULL) {
14042 			result = delete_zoneconf(
14043 				view, cfg->conf_parser, cfg->config,
14044 				dns_zone_getorigin(zone), NULL);
14045 		} else {
14046 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14047 								  "options");
14048 			result = delete_zoneconf(
14049 				view, cfg->conf_parser, voptions,
14050 				dns_zone_getorigin(zone), NULL);
14051 		}
14052 
14053 		if (result != ISC_R_SUCCESS) {
14054 			TCHECK(putstr(text, "former zone configuration "
14055 					    "not deleted: "));
14056 			TCHECK(putstr(text, isc_result_totext(result)));
14057 			goto cleanup;
14058 		}
14059 	}
14060 
14061 	/* Load the zone from the master file if it needs reloading. */
14062 	result = dns_zone_load(zone, true);
14063 
14064 	/*
14065 	 * Dynamic zones need no reloading, so we can pass this result.
14066 	 */
14067 	if (result == DNS_R_DYNAMIC) {
14068 		result = ISC_R_SUCCESS;
14069 	}
14070 
14071 	if (result != ISC_R_SUCCESS) {
14072 		dns_db_t *dbp = NULL;
14073 
14074 		TCHECK(putstr(text, "failed to load zone '"));
14075 		TCHECK(putstr(text, zname));
14076 		TCHECK(putstr(text, "': "));
14077 		TCHECK(putstr(text, isc_result_totext(result)));
14078 		TCHECK(putstr(text, "\nThe zone is no longer being served. "));
14079 		TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
14080 		TCHECK(putstr(text, "the problem and restore service."));
14081 
14082 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14083 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14084 			      "modzone failed; removing zone.");
14085 
14086 		/* If the zone loaded partially, unload it */
14087 		if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14088 			dns_db_detach(&dbp);
14089 			dns_zone_unload(zone);
14090 		}
14091 
14092 		/* Remove the zone from the zone table */
14093 		dns_zt_unmount(view->zonetable, zone);
14094 		goto cleanup;
14095 	}
14096 
14097 #ifndef HAVE_LMDB
14098 	/* Store the new zone configuration; also in NZF if applicable */
14099 	DE_CONST(zoneobj, z);
14100 	CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone"));
14101 #endif /* HAVE_LMDB */
14102 
14103 	if (added) {
14104 #ifdef HAVE_LMDB
14105 		CHECK(nzd_open(view, 0, &txn, &dbi));
14106 		CHECK(nzd_save(&txn, dbi, zone, zoneobj));
14107 #else  /* ifdef HAVE_LMDB */
14108 		result = nzf_append(view, zoneobj);
14109 		if (result != ISC_R_SUCCESS) {
14110 			TCHECK(putstr(text, "\nNew zone config not saved: "));
14111 			TCHECK(putstr(text, isc_result_totext(result)));
14112 			goto cleanup;
14113 		}
14114 #endif /* HAVE_LMDB */
14115 
14116 		TCHECK(putstr(text, "zone '"));
14117 		TCHECK(putstr(text, zname));
14118 		TCHECK(putstr(text, "' reconfigured."));
14119 	} else {
14120 		TCHECK(putstr(text, "zone '"));
14121 		TCHECK(putstr(text, zname));
14122 		TCHECK(putstr(text, "' must also be reconfigured in\n"));
14123 		TCHECK(putstr(text, "named.conf to make changes permanent."));
14124 	}
14125 
14126 cleanup:
14127 	if (exclusive) {
14128 		isc_task_endexclusive(server->task);
14129 	}
14130 
14131 #ifndef HAVE_LMDB
14132 	if (fp != NULL) {
14133 		(void)isc_stdio_close(fp);
14134 	}
14135 #else  /* HAVE_LMDB */
14136 	if (txn != NULL) {
14137 		(void)nzd_close(&txn, false);
14138 	}
14139 	if (locked) {
14140 		UNLOCK(&view->new_zone_lock);
14141 	}
14142 #endif /* HAVE_LMDB */
14143 
14144 	if (zone != NULL) {
14145 		dns_zone_detach(&zone);
14146 	}
14147 
14148 	return (result);
14149 }
14150 
14151 /*
14152  * Act on an "addzone" or "modzone" command from the command channel.
14153  */
14154 isc_result_t
named_server_changezone(named_server_t * server,char * command,isc_buffer_t ** text)14155 named_server_changezone(named_server_t *server, char *command,
14156 			isc_buffer_t **text) {
14157 	isc_result_t result;
14158 	bool addzone;
14159 	bool redirect = false;
14160 	ns_cfgctx_t *cfg = NULL;
14161 	cfg_obj_t *zoneconf = NULL;
14162 	const cfg_obj_t *zoneobj = NULL;
14163 	const char *zonename;
14164 	dns_view_t *view = NULL;
14165 	isc_buffer_t buf;
14166 	dns_fixedname_t fname;
14167 	dns_name_t *dnsname;
14168 
14169 	REQUIRE(text != NULL);
14170 
14171 	if (strncasecmp(command, "add", 3) == 0) {
14172 		addzone = true;
14173 	} else {
14174 		INSIST(strncasecmp(command, "mod", 3) == 0);
14175 		addzone = false;
14176 	}
14177 
14178 	CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj,
14179 			    &redirect, text));
14180 
14181 	/* Are we accepting new zones in this view? */
14182 #ifdef HAVE_LMDB
14183 	if (view->new_zone_db == NULL)
14184 #else  /* ifdef HAVE_LMDB */
14185 	if (view->new_zone_file == NULL)
14186 #endif /* HAVE_LMDB */
14187 	{
14188 		(void)putstr(text, "Not allowing new zones in view '");
14189 		(void)putstr(text, view->name);
14190 		(void)putstr(text, "'");
14191 		result = ISC_R_NOPERM;
14192 		goto cleanup;
14193 	}
14194 
14195 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14196 	if (cfg == NULL) {
14197 		result = ISC_R_FAILURE;
14198 		goto cleanup;
14199 	}
14200 
14201 	zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
14202 	isc_buffer_constinit(&buf, zonename, strlen(zonename));
14203 	isc_buffer_add(&buf, strlen(zonename));
14204 
14205 	dnsname = dns_fixedname_initname(&fname);
14206 	CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL));
14207 
14208 	if (redirect) {
14209 		if (!dns_name_equal(dnsname, dns_rootname)) {
14210 			(void)putstr(text, "redirect zones must be called "
14211 					   "\".\"");
14212 			CHECK(ISC_R_FAILURE);
14213 		}
14214 	}
14215 
14216 	if (addzone) {
14217 		CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj,
14218 				 redirect, text));
14219 	} else {
14220 		CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj,
14221 				 redirect, text));
14222 	}
14223 
14224 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14225 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14226 		      "%s zone %s in view %s via %s",
14227 		      addzone ? "added" : "updated", zonename, view->name,
14228 		      addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
14229 
14230 	/* Changing a zone counts as reconfiguration */
14231 	CHECK(isc_time_now(&named_g_configtime));
14232 
14233 cleanup:
14234 	if (isc_buffer_usedlength(*text) > 0) {
14235 		(void)putnull(text);
14236 	}
14237 	if (zoneconf != NULL) {
14238 		cfg_obj_destroy(named_g_addparser, &zoneconf);
14239 	}
14240 	if (view != NULL) {
14241 		dns_view_detach(&view);
14242 	}
14243 
14244 	return (result);
14245 }
14246 
14247 static bool
inuse(const char * file,bool first,isc_buffer_t ** text)14248 inuse(const char *file, bool first, isc_buffer_t **text) {
14249 	if (file != NULL && isc_file_exists(file)) {
14250 		if (first) {
14251 			(void)putstr(text, "The following files were in use "
14252 					   "and may now be removed:\n");
14253 		} else {
14254 			(void)putstr(text, "\n");
14255 		}
14256 		(void)putstr(text, file);
14257 		(void)putnull(text);
14258 		return (false);
14259 	}
14260 	return (first);
14261 }
14262 
14263 typedef struct {
14264 	dns_zone_t *zone;
14265 	bool cleanup;
14266 } ns_dzctx_t;
14267 
14268 /*
14269  * Carry out a zone deletion scheduled by named_server_delzone().
14270  */
14271 static void
rmzone(isc_task_t * task,isc_event_t * event)14272 rmzone(isc_task_t *task, isc_event_t *event) {
14273 	ns_dzctx_t *dz = (ns_dzctx_t *)event->ev_arg;
14274 	dns_zone_t *zone, *raw = NULL, *mayberaw;
14275 	char zonename[DNS_NAME_FORMATSIZE];
14276 	dns_view_t *view;
14277 	ns_cfgctx_t *cfg;
14278 	dns_db_t *dbp = NULL;
14279 	bool added;
14280 	isc_result_t result;
14281 #ifdef HAVE_LMDB
14282 	MDB_txn *txn = NULL;
14283 	MDB_dbi dbi;
14284 #endif /* ifdef HAVE_LMDB */
14285 
14286 	REQUIRE(dz != NULL);
14287 
14288 	isc_event_free(&event);
14289 
14290 	/* Dig out configuration for this zone */
14291 	zone = dz->zone;
14292 	view = dns_zone_getview(zone);
14293 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14294 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
14295 
14296 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14297 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14298 		      "deleting zone %s in view %s via delzone", zonename,
14299 		      view->name);
14300 
14301 	/* Remove the zone from configuration (and NZF file if applicable) */
14302 	added = dns_zone_getadded(zone);
14303 
14304 	if (added && cfg != NULL) {
14305 #ifdef HAVE_LMDB
14306 		/* Make sure we can open the NZD database */
14307 		LOCK(&view->new_zone_lock);
14308 		result = nzd_open(view, 0, &txn, &dbi);
14309 		if (result != ISC_R_SUCCESS) {
14310 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14311 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14312 				      "unable to open NZD database for '%s'",
14313 				      view->new_zone_db);
14314 		} else {
14315 			result = nzd_save(&txn, dbi, zone, NULL);
14316 		}
14317 
14318 		if (result != ISC_R_SUCCESS) {
14319 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14320 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14321 				      "unable to "
14322 				      "delete zone configuration: %s",
14323 				      isc_result_totext(result));
14324 		}
14325 
14326 		if (txn != NULL) {
14327 			(void)nzd_close(&txn, false);
14328 		}
14329 		UNLOCK(&view->new_zone_lock);
14330 #else  /* ifdef HAVE_LMDB */
14331 		result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
14332 					 dns_zone_getorigin(zone),
14333 					 nzf_writeconf);
14334 		if (result != ISC_R_SUCCESS) {
14335 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14336 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14337 				      "unable to "
14338 				      "delete zone configuration: %s",
14339 				      isc_result_totext(result));
14340 		}
14341 #endif /* HAVE_LMDB */
14342 	}
14343 
14344 	if (!added && cfg != NULL) {
14345 		if (cfg->vconfig != NULL) {
14346 			const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14347 								  "options");
14348 			result = delete_zoneconf(
14349 				view, cfg->conf_parser, voptions,
14350 				dns_zone_getorigin(zone), NULL);
14351 		} else {
14352 			result = delete_zoneconf(
14353 				view, cfg->conf_parser, cfg->config,
14354 				dns_zone_getorigin(zone), NULL);
14355 		}
14356 		if (result != ISC_R_SUCCESS) {
14357 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14358 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14359 				      "unable to "
14360 				      "delete zone configuration: %s",
14361 				      isc_result_totext(result));
14362 		}
14363 	}
14364 
14365 	/* Unload zone database */
14366 	if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14367 		dns_db_detach(&dbp);
14368 		dns_zone_unload(zone);
14369 	}
14370 
14371 	/* Clean up stub/slave zone files if requested to do so */
14372 	dns_zone_getraw(zone, &raw);
14373 	mayberaw = (raw != NULL) ? raw : zone;
14374 
14375 	if (added && dz->cleanup) {
14376 		const char *file;
14377 
14378 		file = dns_zone_getfile(mayberaw);
14379 		result = isc_file_remove(file);
14380 		if (result != ISC_R_SUCCESS) {
14381 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14382 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14383 				      "file %s not removed: %s", file,
14384 				      isc_result_totext(result));
14385 		}
14386 
14387 		file = dns_zone_getjournal(mayberaw);
14388 		result = isc_file_remove(file);
14389 		if (result != ISC_R_SUCCESS) {
14390 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14391 				      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14392 				      "file %s not removed: %s", file,
14393 				      isc_result_totext(result));
14394 		}
14395 
14396 		if (zone != mayberaw) {
14397 			file = dns_zone_getfile(zone);
14398 			result = isc_file_remove(file);
14399 			if (result != ISC_R_SUCCESS) {
14400 				isc_log_write(
14401 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14402 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14403 					"file %s not removed: %s", file,
14404 					isc_result_totext(result));
14405 			}
14406 
14407 			file = dns_zone_getjournal(zone);
14408 			result = isc_file_remove(file);
14409 			if (result != ISC_R_SUCCESS) {
14410 				isc_log_write(
14411 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14412 					NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14413 					"file %s not removed: %s", file,
14414 					isc_result_totext(result));
14415 			}
14416 		}
14417 	}
14418 
14419 	if (raw != NULL) {
14420 		dns_zone_detach(&raw);
14421 	}
14422 	dns_zone_detach(&zone);
14423 	isc_mem_put(named_g_mctx, dz, sizeof(*dz));
14424 	isc_task_detach(&task);
14425 }
14426 
14427 /*
14428  * Act on a "delzone" command from the command channel.
14429  */
14430 isc_result_t
named_server_delzone(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14431 named_server_delzone(named_server_t *server, isc_lex_t *lex,
14432 		     isc_buffer_t **text) {
14433 	isc_result_t result, tresult;
14434 	dns_zone_t *zone = NULL;
14435 	dns_zone_t *raw = NULL;
14436 	dns_zone_t *mayberaw;
14437 	dns_view_t *view = NULL;
14438 	char zonename[DNS_NAME_FORMATSIZE];
14439 	bool cleanup = false;
14440 	const char *ptr;
14441 	bool added;
14442 	ns_dzctx_t *dz = NULL;
14443 	isc_event_t *dzevent = NULL;
14444 	isc_task_t *task = NULL;
14445 
14446 	REQUIRE(text != NULL);
14447 
14448 	/* Skip the command name. */
14449 	ptr = next_token(lex, text);
14450 	if (ptr == NULL) {
14451 		return (ISC_R_UNEXPECTEDEND);
14452 	}
14453 
14454 	/* Find out what we are to do. */
14455 	ptr = next_token(lex, text);
14456 	if (ptr == NULL) {
14457 		return (ISC_R_UNEXPECTEDEND);
14458 	}
14459 
14460 	if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) {
14461 		cleanup = true;
14462 		ptr = next_token(lex, text);
14463 	}
14464 
14465 	CHECK(zone_from_args(server, lex, ptr, &zone, zonename, text, false));
14466 	if (zone == NULL) {
14467 		result = ISC_R_UNEXPECTEDEND;
14468 		goto cleanup;
14469 	}
14470 
14471 	INSIST(zonename != NULL);
14472 
14473 	/* Is this a policy zone? */
14474 	if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
14475 		TCHECK(putstr(text, "zone '"));
14476 		TCHECK(putstr(text, zonename));
14477 		TCHECK(putstr(text, "' cannot be deleted: response-policy "
14478 				    "zone."));
14479 		result = ISC_R_FAILURE;
14480 		goto cleanup;
14481 	}
14482 
14483 	view = dns_zone_getview(zone);
14484 	if (dns_zone_gettype(zone) == dns_zone_redirect) {
14485 		dns_zone_detach(&view->redirect);
14486 	} else {
14487 		CHECK(dns_zt_unmount(view->zonetable, zone));
14488 	}
14489 
14490 	/* Send cleanup event */
14491 	dz = isc_mem_get(named_g_mctx, sizeof(*dz));
14492 
14493 	dz->cleanup = cleanup;
14494 	dz->zone = NULL;
14495 	dns_zone_attach(zone, &dz->zone);
14496 	dzevent = isc_event_allocate(named_g_mctx, server, NAMED_EVENT_DELZONE,
14497 				     rmzone, dz, sizeof(isc_event_t));
14498 
14499 	dns_zone_gettask(zone, &task);
14500 	isc_task_send(task, &dzevent);
14501 	dz = NULL;
14502 
14503 	/* Inform user about cleaning up stub/slave zone files */
14504 	dns_zone_getraw(zone, &raw);
14505 	mayberaw = (raw != NULL) ? raw : zone;
14506 
14507 	added = dns_zone_getadded(zone);
14508 	if (!added) {
14509 		TCHECK(putstr(text, "zone '"));
14510 		TCHECK(putstr(text, zonename));
14511 		TCHECK(putstr(text, "' is no longer active and will be "
14512 				    "deleted.\n"));
14513 		TCHECK(putstr(text, "To keep it from returning "));
14514 		TCHECK(putstr(text, "when the server is restarted, it\n"));
14515 		TCHECK(putstr(text, "must also be removed from named.conf."));
14516 	} else if (cleanup) {
14517 		TCHECK(putstr(text, "zone '"));
14518 		TCHECK(putstr(text, zonename));
14519 		TCHECK(putstr(text, "' and associated files will be deleted."));
14520 	} else if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
14521 		   dns_zone_gettype(mayberaw) == dns_zone_mirror ||
14522 		   dns_zone_gettype(mayberaw) == dns_zone_stub)
14523 	{
14524 		bool first;
14525 		const char *file;
14526 
14527 		TCHECK(putstr(text, "zone '"));
14528 		TCHECK(putstr(text, zonename));
14529 		TCHECK(putstr(text, "' will be deleted."));
14530 
14531 		file = dns_zone_getfile(mayberaw);
14532 		first = inuse(file, true, text);
14533 
14534 		file = dns_zone_getjournal(mayberaw);
14535 		first = inuse(file, first, text);
14536 
14537 		if (zone != mayberaw) {
14538 			file = dns_zone_getfile(zone);
14539 			first = inuse(file, first, text);
14540 
14541 			file = dns_zone_getjournal(zone);
14542 			(void)inuse(file, first, text);
14543 		}
14544 	}
14545 
14546 	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14547 		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14548 		      "zone %s scheduled for removal via delzone", zonename);
14549 
14550 	/* Removing a zone counts as reconfiguration */
14551 	CHECK(isc_time_now(&named_g_configtime));
14552 
14553 	result = ISC_R_SUCCESS;
14554 
14555 cleanup:
14556 	if (isc_buffer_usedlength(*text) > 0) {
14557 		(void)putnull(text);
14558 	}
14559 	if (raw != NULL) {
14560 		dns_zone_detach(&raw);
14561 	}
14562 	if (zone != NULL) {
14563 		dns_zone_detach(&zone);
14564 	}
14565 
14566 	return (result);
14567 }
14568 
14569 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)14570 find_name_in_list_from_map(const cfg_obj_t *config,
14571 			   const char *map_key_for_list, const char *name,
14572 			   bool redirect) {
14573 	const cfg_obj_t *list = NULL;
14574 	const cfg_listelt_t *element;
14575 	const cfg_obj_t *obj = NULL;
14576 	dns_fixedname_t fixed1, fixed2;
14577 	dns_name_t *name1 = NULL, *name2 = NULL;
14578 	isc_result_t result;
14579 
14580 	if (strcmp(map_key_for_list, "zone") == 0) {
14581 		name1 = dns_fixedname_initname(&fixed1);
14582 		name2 = dns_fixedname_initname(&fixed2);
14583 		result = dns_name_fromstring(name1, name, 0, NULL);
14584 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
14585 	}
14586 
14587 	cfg_map_get(config, map_key_for_list, &list);
14588 	for (element = cfg_list_first(list); element != NULL;
14589 	     element = cfg_list_next(element))
14590 	{
14591 		const char *vname;
14592 
14593 		obj = cfg_listelt_value(element);
14594 		INSIST(obj != NULL);
14595 		vname = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
14596 		if (vname == NULL) {
14597 			obj = NULL;
14598 			continue;
14599 		}
14600 
14601 		if (name1 != NULL) {
14602 			result = dns_name_fromstring(name2, vname, 0, NULL);
14603 			if (result == ISC_R_SUCCESS &&
14604 			    dns_name_equal(name1, name2)) {
14605 				const cfg_obj_t *zoptions;
14606 				const cfg_obj_t *typeobj = NULL;
14607 				zoptions = cfg_tuple_get(obj, "options");
14608 
14609 				if (zoptions != NULL) {
14610 					cfg_map_get(zoptions, "type", &typeobj);
14611 				}
14612 				if (redirect && typeobj != NULL &&
14613 				    strcasecmp(cfg_obj_asstring(typeobj),
14614 					       "redirect") == 0)
14615 				{
14616 					break;
14617 				} else if (!redirect) {
14618 					break;
14619 				}
14620 			}
14621 		} else if (strcasecmp(vname, name) == 0) {
14622 			break;
14623 		}
14624 
14625 		obj = NULL;
14626 	}
14627 
14628 	return (obj);
14629 }
14630 
14631 static void
emitzone(void * arg,const char * buf,int len)14632 emitzone(void *arg, const char *buf, int len) {
14633 	ns_dzarg_t *dzarg = arg;
14634 	isc_result_t result;
14635 
14636 	REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
14637 	result = putmem(dzarg->text, buf, len);
14638 	if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
14639 		dzarg->result = result;
14640 	}
14641 }
14642 
14643 /*
14644  * Act on a "showzone" command from the command channel.
14645  */
14646 isc_result_t
named_server_showzone(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14647 named_server_showzone(named_server_t *server, isc_lex_t *lex,
14648 		      isc_buffer_t **text) {
14649 	isc_result_t result;
14650 	const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
14651 	char zonename[DNS_NAME_FORMATSIZE];
14652 	const cfg_obj_t *map;
14653 	dns_view_t *view = NULL;
14654 	dns_zone_t *zone = NULL;
14655 	ns_cfgctx_t *cfg = NULL;
14656 #ifdef HAVE_LMDB
14657 	cfg_obj_t *nzconfig = NULL;
14658 #endif /* HAVE_LMDB */
14659 	bool added, redirect;
14660 	ns_dzarg_t dzarg;
14661 
14662 	REQUIRE(text != NULL);
14663 
14664 	/* Parse parameters */
14665 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
14666 	if (zone == NULL) {
14667 		result = ISC_R_UNEXPECTEDEND;
14668 		goto cleanup;
14669 	}
14670 
14671 	redirect = dns_zone_gettype(zone) == dns_zone_redirect;
14672 	added = dns_zone_getadded(zone);
14673 	view = dns_zone_getview(zone);
14674 	dns_zone_detach(&zone);
14675 
14676 	cfg = (ns_cfgctx_t *)view->new_zone_config;
14677 	if (cfg == NULL) {
14678 		result = ISC_R_FAILURE;
14679 		goto cleanup;
14680 	}
14681 
14682 	if (!added) {
14683 		/* Find the view statement */
14684 		vconfig = find_name_in_list_from_map(cfg->config, "view",
14685 						     view->name, false);
14686 
14687 		/* Find the zone statement */
14688 		if (vconfig != NULL) {
14689 			map = cfg_tuple_get(vconfig, "options");
14690 		} else {
14691 			map = cfg->config;
14692 		}
14693 
14694 		zconfig = find_name_in_list_from_map(map, "zone", zonename,
14695 						     redirect);
14696 	}
14697 
14698 #ifndef HAVE_LMDB
14699 	if (zconfig == NULL && cfg->nzf_config != NULL) {
14700 		zconfig = find_name_in_list_from_map(cfg->nzf_config, "zone",
14701 						     zonename, redirect);
14702 	}
14703 #else  /* HAVE_LMDB */
14704 	if (zconfig == NULL) {
14705 		const cfg_obj_t *zlist = NULL;
14706 		CHECK(get_newzone_config(view, zonename, &nzconfig));
14707 		CHECK(cfg_map_get(nzconfig, "zone", &zlist));
14708 		if (!cfg_obj_islist(zlist)) {
14709 			CHECK(ISC_R_FAILURE);
14710 		}
14711 
14712 		zconfig = cfg_listelt_value(cfg_list_first(zlist));
14713 	}
14714 #endif /* HAVE_LMDB */
14715 
14716 	if (zconfig == NULL) {
14717 		CHECK(ISC_R_NOTFOUND);
14718 	}
14719 
14720 	CHECK(putstr(text, "zone "));
14721 	dzarg.magic = DZARG_MAGIC;
14722 	dzarg.text = text;
14723 	dzarg.result = ISC_R_SUCCESS;
14724 	cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
14725 	CHECK(dzarg.result);
14726 
14727 	CHECK(putstr(text, ";"));
14728 
14729 	result = ISC_R_SUCCESS;
14730 
14731 cleanup:
14732 #ifdef HAVE_LMDB
14733 	if (nzconfig != NULL) {
14734 		cfg_obj_destroy(named_g_addparser, &nzconfig);
14735 	}
14736 #endif /* HAVE_LMDB */
14737 	if (isc_buffer_usedlength(*text) > 0) {
14738 		(void)putnull(text);
14739 	}
14740 
14741 	return (result);
14742 }
14743 
14744 static void
newzone_cfgctx_destroy(void ** cfgp)14745 newzone_cfgctx_destroy(void **cfgp) {
14746 	ns_cfgctx_t *cfg;
14747 
14748 	REQUIRE(cfgp != NULL && *cfgp != NULL);
14749 
14750 	cfg = *cfgp;
14751 
14752 	if (cfg->conf_parser != NULL) {
14753 		if (cfg->config != NULL) {
14754 			cfg_obj_destroy(cfg->conf_parser, &cfg->config);
14755 		}
14756 		if (cfg->vconfig != NULL) {
14757 			cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
14758 		}
14759 		cfg_parser_destroy(&cfg->conf_parser);
14760 	}
14761 	if (cfg->add_parser != NULL) {
14762 		if (cfg->nzf_config != NULL) {
14763 			cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
14764 		}
14765 		cfg_parser_destroy(&cfg->add_parser);
14766 	}
14767 
14768 	if (cfg->actx != NULL) {
14769 		cfg_aclconfctx_detach(&cfg->actx);
14770 	}
14771 
14772 	isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
14773 	*cfgp = NULL;
14774 }
14775 
14776 isc_result_t
named_server_signing(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14777 named_server_signing(named_server_t *server, isc_lex_t *lex,
14778 		     isc_buffer_t **text) {
14779 	isc_result_t result = ISC_R_SUCCESS;
14780 	dns_zone_t *zone = NULL;
14781 	dns_name_t *origin;
14782 	dns_db_t *db = NULL;
14783 	dns_dbnode_t *node = NULL;
14784 	dns_dbversion_t *version = NULL;
14785 	dns_rdatatype_t privatetype;
14786 	dns_rdataset_t privset;
14787 	bool first = true;
14788 	bool list = false, clear = false;
14789 	bool chain = false;
14790 	bool setserial = false;
14791 	bool resalt = false;
14792 	uint32_t serial = 0;
14793 	char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
14794 	unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
14795 	unsigned char salt[255];
14796 	const char *ptr;
14797 	size_t n;
14798 
14799 	REQUIRE(text != NULL);
14800 
14801 	dns_rdataset_init(&privset);
14802 
14803 	/* Skip the command name. */
14804 	ptr = next_token(lex, text);
14805 	if (ptr == NULL) {
14806 		return (ISC_R_UNEXPECTEDEND);
14807 	}
14808 
14809 	/* Find out what we are to do. */
14810 	ptr = next_token(lex, text);
14811 	if (ptr == NULL) {
14812 		return (ISC_R_UNEXPECTEDEND);
14813 	}
14814 
14815 	if (strcasecmp(ptr, "-list") == 0) {
14816 		list = true;
14817 	} else if ((strcasecmp(ptr, "-clear") == 0) ||
14818 		   (strcasecmp(ptr, "-clean") == 0)) {
14819 		clear = true;
14820 		ptr = next_token(lex, text);
14821 		if (ptr == NULL) {
14822 			return (ISC_R_UNEXPECTEDEND);
14823 		}
14824 		strlcpy(keystr, ptr, sizeof(keystr));
14825 	} else if (strcasecmp(ptr, "-nsec3param") == 0) {
14826 		char hashbuf[64], flagbuf[64], iterbuf[64];
14827 		char nbuf[256];
14828 
14829 		chain = true;
14830 		ptr = next_token(lex, text);
14831 		if (ptr == NULL) {
14832 			return (ISC_R_UNEXPECTEDEND);
14833 		}
14834 
14835 		if (strcasecmp(ptr, "none") == 0) {
14836 			hash = 0;
14837 		} else {
14838 			strlcpy(hashbuf, ptr, sizeof(hashbuf));
14839 
14840 			ptr = next_token(lex, text);
14841 			if (ptr == NULL) {
14842 				return (ISC_R_UNEXPECTEDEND);
14843 			}
14844 			strlcpy(flagbuf, ptr, sizeof(flagbuf));
14845 
14846 			ptr = next_token(lex, text);
14847 			if (ptr == NULL) {
14848 				return (ISC_R_UNEXPECTEDEND);
14849 			}
14850 			strlcpy(iterbuf, ptr, sizeof(iterbuf));
14851 			n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", hashbuf,
14852 				     flagbuf, iterbuf);
14853 			if (n == sizeof(nbuf)) {
14854 				return (ISC_R_NOSPACE);
14855 			}
14856 			n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
14857 			if (n != 3U) {
14858 				return (ISC_R_BADNUMBER);
14859 			}
14860 
14861 			if (hash > 0xffU || flags > 0xffU ||
14862 			    iter > dns_nsec3_maxiterations()) {
14863 				return (ISC_R_RANGE);
14864 			}
14865 
14866 			ptr = next_token(lex, text);
14867 			if (ptr == NULL) {
14868 				return (ISC_R_UNEXPECTEDEND);
14869 			} else if (strcasecmp(ptr, "auto") == 0) {
14870 				/* Auto-generate a random salt.
14871 				 * XXXMUKS: This currently uses the
14872 				 * minimum recommended length by RFC
14873 				 * 5155 (64 bits). It should be made
14874 				 * configurable.
14875 				 */
14876 				saltlen = 8;
14877 				resalt = true;
14878 			} else if (strcmp(ptr, "-") != 0) {
14879 				isc_buffer_t buf;
14880 
14881 				isc_buffer_init(&buf, salt, sizeof(salt));
14882 				CHECK(isc_hex_decodestring(ptr, &buf));
14883 				saltlen = isc_buffer_usedlength(&buf);
14884 			}
14885 		}
14886 	} else if (strcasecmp(ptr, "-serial") == 0) {
14887 		ptr = next_token(lex, text);
14888 		if (ptr == NULL) {
14889 			return (ISC_R_UNEXPECTEDEND);
14890 		}
14891 		CHECK(isc_parse_uint32(&serial, ptr, 10));
14892 		setserial = true;
14893 	} else {
14894 		CHECK(DNS_R_SYNTAX);
14895 	}
14896 
14897 	CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
14898 	if (zone == NULL) {
14899 		CHECK(ISC_R_UNEXPECTEDEND);
14900 	}
14901 
14902 	if (dns_zone_getkasp(zone) != NULL) {
14903 		(void)putstr(text, "zone uses dnssec-policy, use rndc dnssec "
14904 				   "command instead");
14905 		(void)putnull(text);
14906 		goto cleanup;
14907 	}
14908 
14909 	if (clear) {
14910 		CHECK(dns_zone_keydone(zone, keystr));
14911 		(void)putstr(text, "request queued");
14912 		(void)putnull(text);
14913 	} else if (chain) {
14914 		CHECK(dns_zone_setnsec3param(
14915 			zone, (uint8_t)hash, (uint8_t)flags, iter,
14916 			(uint8_t)saltlen, salt, true, resalt));
14917 		(void)putstr(text, "nsec3param request queued");
14918 		(void)putnull(text);
14919 	} else if (setserial) {
14920 		CHECK(dns_zone_setserial(zone, serial));
14921 		(void)putstr(text, "serial request queued");
14922 		(void)putnull(text);
14923 	} else if (list) {
14924 		privatetype = dns_zone_getprivatetype(zone);
14925 		origin = dns_zone_getorigin(zone);
14926 		CHECK(dns_zone_getdb(zone, &db));
14927 		CHECK(dns_db_findnode(db, origin, false, &node));
14928 		dns_db_currentversion(db, &version);
14929 
14930 		result = dns_db_findrdataset(db, node, version, privatetype,
14931 					     dns_rdatatype_none, 0, &privset,
14932 					     NULL);
14933 		if (result == ISC_R_NOTFOUND) {
14934 			(void)putstr(text, "No signing records found");
14935 			(void)putnull(text);
14936 			result = ISC_R_SUCCESS;
14937 			goto cleanup;
14938 		}
14939 
14940 		for (result = dns_rdataset_first(&privset);
14941 		     result == ISC_R_SUCCESS;
14942 		     result = dns_rdataset_next(&privset))
14943 		{
14944 			dns_rdata_t priv = DNS_RDATA_INIT;
14945 			char output[BUFSIZ];
14946 			isc_buffer_t buf;
14947 
14948 			dns_rdataset_current(&privset, &priv);
14949 
14950 			isc_buffer_init(&buf, output, sizeof(output));
14951 			CHECK(dns_private_totext(&priv, &buf));
14952 			if (!first) {
14953 				CHECK(putstr(text, "\n"));
14954 			}
14955 			CHECK(putstr(text, output));
14956 			first = false;
14957 		}
14958 		if (!first) {
14959 			CHECK(putnull(text));
14960 		}
14961 
14962 		if (result == ISC_R_NOMORE) {
14963 			result = ISC_R_SUCCESS;
14964 		}
14965 	}
14966 
14967 cleanup:
14968 	if (dns_rdataset_isassociated(&privset)) {
14969 		dns_rdataset_disassociate(&privset);
14970 	}
14971 	if (node != NULL) {
14972 		dns_db_detachnode(db, &node);
14973 	}
14974 	if (version != NULL) {
14975 		dns_db_closeversion(db, &version, false);
14976 	}
14977 	if (db != NULL) {
14978 		dns_db_detach(&db);
14979 	}
14980 	if (zone != NULL) {
14981 		dns_zone_detach(&zone);
14982 	}
14983 
14984 	return (result);
14985 }
14986 
14987 static inline bool
argcheck(char * cmd,const char * full)14988 argcheck(char *cmd, const char *full) {
14989 	size_t l;
14990 
14991 	if (cmd == NULL || cmd[0] != '-') {
14992 		return (false);
14993 	}
14994 
14995 	cmd++;
14996 	l = strlen(cmd);
14997 	if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
14998 		return (false);
14999 	}
15000 
15001 	return (true);
15002 }
15003 
15004 isc_result_t
named_server_dnssec(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)15005 named_server_dnssec(named_server_t *server, isc_lex_t *lex,
15006 		    isc_buffer_t **text) {
15007 	isc_result_t result = ISC_R_SUCCESS;
15008 	dns_zone_t *zone = NULL;
15009 	dns_kasp_t *kasp = NULL;
15010 	dns_dnsseckeylist_t keys;
15011 	dns_dnsseckey_t *key;
15012 	char *ptr, *zonetext = NULL;
15013 	const char *msg = NULL;
15014 	/* variables for -checkds */
15015 	bool checkds = false, dspublish = false;
15016 	/* variables for -rollover */
15017 	bool rollover = false;
15018 	/* variables for -key */
15019 	bool use_keyid = false;
15020 	dns_keytag_t keyid = 0;
15021 	uint8_t algorithm = 0;
15022 	/* variables for -status */
15023 	bool status = false;
15024 	char output[4096];
15025 	isc_stdtime_t now, when;
15026 	isc_time_t timenow, timewhen;
15027 	const char *dir;
15028 	dns_db_t *db = NULL;
15029 	dns_dbversion_t *version = NULL;
15030 
15031 	REQUIRE(text != NULL);
15032 
15033 	/* Skip the command name. */
15034 	ptr = next_token(lex, text);
15035 	if (ptr == NULL) {
15036 		return (ISC_R_UNEXPECTEDEND);
15037 	}
15038 
15039 	/* Find out what we are to do. */
15040 	ptr = next_token(lex, text);
15041 	if (ptr == NULL) {
15042 		return (ISC_R_UNEXPECTEDEND);
15043 	}
15044 
15045 	/* Initialize current time and key list. */
15046 	TIME_NOW(&timenow);
15047 	now = isc_time_seconds(&timenow);
15048 	when = now;
15049 
15050 	ISC_LIST_INIT(keys);
15051 
15052 	if (strcasecmp(ptr, "-status") == 0) {
15053 		status = true;
15054 	} else if (strcasecmp(ptr, "-rollover") == 0) {
15055 		rollover = true;
15056 	} else if (strcasecmp(ptr, "-checkds") == 0) {
15057 		checkds = true;
15058 	} else {
15059 		CHECK(DNS_R_SYNTAX);
15060 	}
15061 
15062 	if (rollover || checkds) {
15063 		/* Check for options */
15064 		for (;;) {
15065 			ptr = next_token(lex, text);
15066 			if (ptr == NULL) {
15067 				msg = "Bad format";
15068 				CHECK(ISC_R_UNEXPECTEDEND);
15069 			} else if (argcheck(ptr, "alg")) {
15070 				isc_consttextregion_t alg;
15071 				ptr = next_token(lex, text);
15072 				if (ptr == NULL) {
15073 					msg = "No key algorithm specified";
15074 					CHECK(ISC_R_UNEXPECTEDEND);
15075 				}
15076 				alg.base = ptr;
15077 				alg.length = strlen(alg.base);
15078 				result = dns_secalg_fromtext(
15079 					&algorithm, (isc_textregion_t *)&alg);
15080 				if (result != ISC_R_SUCCESS) {
15081 					msg = "Bad algorithm";
15082 					CHECK(DNS_R_SYNTAX);
15083 				}
15084 				continue;
15085 			} else if (argcheck(ptr, "key")) {
15086 				uint16_t id;
15087 				ptr = next_token(lex, text);
15088 				if (ptr == NULL) {
15089 					msg = "No key identifier specified";
15090 					CHECK(ISC_R_UNEXPECTEDEND);
15091 				}
15092 				CHECK(isc_parse_uint16(&id, ptr, 10));
15093 				keyid = (dns_keytag_t)id;
15094 				use_keyid = true;
15095 				continue;
15096 			} else if (argcheck(ptr, "when")) {
15097 				uint32_t tw;
15098 				ptr = next_token(lex, text);
15099 				if (ptr == NULL) {
15100 					msg = "No time specified";
15101 					CHECK(ISC_R_UNEXPECTEDEND);
15102 				}
15103 				CHECK(dns_time32_fromtext(ptr, &tw));
15104 				when = (isc_stdtime_t)tw;
15105 				continue;
15106 			} else if (ptr[0] == '-') {
15107 				msg = "Unknown option";
15108 				CHECK(DNS_R_SYNTAX);
15109 			} else if (checkds) {
15110 				/*
15111 				 * No arguments provided, so we must be
15112 				 * parsing "published|withdrawn".
15113 				 */
15114 				if (strcasecmp(ptr, "published") == 0) {
15115 					dspublish = true;
15116 				} else if (strcasecmp(ptr, "withdrawn") != 0) {
15117 					CHECK(DNS_R_SYNTAX);
15118 				}
15119 			} else if (rollover) {
15120 				/*
15121 				 * No arguments provided, so we must be
15122 				 * parsing the zone.
15123 				 */
15124 				zonetext = ptr;
15125 			}
15126 			break;
15127 		}
15128 
15129 		if (rollover && !use_keyid) {
15130 			msg = "Key id is required when scheduling rollover";
15131 			CHECK(DNS_R_SYNTAX);
15132 		}
15133 
15134 		if (algorithm > 0 && !use_keyid) {
15135 			msg = "Key id is required when setting algorithm";
15136 			CHECK(DNS_R_SYNTAX);
15137 		}
15138 	}
15139 
15140 	/* Get zone. */
15141 	CHECK(zone_from_args(server, lex, zonetext, &zone, NULL, text, false));
15142 	if (zone == NULL) {
15143 		msg = "Zone not found";
15144 		CHECK(ISC_R_UNEXPECTEDEND);
15145 	}
15146 
15147 	/* Trailing garbage? */
15148 	ptr = next_token(lex, text);
15149 	if (ptr != NULL) {
15150 		msg = "Too many arguments";
15151 		CHECK(DNS_R_SYNTAX);
15152 	}
15153 
15154 	/* Get dnssec-policy. */
15155 	kasp = dns_zone_getkasp(zone);
15156 	if (kasp == NULL) {
15157 		msg = "Zone does not have dnssec-policy";
15158 		goto cleanup;
15159 	}
15160 
15161 	/* Get DNSSEC keys. */
15162 	dir = dns_zone_getkeydirectory(zone);
15163 	CHECK(dns_zone_getdb(zone, &db));
15164 	dns_db_currentversion(db, &version);
15165 	LOCK(&kasp->lock);
15166 	result = dns_zone_getdnsseckeys(zone, db, version, now, &keys);
15167 	UNLOCK(&kasp->lock);
15168 	if (result != ISC_R_SUCCESS) {
15169 		if (result != ISC_R_NOTFOUND) {
15170 			goto cleanup;
15171 		}
15172 	}
15173 
15174 	if (status) {
15175 		/*
15176 		 * Output the DNSSEC status of the key and signing policy.
15177 		 */
15178 		LOCK(&kasp->lock);
15179 		dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
15180 		UNLOCK(&kasp->lock);
15181 		CHECK(putstr(text, output));
15182 	} else if (checkds) {
15183 		/*
15184 		 * Mark DS record has been seen, so it may move to the
15185 		 * rumoured state.
15186 		 */
15187 		char whenbuf[80];
15188 		isc_time_set(&timewhen, when, 0);
15189 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
15190 		isc_result_t ret;
15191 
15192 		LOCK(&kasp->lock);
15193 		if (use_keyid) {
15194 			result = dns_keymgr_checkds_id(kasp, &keys, dir, now,
15195 						       when, dspublish, keyid,
15196 						       (unsigned int)algorithm);
15197 		} else {
15198 			result = dns_keymgr_checkds(kasp, &keys, dir, now, when,
15199 						    dspublish);
15200 		}
15201 		UNLOCK(&kasp->lock);
15202 
15203 		switch (result) {
15204 		case ISC_R_SUCCESS:
15205 			/*
15206 			 * Rekey after checkds command because the next key
15207 			 * event may have changed.
15208 			 */
15209 			dns_zone_rekey(zone, false);
15210 
15211 			if (use_keyid) {
15212 				char tagbuf[6];
15213 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
15214 				CHECK(putstr(text, "KSK "));
15215 				CHECK(putstr(text, tagbuf));
15216 				CHECK(putstr(text, ": "));
15217 			}
15218 			CHECK(putstr(text, "Marked DS as "));
15219 			if (dspublish) {
15220 				CHECK(putstr(text, "published "));
15221 			} else {
15222 				CHECK(putstr(text, "withdrawn "));
15223 			}
15224 			CHECK(putstr(text, "since "));
15225 			CHECK(putstr(text, whenbuf));
15226 			break;
15227 		case DNS_R_TOOMANYKEYS:
15228 			CHECK(putstr(text,
15229 				     "Error: multiple possible keys found, "
15230 				     "retry command with -key id"));
15231 			break;
15232 		default:
15233 			ret = result;
15234 			CHECK(putstr(text,
15235 				     "Error executing checkds command: "));
15236 			CHECK(putstr(text, isc_result_totext(ret)));
15237 			break;
15238 		}
15239 	} else if (rollover) {
15240 		/*
15241 		 * Manually rollover a key.
15242 		 */
15243 		char whenbuf[80];
15244 		isc_time_set(&timewhen, when, 0);
15245 		isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
15246 		isc_result_t ret;
15247 
15248 		LOCK(&kasp->lock);
15249 		result = dns_keymgr_rollover(kasp, &keys, dir, now, when, keyid,
15250 					     (unsigned int)algorithm);
15251 		UNLOCK(&kasp->lock);
15252 
15253 		switch (result) {
15254 		case ISC_R_SUCCESS:
15255 			/*
15256 			 * Rekey after rollover command because the next key
15257 			 * event may have changed.
15258 			 */
15259 			dns_zone_rekey(zone, false);
15260 
15261 			if (use_keyid) {
15262 				char tagbuf[6];
15263 				snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
15264 				CHECK(putstr(text, "Key "));
15265 				CHECK(putstr(text, tagbuf));
15266 				CHECK(putstr(text, ": "));
15267 			}
15268 			CHECK(putstr(text, "Rollover scheduled on "));
15269 			CHECK(putstr(text, whenbuf));
15270 			break;
15271 		case DNS_R_TOOMANYKEYS:
15272 			CHECK(putstr(text,
15273 				     "Error: multiple possible keys found, "
15274 				     "retry command with -alg algorithm"));
15275 			break;
15276 		default:
15277 			ret = result;
15278 			CHECK(putstr(text,
15279 				     "Error executing rollover command: "));
15280 			CHECK(putstr(text, isc_result_totext(ret)));
15281 			break;
15282 		}
15283 	}
15284 	CHECK(putnull(text));
15285 
15286 cleanup:
15287 	if (msg != NULL) {
15288 		(void)putstr(text, msg);
15289 		(void)putnull(text);
15290 	}
15291 
15292 	if (version != NULL) {
15293 		dns_db_closeversion(db, &version, false);
15294 	}
15295 	if (db != NULL) {
15296 		dns_db_detach(&db);
15297 	}
15298 
15299 	while (!ISC_LIST_EMPTY(keys)) {
15300 		key = ISC_LIST_HEAD(keys);
15301 		ISC_LIST_UNLINK(keys, key, link);
15302 		dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
15303 	}
15304 
15305 	if (zone != NULL) {
15306 		dns_zone_detach(&zone);
15307 	}
15308 
15309 	return (result);
15310 }
15311 
15312 static isc_result_t
putmem(isc_buffer_t ** b,const char * str,size_t len)15313 putmem(isc_buffer_t **b, const char *str, size_t len) {
15314 	isc_result_t result;
15315 
15316 	result = isc_buffer_reserve(b, (unsigned int)len);
15317 	if (result != ISC_R_SUCCESS) {
15318 		return (ISC_R_NOSPACE);
15319 	}
15320 
15321 	isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
15322 	return (ISC_R_SUCCESS);
15323 }
15324 
15325 static inline isc_result_t
putstr(isc_buffer_t ** b,const char * str)15326 putstr(isc_buffer_t **b, const char *str) {
15327 	return (putmem(b, str, strlen(str)));
15328 }
15329 
15330 static isc_result_t
putuint8(isc_buffer_t ** b,uint8_t val)15331 putuint8(isc_buffer_t **b, uint8_t val) {
15332 	isc_result_t result;
15333 
15334 	result = isc_buffer_reserve(b, 1);
15335 	if (result != ISC_R_SUCCESS) {
15336 		return (ISC_R_NOSPACE);
15337 	}
15338 
15339 	isc_buffer_putuint8(*b, val);
15340 	return (ISC_R_SUCCESS);
15341 }
15342 
15343 static inline isc_result_t
putnull(isc_buffer_t ** b)15344 putnull(isc_buffer_t **b) {
15345 	return (putuint8(b, 0));
15346 }
15347 
15348 isc_result_t
named_server_zonestatus(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)15349 named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
15350 			isc_buffer_t **text) {
15351 	isc_result_t result = ISC_R_SUCCESS;
15352 	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
15353 	const char *type, *file;
15354 	char zonename[DNS_NAME_FORMATSIZE];
15355 	uint32_t serial, signed_serial, nodes;
15356 	char serbuf[16], sserbuf[16], nodebuf[16];
15357 	char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2];
15358 	char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15359 	char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15360 	char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15361 	char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15362 	char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15363 	isc_time_t loadtime, expiretime, refreshtime;
15364 	isc_time_t refreshkeytime, resigntime;
15365 	dns_zonetype_t zonetype;
15366 	bool dynamic = false, frozen = false;
15367 	bool hasraw = false;
15368 	bool secure, maintain, allow;
15369 	dns_db_t *db = NULL, *rawdb = NULL;
15370 	char **incfiles = NULL;
15371 	int nfiles = 0;
15372 
15373 	REQUIRE(text != NULL);
15374 
15375 	isc_time_settoepoch(&loadtime);
15376 	isc_time_settoepoch(&refreshtime);
15377 	isc_time_settoepoch(&expiretime);
15378 	isc_time_settoepoch(&refreshkeytime);
15379 	isc_time_settoepoch(&resigntime);
15380 
15381 	CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
15382 	if (zone == NULL) {
15383 		result = ISC_R_UNEXPECTEDEND;
15384 		goto cleanup;
15385 	}
15386 
15387 	/* Inline signing? */
15388 	CHECK(dns_zone_getdb(zone, &db));
15389 	dns_zone_getraw(zone, &raw);
15390 	hasraw = (raw != NULL);
15391 	if (hasraw) {
15392 		mayberaw = raw;
15393 		zonetype = dns_zone_gettype(raw);
15394 		CHECK(dns_zone_getdb(raw, &rawdb));
15395 	} else {
15396 		mayberaw = zone;
15397 		zonetype = dns_zone_gettype(zone);
15398 	}
15399 
15400 	type = dns_zonetype_name(zonetype);
15401 
15402 	/* Serial number */
15403 	result = dns_zone_getserial(mayberaw, &serial);
15404 
15405 	/* This is to mirror old behavior with dns_zone_getserial */
15406 	if (result != ISC_R_SUCCESS) {
15407 		serial = 0;
15408 	}
15409 
15410 	snprintf(serbuf, sizeof(serbuf), "%u", serial);
15411 	if (hasraw) {
15412 		result = dns_zone_getserial(zone, &signed_serial);
15413 		if (result != ISC_R_SUCCESS) {
15414 			serial = 0;
15415 		}
15416 		snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial);
15417 	}
15418 
15419 	/* Database node count */
15420 	nodes = dns_db_nodecount(hasraw ? rawdb : db);
15421 	snprintf(nodebuf, sizeof(nodebuf), "%u", nodes);
15422 
15423 	/* Security */
15424 	secure = dns_db_issecure(db);
15425 	allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
15426 	maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
15427 
15428 	/* Master files */
15429 	file = dns_zone_getfile(mayberaw);
15430 	nfiles = dns_zone_getincludes(mayberaw, &incfiles);
15431 
15432 	/* Load time */
15433 	dns_zone_getloadtime(zone, &loadtime);
15434 	isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
15435 
15436 	/* Refresh/expire times */
15437 	if (zonetype == dns_zone_secondary || zonetype == dns_zone_mirror ||
15438 	    zonetype == dns_zone_stub || zonetype == dns_zone_redirect)
15439 	{
15440 		dns_zone_getexpiretime(mayberaw, &expiretime);
15441 		isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
15442 		dns_zone_getrefreshtime(mayberaw, &refreshtime);
15443 		isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
15444 	}
15445 
15446 	/* Key refresh time */
15447 	if (zonetype == dns_zone_primary ||
15448 	    (zonetype == dns_zone_secondary && hasraw)) {
15449 		dns_zone_getrefreshkeytime(zone, &refreshkeytime);
15450 		isc_time_formathttptimestamp(&refreshkeytime, kbuf,
15451 					     sizeof(kbuf));
15452 	}
15453 
15454 	/* Dynamic? */
15455 	if (zonetype == dns_zone_primary) {
15456 		dynamic = dns_zone_isdynamic(mayberaw, true);
15457 		frozen = dynamic && !dns_zone_isdynamic(mayberaw, false);
15458 	}
15459 
15460 	/* Next resign event */
15461 	if (secure &&
15462 	    (zonetype == dns_zone_primary ||
15463 	     (zonetype == dns_zone_secondary && hasraw)) &&
15464 	    ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0))
15465 	{
15466 		dns_name_t *name;
15467 		dns_fixedname_t fixed;
15468 		dns_rdataset_t next;
15469 
15470 		dns_rdataset_init(&next);
15471 		name = dns_fixedname_initname(&fixed);
15472 
15473 		result = dns_db_getsigningtime(db, &next, name);
15474 		if (result == ISC_R_SUCCESS) {
15475 			isc_stdtime_t timenow;
15476 			char namebuf[DNS_NAME_FORMATSIZE];
15477 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
15478 
15479 			isc_stdtime_get(&timenow);
15480 			dns_name_format(name, namebuf, sizeof(namebuf));
15481 			dns_rdatatype_format(next.covers, typebuf,
15482 					     sizeof(typebuf));
15483 			snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf,
15484 				 typebuf);
15485 			isc_time_set(
15486 				&resigntime,
15487 				next.resign -
15488 					dns_zone_getsigresigninginterval(zone),
15489 				0);
15490 			isc_time_formathttptimestamp(&resigntime, rtbuf,
15491 						     sizeof(rtbuf));
15492 			dns_rdataset_disassociate(&next);
15493 		}
15494 	}
15495 
15496 	/* Create text */
15497 	CHECK(putstr(text, "name: "));
15498 	CHECK(putstr(text, zonename));
15499 
15500 	CHECK(putstr(text, "\ntype: "));
15501 	CHECK(putstr(text, type));
15502 
15503 	if (file != NULL) {
15504 		int i;
15505 		CHECK(putstr(text, "\nfiles: "));
15506 		CHECK(putstr(text, file));
15507 		for (i = 0; i < nfiles; i++) {
15508 			CHECK(putstr(text, ", "));
15509 			if (incfiles[i] != NULL) {
15510 				CHECK(putstr(text, incfiles[i]));
15511 			}
15512 		}
15513 	}
15514 
15515 	CHECK(putstr(text, "\nserial: "));
15516 	CHECK(putstr(text, serbuf));
15517 	if (hasraw) {
15518 		CHECK(putstr(text, "\nsigned serial: "));
15519 		CHECK(putstr(text, sserbuf));
15520 	}
15521 
15522 	CHECK(putstr(text, "\nnodes: "));
15523 	CHECK(putstr(text, nodebuf));
15524 
15525 	if (!isc_time_isepoch(&loadtime)) {
15526 		CHECK(putstr(text, "\nlast loaded: "));
15527 		CHECK(putstr(text, lbuf));
15528 	}
15529 
15530 	if (!isc_time_isepoch(&refreshtime)) {
15531 		CHECK(putstr(text, "\nnext refresh: "));
15532 		CHECK(putstr(text, rbuf));
15533 	}
15534 
15535 	if (!isc_time_isepoch(&expiretime)) {
15536 		CHECK(putstr(text, "\nexpires: "));
15537 		CHECK(putstr(text, xbuf));
15538 	}
15539 
15540 	if (secure) {
15541 		CHECK(putstr(text, "\nsecure: yes"));
15542 		if (hasraw) {
15543 			CHECK(putstr(text, "\ninline signing: yes"));
15544 		} else {
15545 			CHECK(putstr(text, "\ninline signing: no"));
15546 		}
15547 	} else {
15548 		CHECK(putstr(text, "\nsecure: no"));
15549 	}
15550 
15551 	if (maintain) {
15552 		CHECK(putstr(text, "\nkey maintenance: automatic"));
15553 		if (!isc_time_isepoch(&refreshkeytime)) {
15554 			CHECK(putstr(text, "\nnext key event: "));
15555 			CHECK(putstr(text, kbuf));
15556 		}
15557 	} else if (allow) {
15558 		CHECK(putstr(text, "\nkey maintenance: on command"));
15559 	} else if (secure || hasraw) {
15560 		CHECK(putstr(text, "\nkey maintenance: none"));
15561 	}
15562 
15563 	if (!isc_time_isepoch(&resigntime)) {
15564 		CHECK(putstr(text, "\nnext resign node: "));
15565 		CHECK(putstr(text, resignbuf));
15566 		CHECK(putstr(text, "\nnext resign time: "));
15567 		CHECK(putstr(text, rtbuf));
15568 	}
15569 
15570 	if (dynamic) {
15571 		CHECK(putstr(text, "\ndynamic: yes"));
15572 		if (frozen) {
15573 			CHECK(putstr(text, "\nfrozen: yes"));
15574 		} else {
15575 			CHECK(putstr(text, "\nfrozen: no"));
15576 		}
15577 	} else {
15578 		CHECK(putstr(text, "\ndynamic: no"));
15579 	}
15580 
15581 	CHECK(putstr(text, "\nreconfigurable via modzone: "));
15582 	CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
15583 
15584 cleanup:
15585 	/* Indicate truncated output if possible. */
15586 	if (result == ISC_R_NOSPACE) {
15587 		(void)putstr(text, "\n...");
15588 	}
15589 	if ((result == ISC_R_SUCCESS || result == ISC_R_NOSPACE)) {
15590 		(void)putnull(text);
15591 	}
15592 
15593 	if (db != NULL) {
15594 		dns_db_detach(&db);
15595 	}
15596 	if (rawdb != NULL) {
15597 		dns_db_detach(&rawdb);
15598 	}
15599 	if (incfiles != NULL && mayberaw != NULL) {
15600 		int i;
15601 		isc_mem_t *mctx = dns_zone_getmctx(mayberaw);
15602 
15603 		for (i = 0; i < nfiles; i++) {
15604 			if (incfiles[i] != NULL) {
15605 				isc_mem_free(mctx, incfiles[i]);
15606 			}
15607 		}
15608 		isc_mem_free(mctx, incfiles);
15609 	}
15610 	if (raw != NULL) {
15611 		dns_zone_detach(&raw);
15612 	}
15613 	if (zone != NULL) {
15614 		dns_zone_detach(&zone);
15615 	}
15616 	return (result);
15617 }
15618 
15619 isc_result_t
named_server_nta(named_server_t * server,isc_lex_t * lex,bool readonly,isc_buffer_t ** text)15620 named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
15621 		 isc_buffer_t **text) {
15622 	dns_view_t *view;
15623 	dns_ntatable_t *ntatable = NULL;
15624 	isc_result_t result = ISC_R_SUCCESS;
15625 	char *ptr, *nametext = NULL, *viewname;
15626 	char namebuf[DNS_NAME_FORMATSIZE];
15627 	char viewbuf[DNS_NAME_FORMATSIZE];
15628 	isc_stdtime_t now, when;
15629 	isc_time_t t;
15630 	char tbuf[64];
15631 	const char *msg = NULL;
15632 	bool dump = false, force = false;
15633 	dns_fixedname_t fn;
15634 	const dns_name_t *ntaname;
15635 	dns_name_t *fname;
15636 	dns_ttl_t ntattl;
15637 	bool ttlset = false, excl = false, viewfound = false;
15638 	dns_rdataclass_t rdclass = dns_rdataclass_in;
15639 	bool first = true;
15640 
15641 	REQUIRE(text != NULL);
15642 
15643 	UNUSED(force);
15644 
15645 	fname = dns_fixedname_initname(&fn);
15646 
15647 	/* Skip the command name. */
15648 	ptr = next_token(lex, text);
15649 	if (ptr == NULL) {
15650 		return (ISC_R_UNEXPECTEDEND);
15651 	}
15652 
15653 	for (;;) {
15654 		/* Check for options */
15655 		ptr = next_token(lex, text);
15656 		if (ptr == NULL) {
15657 			return (ISC_R_UNEXPECTEDEND);
15658 		}
15659 
15660 		if (strcmp(ptr, "--") == 0) {
15661 			break;
15662 		} else if (argcheck(ptr, "dump")) {
15663 			dump = true;
15664 		} else if (argcheck(ptr, "remove")) {
15665 			ntattl = 0;
15666 			ttlset = true;
15667 		} else if (argcheck(ptr, "force")) {
15668 			force = true;
15669 			continue;
15670 		} else if (argcheck(ptr, "lifetime")) {
15671 			isc_textregion_t tr;
15672 
15673 			ptr = next_token(lex, text);
15674 			if (ptr == NULL) {
15675 				msg = "No lifetime specified";
15676 				CHECK(ISC_R_UNEXPECTEDEND);
15677 			}
15678 
15679 			tr.base = ptr;
15680 			tr.length = strlen(ptr);
15681 			result = dns_ttl_fromtext(&tr, &ntattl);
15682 			if (result != ISC_R_SUCCESS) {
15683 				msg = "could not parse NTA lifetime";
15684 				CHECK(result);
15685 			}
15686 
15687 			if (ntattl > 604800) {
15688 				msg = "NTA lifetime cannot exceed one week";
15689 				CHECK(ISC_R_RANGE);
15690 			}
15691 
15692 			ttlset = true;
15693 			continue;
15694 		} else if (argcheck(ptr, "class")) {
15695 			isc_textregion_t tr;
15696 
15697 			ptr = next_token(lex, text);
15698 			if (ptr == NULL) {
15699 				msg = "No class specified";
15700 				CHECK(ISC_R_UNEXPECTEDEND);
15701 			}
15702 
15703 			tr.base = ptr;
15704 			tr.length = strlen(ptr);
15705 			CHECK(dns_rdataclass_fromtext(&rdclass, &tr));
15706 			continue;
15707 		} else if (ptr[0] == '-') {
15708 			msg = "Unknown option";
15709 			CHECK(DNS_R_SYNTAX);
15710 		} else {
15711 			nametext = ptr;
15712 		}
15713 
15714 		break;
15715 	}
15716 
15717 	/*
15718 	 * If -dump was specified, list NTA's and return
15719 	 */
15720 	if (dump) {
15721 		for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15722 		     view = ISC_LIST_NEXT(view, link))
15723 		{
15724 			if (ntatable != NULL) {
15725 				dns_ntatable_detach(&ntatable);
15726 			}
15727 			result = dns_view_getntatable(view, &ntatable);
15728 			if (result == ISC_R_NOTFOUND) {
15729 				continue;
15730 			}
15731 
15732 			CHECK(dns_ntatable_totext(ntatable, view->name, text));
15733 		}
15734 		CHECK(putnull(text));
15735 
15736 		goto cleanup;
15737 	}
15738 
15739 	if (readonly) {
15740 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15741 			      NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
15742 			      "rejecting restricted control channel "
15743 			      "NTA command");
15744 		CHECK(ISC_R_FAILURE);
15745 	}
15746 
15747 	/* Get the NTA name if not found above. */
15748 	if (nametext == NULL) {
15749 		nametext = next_token(lex, text);
15750 	}
15751 	if (nametext == NULL) {
15752 		return (ISC_R_UNEXPECTEDEND);
15753 	}
15754 
15755 	/* Copy nametext as it'll be overwritten by next_token() */
15756 	strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE);
15757 
15758 	if (strcmp(namebuf, ".") == 0) {
15759 		ntaname = dns_rootname;
15760 	} else {
15761 		isc_buffer_t b;
15762 		isc_buffer_init(&b, namebuf, strlen(namebuf));
15763 		isc_buffer_add(&b, strlen(namebuf));
15764 		CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL));
15765 		ntaname = fname;
15766 	}
15767 
15768 	/* Look for the view name. */
15769 	viewname = next_token(lex, text);
15770 	if (viewname != NULL) {
15771 		strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE);
15772 		viewname = viewbuf;
15773 	}
15774 
15775 	if (next_token(lex, text) != NULL) {
15776 		CHECK(DNS_R_SYNTAX);
15777 	}
15778 
15779 	isc_stdtime_get(&now);
15780 
15781 	result = isc_task_beginexclusive(server->task);
15782 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
15783 	excl = true;
15784 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15785 	     view = ISC_LIST_NEXT(view, link))
15786 	{
15787 		if (viewname != NULL && strcmp(view->name, viewname) != 0) {
15788 			continue;
15789 		}
15790 		viewfound = true;
15791 
15792 		if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) {
15793 			continue;
15794 		}
15795 
15796 		if (view->nta_lifetime == 0) {
15797 			continue;
15798 		}
15799 
15800 		if (!ttlset) {
15801 			ntattl = view->nta_lifetime;
15802 		}
15803 
15804 		if (ntatable != NULL) {
15805 			dns_ntatable_detach(&ntatable);
15806 		}
15807 
15808 		result = dns_view_getntatable(view, &ntatable);
15809 		if (result == ISC_R_NOTFOUND) {
15810 			result = ISC_R_SUCCESS;
15811 			continue;
15812 		}
15813 
15814 		result = dns_view_flushnode(view, ntaname, true);
15815 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15816 			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15817 			      "flush tree '%s' in cache view '%s': %s", namebuf,
15818 			      view->name, isc_result_totext(result));
15819 
15820 		if (ntattl != 0) {
15821 			CHECK(dns_ntatable_add(ntatable, ntaname, force, now,
15822 					       ntattl));
15823 
15824 			when = now + ntattl;
15825 			isc_time_set(&t, when, 0);
15826 			isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
15827 
15828 			if (!first) {
15829 				CHECK(putstr(text, "\n"));
15830 			}
15831 			first = false;
15832 
15833 			CHECK(putstr(text, "Negative trust anchor added: "));
15834 			CHECK(putstr(text, namebuf));
15835 			CHECK(putstr(text, "/"));
15836 			CHECK(putstr(text, view->name));
15837 			CHECK(putstr(text, ", expires "));
15838 			CHECK(putstr(text, tbuf));
15839 
15840 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15841 				      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15842 				      "added NTA '%s' (%d sec) in view '%s'",
15843 				      namebuf, ntattl, view->name);
15844 		} else {
15845 			bool wasremoved;
15846 
15847 			result = dns_ntatable_delete(ntatable, ntaname);
15848 			if (result == ISC_R_SUCCESS) {
15849 				wasremoved = true;
15850 			} else if (result == ISC_R_NOTFOUND) {
15851 				wasremoved = false;
15852 			} else {
15853 				goto cleanup;
15854 			}
15855 
15856 			if (!first) {
15857 				CHECK(putstr(text, "\n"));
15858 			}
15859 			first = false;
15860 
15861 			CHECK(putstr(text, "Negative trust anchor "));
15862 			CHECK(putstr(text,
15863 				     wasremoved ? "removed: " : "not found: "));
15864 			CHECK(putstr(text, namebuf));
15865 			CHECK(putstr(text, "/"));
15866 			CHECK(putstr(text, view->name));
15867 
15868 			if (wasremoved) {
15869 				isc_log_write(
15870 					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15871 					NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15872 					"removed NTA '%s' in view %s", namebuf,
15873 					view->name);
15874 			}
15875 		}
15876 
15877 		result = dns_view_saventa(view);
15878 		if (result != ISC_R_SUCCESS) {
15879 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15880 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15881 				      "error writing NTA file "
15882 				      "for view '%s': %s",
15883 				      view->name, isc_result_totext(result));
15884 		}
15885 	}
15886 
15887 	if (!viewfound) {
15888 		msg = "No such view";
15889 		CHECK(ISC_R_NOTFOUND);
15890 	}
15891 
15892 	(void)putnull(text);
15893 
15894 cleanup:
15895 	if (msg != NULL) {
15896 		(void)putstr(text, msg);
15897 		(void)putnull(text);
15898 	}
15899 
15900 	if (excl) {
15901 		isc_task_endexclusive(server->task);
15902 	}
15903 	if (ntatable != NULL) {
15904 		dns_ntatable_detach(&ntatable);
15905 	}
15906 	return (result);
15907 }
15908 
15909 isc_result_t
named_server_saventa(named_server_t * server)15910 named_server_saventa(named_server_t *server) {
15911 	dns_view_t *view;
15912 
15913 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15914 	     view = ISC_LIST_NEXT(view, link))
15915 	{
15916 		isc_result_t result = dns_view_saventa(view);
15917 
15918 		if (result != ISC_R_SUCCESS) {
15919 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15920 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15921 				      "error writing NTA file "
15922 				      "for view '%s': %s",
15923 				      view->name, isc_result_totext(result));
15924 		}
15925 	}
15926 
15927 	return (ISC_R_SUCCESS);
15928 }
15929 
15930 isc_result_t
named_server_loadnta(named_server_t * server)15931 named_server_loadnta(named_server_t *server) {
15932 	dns_view_t *view;
15933 
15934 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15935 	     view = ISC_LIST_NEXT(view, link))
15936 	{
15937 		isc_result_t result = dns_view_loadnta(view);
15938 
15939 		if ((result != ISC_R_SUCCESS) &&
15940 		    (result != ISC_R_FILENOTFOUND) &&
15941 		    (result != ISC_R_NOTFOUND))
15942 		{
15943 			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15944 				      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15945 				      "error loading NTA file "
15946 				      "for view '%s': %s",
15947 				      view->name, isc_result_totext(result));
15948 		}
15949 	}
15950 
15951 	return (ISC_R_SUCCESS);
15952 }
15953 
15954 static isc_result_t
mkey_refresh(dns_view_t * view,isc_buffer_t ** text)15955 mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
15956 	isc_result_t result;
15957 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
15958 
15959 	snprintf(msg, sizeof(msg), "refreshing managed keys for '%s'",
15960 		 view->name);
15961 	CHECK(putstr(text, msg));
15962 	CHECK(dns_zone_synckeyzone(view->managed_keys));
15963 
15964 cleanup:
15965 	return (result);
15966 }
15967 
15968 static isc_result_t
mkey_destroy(named_server_t * server,dns_view_t * view,isc_buffer_t ** text)15969 mkey_destroy(named_server_t *server, dns_view_t *view, isc_buffer_t **text) {
15970 	isc_result_t result;
15971 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
15972 	bool exclusive = false;
15973 	const char *file = NULL;
15974 	dns_db_t *dbp = NULL;
15975 	dns_zone_t *mkzone = NULL;
15976 	bool removed_a_file = false;
15977 
15978 	if (view->managed_keys == NULL) {
15979 		CHECK(ISC_R_NOTFOUND);
15980 	}
15981 
15982 	snprintf(msg, sizeof(msg), "destroying managed-keys database for '%s'",
15983 		 view->name);
15984 	CHECK(putstr(text, msg));
15985 
15986 	result = isc_task_beginexclusive(server->task);
15987 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
15988 	exclusive = true;
15989 
15990 	/* Remove and clean up managed keys zone from view */
15991 	mkzone = view->managed_keys;
15992 	view->managed_keys = NULL;
15993 	(void)dns_zone_flush(mkzone);
15994 
15995 	/* Unload zone database */
15996 	if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) {
15997 		dns_db_detach(&dbp);
15998 		dns_zone_unload(mkzone);
15999 	}
16000 
16001 	/* Delete files */
16002 	file = dns_zone_getfile(mkzone);
16003 	result = isc_file_remove(file);
16004 	if (result == ISC_R_SUCCESS) {
16005 		removed_a_file = true;
16006 	} else {
16007 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16008 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
16009 			      "file %s not removed: %s", file,
16010 			      isc_result_totext(result));
16011 	}
16012 
16013 	file = dns_zone_getjournal(mkzone);
16014 	result = isc_file_remove(file);
16015 	if (result == ISC_R_SUCCESS) {
16016 		removed_a_file = true;
16017 	} else {
16018 		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
16019 			      NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
16020 			      "file %s not removed: %s", file,
16021 			      isc_result_totext(result));
16022 	}
16023 
16024 	if (!removed_a_file) {
16025 		CHECK(putstr(text, "error: no files could be removed"));
16026 		CHECK(ISC_R_FAILURE);
16027 	}
16028 
16029 	dns_zone_detach(&mkzone);
16030 	result = ISC_R_SUCCESS;
16031 
16032 cleanup:
16033 	if (exclusive) {
16034 		isc_task_endexclusive(server->task);
16035 	}
16036 	return (result);
16037 }
16038 
16039 static isc_result_t
mkey_dumpzone(dns_view_t * view,isc_buffer_t ** text)16040 mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
16041 	isc_result_t result;
16042 	dns_db_t *db = NULL;
16043 	dns_dbversion_t *ver = NULL;
16044 	dns_rriterator_t rrit;
16045 	isc_stdtime_t now;
16046 	dns_name_t *prevname = NULL;
16047 
16048 	isc_stdtime_get(&now);
16049 
16050 	CHECK(dns_zone_getdb(view->managed_keys, &db));
16051 	dns_db_currentversion(db, &ver);
16052 	dns_rriterator_init(&rrit, db, ver, 0);
16053 	for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS;
16054 	     result = dns_rriterator_nextrrset(&rrit))
16055 	{
16056 		char buf[DNS_NAME_FORMATSIZE + 500];
16057 		dns_name_t *name = NULL;
16058 		dns_rdataset_t *kdset = NULL;
16059 		dns_rdata_t rdata = DNS_RDATA_INIT;
16060 		dns_rdata_keydata_t kd;
16061 		uint32_t ttl;
16062 
16063 		dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
16064 		if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
16065 		    !dns_rdataset_isassociated(kdset))
16066 		{
16067 			continue;
16068 		}
16069 
16070 		if (name != prevname) {
16071 			char nbuf[DNS_NAME_FORMATSIZE];
16072 			dns_name_format(name, nbuf, sizeof(nbuf));
16073 			snprintf(buf, sizeof(buf), "\n\n    name: %s", nbuf);
16074 			CHECK(putstr(text, buf));
16075 		}
16076 
16077 		for (result = dns_rdataset_first(kdset);
16078 		     result == ISC_R_SUCCESS; result = dns_rdataset_next(kdset))
16079 		{
16080 			char alg[DNS_SECALG_FORMATSIZE];
16081 			char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
16082 			dns_keytag_t keyid;
16083 			isc_region_t r;
16084 			isc_time_t t;
16085 			bool revoked;
16086 
16087 			dns_rdata_reset(&rdata);
16088 			dns_rdataset_current(kdset, &rdata);
16089 			result = dns_rdata_tostruct(&rdata, &kd, NULL);
16090 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
16091 
16092 			dns_rdata_toregion(&rdata, &r);
16093 			isc_region_consume(&r, 12);
16094 			keyid = dst_region_computeid(&r);
16095 
16096 			snprintf(buf, sizeof(buf), "\n    keyid: %u", keyid);
16097 			CHECK(putstr(text, buf));
16098 
16099 			dns_secalg_format(kd.algorithm, alg, sizeof(alg));
16100 			snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
16101 			CHECK(putstr(text, buf));
16102 
16103 			revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
16104 			snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
16105 				 revoked ? " REVOKE" : "",
16106 				 ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP"
16107 								     : "",
16108 				 (kd.flags == 0) ? " (none)" : "");
16109 			CHECK(putstr(text, buf));
16110 
16111 			isc_time_set(&t, kd.refresh, 0);
16112 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
16113 			snprintf(buf, sizeof(buf), "\n\tnext refresh: %s",
16114 				 tbuf);
16115 			CHECK(putstr(text, buf));
16116 
16117 			if (kd.removehd != 0) {
16118 				isc_time_set(&t, kd.removehd, 0);
16119 				isc_time_formathttptimestamp(&t, tbuf,
16120 							     sizeof(tbuf));
16121 				snprintf(buf, sizeof(buf), "\n\tremove at: %s",
16122 					 tbuf);
16123 				CHECK(putstr(text, buf));
16124 			}
16125 
16126 			isc_time_set(&t, kd.addhd, 0);
16127 			isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
16128 			if (kd.addhd == 0) {
16129 				snprintf(buf, sizeof(buf), "\n\tno trust");
16130 			} else if (revoked) {
16131 				snprintf(buf, sizeof(buf), "\n\ttrust revoked");
16132 			} else if (kd.addhd <= now) {
16133 				snprintf(buf, sizeof(buf),
16134 					 "\n\ttrusted since: %s", tbuf);
16135 			} else if (kd.addhd > now) {
16136 				snprintf(buf, sizeof(buf),
16137 					 "\n\ttrust pending: %s", tbuf);
16138 			}
16139 			CHECK(putstr(text, buf));
16140 		}
16141 	}
16142 
16143 	if (result == ISC_R_NOMORE) {
16144 		result = ISC_R_SUCCESS;
16145 	}
16146 
16147 cleanup:
16148 	if (ver != NULL) {
16149 		dns_rriterator_destroy(&rrit);
16150 		dns_db_closeversion(db, &ver, false);
16151 	}
16152 	if (db != NULL) {
16153 		dns_db_detach(&db);
16154 	}
16155 
16156 	return (result);
16157 }
16158 
16159 static isc_result_t
mkey_status(dns_view_t * view,isc_buffer_t ** text)16160 mkey_status(dns_view_t *view, isc_buffer_t **text) {
16161 	isc_result_t result;
16162 	char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
16163 	isc_time_t t;
16164 
16165 	CHECK(putstr(text, "view: "));
16166 	CHECK(putstr(text, view->name));
16167 
16168 	CHECK(putstr(text, "\nnext scheduled event: "));
16169 
16170 	dns_zone_getrefreshkeytime(view->managed_keys, &t);
16171 	if (isc_time_isepoch(&t)) {
16172 		CHECK(putstr(text, "never"));
16173 	} else {
16174 		isc_time_formathttptimestamp(&t, msg, sizeof(msg));
16175 		CHECK(putstr(text, msg));
16176 	}
16177 
16178 	CHECK(mkey_dumpzone(view, text));
16179 
16180 cleanup:
16181 	return (result);
16182 }
16183 
16184 isc_result_t
named_server_mkeys(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)16185 named_server_mkeys(named_server_t *server, isc_lex_t *lex,
16186 		   isc_buffer_t **text) {
16187 	char *cmd, *classtxt, *viewtxt = NULL;
16188 	isc_result_t result = ISC_R_SUCCESS;
16189 	dns_view_t *view = NULL;
16190 	dns_rdataclass_t rdclass;
16191 	char msg[DNS_NAME_FORMATSIZE + 500] = "";
16192 	enum { NONE, STATUS, REFRESH, SYNC, DESTROY } opt = NONE;
16193 	bool found = false;
16194 	bool first = true;
16195 
16196 	REQUIRE(text != NULL);
16197 
16198 	/* Skip rndc command name */
16199 	cmd = next_token(lex, text);
16200 	if (cmd == NULL) {
16201 		return (ISC_R_UNEXPECTEDEND);
16202 	}
16203 
16204 	/* Get managed-keys subcommand */
16205 	cmd = next_token(lex, text);
16206 	if (cmd == NULL) {
16207 		return (ISC_R_UNEXPECTEDEND);
16208 	}
16209 
16210 	if (strcasecmp(cmd, "status") == 0) {
16211 		opt = STATUS;
16212 	} else if (strcasecmp(cmd, "refresh") == 0) {
16213 		opt = REFRESH;
16214 	} else if (strcasecmp(cmd, "sync") == 0) {
16215 		opt = SYNC;
16216 	} else if (strcasecmp(cmd, "destroy") == 0) {
16217 		opt = DESTROY;
16218 	} else {
16219 		snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
16220 		(void)putstr(text, msg);
16221 		result = ISC_R_UNEXPECTED;
16222 		goto cleanup;
16223 	}
16224 
16225 	/* Look for the optional class name. */
16226 	classtxt = next_token(lex, text);
16227 	if (classtxt != NULL) {
16228 		isc_textregion_t r;
16229 		r.base = classtxt;
16230 		r.length = strlen(classtxt);
16231 		result = dns_rdataclass_fromtext(&rdclass, &r);
16232 		if (result != ISC_R_SUCCESS) {
16233 			snprintf(msg, sizeof(msg), "unknown class '%s'",
16234 				 classtxt);
16235 			(void)putstr(text, msg);
16236 			goto cleanup;
16237 		}
16238 		viewtxt = next_token(lex, text);
16239 	}
16240 
16241 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16242 	     view = ISC_LIST_NEXT(view, link))
16243 	{
16244 		if (viewtxt != NULL && (rdclass != view->rdclass ||
16245 					strcmp(view->name, viewtxt) != 0))
16246 		{
16247 			continue;
16248 		}
16249 
16250 		if (view->managed_keys == NULL) {
16251 			if (viewtxt != NULL) {
16252 				snprintf(msg, sizeof(msg),
16253 					 "view '%s': no managed keys", viewtxt);
16254 				CHECK(putstr(text, msg));
16255 				goto cleanup;
16256 			} else {
16257 				continue;
16258 			}
16259 		}
16260 
16261 		found = true;
16262 
16263 		switch (opt) {
16264 		case REFRESH:
16265 			if (!first) {
16266 				CHECK(putstr(text, "\n"));
16267 			}
16268 			CHECK(mkey_refresh(view, text));
16269 			break;
16270 		case STATUS:
16271 			if (!first) {
16272 				CHECK(putstr(text, "\n\n"));
16273 			}
16274 			CHECK(mkey_status(view, text));
16275 			break;
16276 		case SYNC:
16277 			CHECK(dns_zone_flush(view->managed_keys));
16278 			break;
16279 		case DESTROY:
16280 			if (!first) {
16281 				CHECK(putstr(text, "\n"));
16282 			}
16283 			CHECK(mkey_destroy(server, view, text));
16284 			break;
16285 		default:
16286 			INSIST(0);
16287 			ISC_UNREACHABLE();
16288 		}
16289 
16290 		if (viewtxt != NULL) {
16291 			break;
16292 		}
16293 		first = false;
16294 	}
16295 
16296 	if (!found) {
16297 		CHECK(putstr(text, "no views with managed keys"));
16298 	}
16299 
16300 cleanup:
16301 	if (isc_buffer_usedlength(*text) > 0) {
16302 		(void)putnull(text);
16303 	}
16304 
16305 	return (result);
16306 }
16307 
16308 isc_result_t
named_server_dnstap(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)16309 named_server_dnstap(named_server_t *server, isc_lex_t *lex,
16310 		    isc_buffer_t **text) {
16311 #ifdef HAVE_DNSTAP
16312 	char *ptr;
16313 	isc_result_t result;
16314 	bool reopen = false;
16315 	int backups = 0;
16316 
16317 	REQUIRE(text != NULL);
16318 
16319 	if (server->dtenv == NULL) {
16320 		return (ISC_R_NOTFOUND);
16321 	}
16322 
16323 	/* Check the command name. */
16324 	ptr = next_token(lex, text);
16325 	if (ptr == NULL) {
16326 		return (ISC_R_UNEXPECTEDEND);
16327 	}
16328 
16329 	/* "dnstap-reopen" was used in 9.11.0b1 */
16330 	if (strcasecmp(ptr, "dnstap-reopen") == 0) {
16331 		reopen = true;
16332 	} else {
16333 		ptr = next_token(lex, text);
16334 		if (ptr == NULL) {
16335 			return (ISC_R_UNEXPECTEDEND);
16336 		}
16337 	}
16338 
16339 	if (reopen || strcasecmp(ptr, "-reopen") == 0) {
16340 		backups = ISC_LOG_ROLLNEVER;
16341 	} else if ((strcasecmp(ptr, "-roll") == 0)) {
16342 		unsigned int n;
16343 		ptr = next_token(lex, text);
16344 		if (ptr != NULL) {
16345 			unsigned int u;
16346 			n = sscanf(ptr, "%u", &u);
16347 			if (n != 1U || u > INT_MAX) {
16348 				return (ISC_R_BADNUMBER);
16349 			}
16350 			backups = u;
16351 		} else {
16352 			backups = ISC_LOG_ROLLINFINITE;
16353 		}
16354 	} else {
16355 		return (DNS_R_SYNTAX);
16356 	}
16357 
16358 	result = dns_dt_reopen(server->dtenv, backups);
16359 	return (result);
16360 #else  /* ifdef HAVE_DNSTAP */
16361 	UNUSED(server);
16362 	UNUSED(lex);
16363 	UNUSED(text);
16364 	return (ISC_R_NOTIMPLEMENTED);
16365 #endif /* ifdef HAVE_DNSTAP */
16366 }
16367 
16368 isc_result_t
named_server_tcptimeouts(isc_lex_t * lex,isc_buffer_t ** text)16369 named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) {
16370 	char *ptr;
16371 	isc_result_t result = ISC_R_SUCCESS;
16372 	uint32_t initial, idle, keepalive, advertised;
16373 	char msg[128];
16374 
16375 	/* Skip the command name. */
16376 	ptr = next_token(lex, text);
16377 	if (ptr == NULL) {
16378 		return (ISC_R_UNEXPECTEDEND);
16379 	}
16380 
16381 	isc_nm_gettimeouts(named_g_netmgr, &initial, &idle, &keepalive,
16382 			   &advertised);
16383 
16384 	/* Look for optional arguments. */
16385 	ptr = next_token(lex, NULL);
16386 	if (ptr != NULL) {
16387 		CHECK(isc_parse_uint32(&initial, ptr, 10));
16388 		initial *= 100;
16389 		if (initial > MAX_INITIAL_TIMEOUT) {
16390 			CHECK(ISC_R_RANGE);
16391 		}
16392 		if (initial < MIN_INITIAL_TIMEOUT) {
16393 			CHECK(ISC_R_RANGE);
16394 		}
16395 
16396 		ptr = next_token(lex, text);
16397 		if (ptr == NULL) {
16398 			return (ISC_R_UNEXPECTEDEND);
16399 		}
16400 		CHECK(isc_parse_uint32(&idle, ptr, 10));
16401 		idle *= 100;
16402 		if (idle > MAX_IDLE_TIMEOUT) {
16403 			CHECK(ISC_R_RANGE);
16404 		}
16405 		if (idle < MIN_IDLE_TIMEOUT) {
16406 			CHECK(ISC_R_RANGE);
16407 		}
16408 
16409 		ptr = next_token(lex, text);
16410 		if (ptr == NULL) {
16411 			return (ISC_R_UNEXPECTEDEND);
16412 		}
16413 		CHECK(isc_parse_uint32(&keepalive, ptr, 10));
16414 		keepalive *= 100;
16415 		if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
16416 			CHECK(ISC_R_RANGE);
16417 		}
16418 		if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
16419 			CHECK(ISC_R_RANGE);
16420 		}
16421 
16422 		ptr = next_token(lex, text);
16423 		if (ptr == NULL) {
16424 			return (ISC_R_UNEXPECTEDEND);
16425 		}
16426 		CHECK(isc_parse_uint32(&advertised, ptr, 10));
16427 		advertised *= 100;
16428 		if (advertised > MAX_ADVERTISED_TIMEOUT) {
16429 			CHECK(ISC_R_RANGE);
16430 		}
16431 
16432 		result = isc_task_beginexclusive(named_g_server->task);
16433 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
16434 
16435 		isc_nm_settimeouts(named_g_netmgr, initial, idle, keepalive,
16436 				   advertised);
16437 
16438 		isc_task_endexclusive(named_g_server->task);
16439 	}
16440 
16441 	snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100);
16442 	CHECK(putstr(text, msg));
16443 	snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100);
16444 	CHECK(putstr(text, msg));
16445 	snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n",
16446 		 keepalive / 100);
16447 	CHECK(putstr(text, msg));
16448 	snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u",
16449 		 advertised / 100);
16450 	CHECK(putstr(text, msg));
16451 
16452 cleanup:
16453 	if (isc_buffer_usedlength(*text) > 0) {
16454 		(void)putnull(text);
16455 	}
16456 
16457 	return (result);
16458 }
16459 
16460 isc_result_t
named_server_servestale(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)16461 named_server_servestale(named_server_t *server, isc_lex_t *lex,
16462 			isc_buffer_t **text) {
16463 	char *ptr, *classtxt, *viewtxt = NULL;
16464 	char msg[128];
16465 	dns_rdataclass_t rdclass = dns_rdataclass_in;
16466 	dns_view_t *view;
16467 	bool found = false;
16468 	dns_stale_answer_t staleanswersok = dns_stale_answer_conf;
16469 	bool wantstatus = false;
16470 	isc_result_t result = ISC_R_SUCCESS;
16471 	bool exclusive = false;
16472 
16473 	REQUIRE(text != NULL);
16474 
16475 	/* Skip the command name. */
16476 	ptr = next_token(lex, text);
16477 	if (ptr == NULL) {
16478 		return (ISC_R_UNEXPECTEDEND);
16479 	}
16480 
16481 	ptr = next_token(lex, NULL);
16482 	if (ptr == NULL) {
16483 		return (ISC_R_UNEXPECTEDEND);
16484 	}
16485 
16486 	if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
16487 	    !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
16488 	{
16489 		staleanswersok = dns_stale_answer_yes;
16490 	} else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
16491 		   !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
16492 	{
16493 		staleanswersok = dns_stale_answer_no;
16494 	} else if (strcasecmp(ptr, "reset") == 0) {
16495 		staleanswersok = dns_stale_answer_conf;
16496 	} else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
16497 		wantstatus = true;
16498 	} else {
16499 		return (DNS_R_SYNTAX);
16500 	}
16501 
16502 	/* Look for the optional class name. */
16503 	classtxt = next_token(lex, text);
16504 	if (classtxt != NULL) {
16505 		isc_textregion_t r;
16506 
16507 		/* Look for the optional view name. */
16508 		viewtxt = next_token(lex, text);
16509 
16510 		/*
16511 		 * If 'classtext' is not a valid class then it us a view name.
16512 		 */
16513 		r.base = classtxt;
16514 		r.length = strlen(classtxt);
16515 		result = dns_rdataclass_fromtext(&rdclass, &r);
16516 		if (result != ISC_R_SUCCESS) {
16517 			if (viewtxt != NULL) {
16518 				snprintf(msg, sizeof(msg), "unknown class '%s'",
16519 					 classtxt);
16520 				(void)putstr(text, msg);
16521 				goto cleanup;
16522 			}
16523 
16524 			viewtxt = classtxt;
16525 			classtxt = NULL;
16526 		}
16527 	}
16528 
16529 	result = isc_task_beginexclusive(server->task);
16530 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
16531 	exclusive = true;
16532 
16533 	for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16534 	     view = ISC_LIST_NEXT(view, link))
16535 	{
16536 		dns_ttl_t stale_ttl = 0;
16537 		uint32_t stale_refresh = 0;
16538 		dns_db_t *db = NULL;
16539 
16540 		if (classtxt != NULL && rdclass != view->rdclass) {
16541 			continue;
16542 		}
16543 
16544 		if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0) {
16545 			continue;
16546 		}
16547 
16548 		if (!wantstatus) {
16549 			view->staleanswersok = staleanswersok;
16550 			found = true;
16551 			continue;
16552 		}
16553 
16554 		db = NULL;
16555 		dns_db_attach(view->cachedb, &db);
16556 		(void)dns_db_getservestalettl(db, &stale_ttl);
16557 		(void)dns_db_getservestalerefresh(db, &stale_refresh);
16558 		dns_db_detach(&db);
16559 		if (found) {
16560 			CHECK(putstr(text, "\n"));
16561 		}
16562 		CHECK(putstr(text, view->name));
16563 		CHECK(putstr(text, ": "));
16564 		switch (view->staleanswersok) {
16565 		case dns_stale_answer_yes:
16566 			if (stale_ttl > 0) {
16567 				CHECK(putstr(text, "on (rndc)"));
16568 			} else {
16569 				CHECK(putstr(text, "off (not-cached)"));
16570 			}
16571 			break;
16572 		case dns_stale_answer_no:
16573 			CHECK(putstr(text, "off (rndc)"));
16574 			break;
16575 		case dns_stale_answer_conf:
16576 			if (view->staleanswersenable && stale_ttl > 0) {
16577 				CHECK(putstr(text, "on"));
16578 			} else if (view->staleanswersenable) {
16579 				CHECK(putstr(text, "off (not-cached)"));
16580 			} else {
16581 				CHECK(putstr(text, "off"));
16582 			}
16583 			break;
16584 		}
16585 		if (stale_ttl > 0) {
16586 			snprintf(msg, sizeof(msg),
16587 				 " (stale-answer-ttl=%u max-stale-ttl=%u "
16588 				 "stale-refresh-time=%u)",
16589 				 view->staleanswerttl, stale_ttl,
16590 				 stale_refresh);
16591 			CHECK(putstr(text, msg));
16592 		}
16593 		found = true;
16594 	}
16595 
16596 	if (!found) {
16597 		result = ISC_R_NOTFOUND;
16598 	}
16599 
16600 cleanup:
16601 	if (exclusive) {
16602 		isc_task_endexclusive(named_g_server->task);
16603 	}
16604 
16605 	if (isc_buffer_usedlength(*text) > 0) {
16606 		(void)putnull(text);
16607 	}
16608 
16609 	return (result);
16610 }
16611