1 /* $NetBSD: server.c,v 1.20 2023/06/26 22:02:59 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*! \file */
17
18 #include <ctype.h>
19 #include <inttypes.h>
20 #include <limits.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #ifdef HAVE_DNSTAP
28 #include <fstrm.h>
29 #endif
30
31 #include <isc/aes.h>
32 #include <isc/app.h>
33 #include <isc/base64.h>
34 #include <isc/commandline.h>
35 #include <isc/dir.h>
36 #include <isc/file.h>
37 #include <isc/hash.h>
38 #include <isc/hex.h>
39 #include <isc/hmac.h>
40 #include <isc/httpd.h>
41 #include <isc/lex.h>
42 #include <isc/meminfo.h>
43 #include <isc/netmgr.h>
44 #include <isc/nonce.h>
45 #include <isc/parseint.h>
46 #include <isc/platform.h>
47 #include <isc/portset.h>
48 #include <isc/print.h>
49 #include <isc/refcount.h>
50 #include <isc/resource.h>
51 #include <isc/siphash.h>
52 #include <isc/socket.h>
53 #include <isc/stat.h>
54 #include <isc/stats.h>
55 #include <isc/stdio.h>
56 #include <isc/string.h>
57 #include <isc/task.h>
58 #include <isc/timer.h>
59 #include <isc/util.h>
60
61 #include <dns/adb.h>
62 #include <dns/badcache.h>
63 #include <dns/cache.h>
64 #include <dns/catz.h>
65 #include <dns/db.h>
66 #include <dns/dispatch.h>
67 #include <dns/dlz.h>
68 #include <dns/dns64.h>
69 #include <dns/dnsrps.h>
70 #include <dns/dnssec.h>
71 #include <dns/dyndb.h>
72 #include <dns/events.h>
73 #include <dns/fixedname.h>
74 #include <dns/forward.h>
75 #include <dns/geoip.h>
76 #include <dns/journal.h>
77 #include <dns/kasp.h>
78 #include <dns/keymgr.h>
79 #include <dns/keytable.h>
80 #include <dns/keyvalues.h>
81 #include <dns/lib.h>
82 #include <dns/master.h>
83 #include <dns/masterdump.h>
84 #include <dns/nsec3.h>
85 #include <dns/nta.h>
86 #include <dns/order.h>
87 #include <dns/peer.h>
88 #include <dns/portlist.h>
89 #include <dns/private.h>
90 #include <dns/rbt.h>
91 #include <dns/rdataclass.h>
92 #include <dns/rdatalist.h>
93 #include <dns/rdataset.h>
94 #include <dns/rdatastruct.h>
95 #include <dns/resolver.h>
96 #include <dns/rootns.h>
97 #include <dns/rriterator.h>
98 #include <dns/secalg.h>
99 #include <dns/soa.h>
100 #include <dns/stats.h>
101 #include <dns/time.h>
102 #include <dns/tkey.h>
103 #include <dns/tsig.h>
104 #include <dns/ttl.h>
105 #include <dns/view.h>
106 #include <dns/zone.h>
107 #include <dns/zt.h>
108
109 #include <dst/dst.h>
110 #include <dst/result.h>
111
112 #include <isccfg/grammar.h>
113 #include <isccfg/kaspconf.h>
114 #include <isccfg/namedconf.h>
115
116 #include <ns/client.h>
117 #include <ns/hooks.h>
118 #include <ns/interfacemgr.h>
119 #include <ns/listenlist.h>
120
121 #include <bind9/check.h>
122
123 #include <named/config.h>
124 #include <named/control.h>
125 #if defined(HAVE_GEOIP2)
126 #include <named/geoip.h>
127 #endif /* HAVE_GEOIP2 */
128 #include <named/log.h>
129 #include <named/logconf.h>
130 #include <named/main.h>
131 #include <named/os.h>
132 #include <named/server.h>
133 #include <named/statschannel.h>
134 #include <named/tkeyconf.h>
135 #include <named/tsigconf.h>
136 #include <named/zoneconf.h>
137 #ifdef HAVE_LIBSCF
138 #include <stdlib.h>
139
140 #include <named/smf_globals.h>
141 #endif /* ifdef HAVE_LIBSCF */
142
143 #ifdef HAVE_LMDB
144 #include <lmdb.h>
145
146 #include <dns/lmdb.h>
147 #define count_newzones count_newzones_db
148 #define configure_newzones configure_newzones_db
149 #define dumpzone dumpzone_db
150 #else /* HAVE_LMDB */
151 #define count_newzones count_newzones_file
152 #define configure_newzones configure_newzones_file
153 #define dumpzone dumpzone_file
154 #endif /* HAVE_LMDB */
155
156 #ifndef SIZE_MAX
157 #define SIZE_MAX ((size_t)-1)
158 #endif /* ifndef SIZE_MAX */
159
160 #ifndef SIZE_AS_PERCENT
161 #define SIZE_AS_PERCENT ((size_t)-2)
162 #endif /* ifndef SIZE_AS_PERCENT */
163
164 #ifdef TUNE_LARGE
165 #define RESOLVER_NTASKS_PERCPU 32
166 #define UDPBUFFERS 32768
167 #define EXCLBUFFERS 32768
168 #else
169 #define RESOLVER_NTASKS_PERCPU 8
170 #define UDPBUFFERS 1000
171 #define EXCLBUFFERS 4096
172 #endif /* TUNE_LARGE */
173
174 /* RFC7828 defines timeout as 16-bit value specified in units of 100
175 * milliseconds, so the maximum and minimum advertised and keepalive
176 * timeouts are capped by the data type (it's ~109 minutes)
177 */
178 #define MIN_INITIAL_TIMEOUT UINT32_C(2500) /* 2.5 seconds */
179 #define MAX_INITIAL_TIMEOUT UINT32_C(120000) /* 2 minutes */
180 #define MIN_IDLE_TIMEOUT UINT32_C(100) /* 0.1 seconds */
181 #define MAX_IDLE_TIMEOUT UINT32_C(120000) /* 2 minutes */
182 #define MIN_KEEPALIVE_TIMEOUT UINT32_C(100) /* 0.1 seconds */
183 #define MAX_KEEPALIVE_TIMEOUT UINT32_C(UINT16_MAX * 100)
184 #define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */
185 #define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100)
186
187 /*%
188 * Check an operation for failure. Assumes that the function
189 * using it has a 'result' variable and a 'cleanup' label.
190 */
191 #define CHECK(op) \
192 do { \
193 result = (op); \
194 if (result != ISC_R_SUCCESS) \
195 goto cleanup; \
196 } while (0)
197
198 #define TCHECK(op) \
199 do { \
200 tresult = (op); \
201 if (tresult != ISC_R_SUCCESS) { \
202 isc_buffer_clear(*text); \
203 goto cleanup; \
204 } \
205 } while (0)
206
207 #define CHECKM(op, msg) \
208 do { \
209 result = (op); \
210 if (result != ISC_R_SUCCESS) { \
211 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
212 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, \
213 "%s: %s", msg, \
214 isc_result_totext(result)); \
215 goto cleanup; \
216 } \
217 } while (0)
218
219 #define CHECKMF(op, msg, file) \
220 do { \
221 result = (op); \
222 if (result != ISC_R_SUCCESS) { \
223 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, \
224 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, \
225 "%s '%s': %s", msg, file, \
226 isc_result_totext(result)); \
227 goto cleanup; \
228 } \
229 } while (0)
230
231 #define CHECKFATAL(op, msg) \
232 do { \
233 result = (op); \
234 if (result != ISC_R_SUCCESS) \
235 fatal(server, msg, result); \
236 } while (0)
237
238 /*%
239 * Maximum ADB size for views that share a cache. Use this limit to suppress
240 * the total of memory footprint, which should be the main reason for sharing
241 * a cache. Only effective when a finite max-cache-size is specified.
242 * This is currently defined to be 8MB.
243 */
244 #define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
245
246 struct named_dispatch {
247 isc_sockaddr_t addr;
248 unsigned int dispatchgen;
249 dns_dispatch_t *dispatch;
250 ISC_LINK(struct named_dispatch) link;
251 };
252
253 struct named_cache {
254 dns_cache_t *cache;
255 dns_view_t *primaryview;
256 bool needflush;
257 bool adbsizeadjusted;
258 dns_rdataclass_t rdclass;
259 ISC_LINK(named_cache_t) link;
260 };
261
262 struct dumpcontext {
263 isc_mem_t *mctx;
264 bool dumpcache;
265 bool dumpzones;
266 bool dumpadb;
267 bool dumpbad;
268 bool dumpexpired;
269 bool dumpfail;
270 FILE *fp;
271 ISC_LIST(struct viewlistentry) viewlist;
272 struct viewlistentry *view;
273 struct zonelistentry *zone;
274 dns_dumpctx_t *mdctx;
275 dns_db_t *db;
276 dns_db_t *cache;
277 isc_task_t *task;
278 dns_dbversion_t *version;
279 };
280
281 struct viewlistentry {
282 dns_view_t *view;
283 ISC_LINK(struct viewlistentry) link;
284 ISC_LIST(struct zonelistentry) zonelist;
285 };
286
287 struct zonelistentry {
288 dns_zone_t *zone;
289 ISC_LINK(struct zonelistentry) link;
290 };
291
292 /*%
293 * Configuration context to retain for each view that allows
294 * new zones to be added at runtime.
295 */
296 typedef struct ns_cfgctx {
297 isc_mem_t *mctx;
298 cfg_parser_t *conf_parser;
299 cfg_parser_t *add_parser;
300 cfg_obj_t *config;
301 cfg_obj_t *vconfig;
302 cfg_obj_t *nzf_config;
303 cfg_aclconfctx_t *actx;
304 } ns_cfgctx_t;
305
306 /*%
307 * A function to write out added-zone configuration to the new_zone_file
308 * specified in 'view'. Maybe called by delete_zoneconf().
309 */
310 typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
311
312 /*%
313 * Holds state information for the initial zone loading process.
314 * Uses the isc_refcount structure to count the number of views
315 * with pending zone loads, dereferencing as each view finishes.
316 */
317 typedef struct {
318 named_server_t *server;
319 bool reconfig;
320 isc_refcount_t refs;
321 } ns_zoneload_t;
322
323 typedef struct {
324 named_server_t *server;
325 } catz_cb_data_t;
326
327 typedef struct catz_chgzone_event {
328 ISC_EVENT_COMMON(struct catz_chgzone_event);
329 dns_catz_entry_t *entry;
330 dns_catz_zone_t *origin;
331 dns_view_t *view;
332 catz_cb_data_t *cbd;
333 bool mod;
334 } catz_chgzone_event_t;
335
336 typedef struct {
337 unsigned int magic;
338 #define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
339 isc_buffer_t **text;
340 isc_result_t result;
341 } ns_dzarg_t;
342
343 /*
344 * These zones should not leak onto the Internet.
345 */
346 const char *empty_zones[] = {
347 /* RFC 1918 */
348 "10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
349 "18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
350 "21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
351 "24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
352 "27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
353 "30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
354
355 /* RFC 6598 */
356 "64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
357 "67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
358 "70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
359 "73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
360 "76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
361 "79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
362 "82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
363 "85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
364 "88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
365 "91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
366 "94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
367 "97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
368 "100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA", "102.100.IN-ADDR.ARPA",
369 "103.100.IN-ADDR.ARPA", "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
370 "106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA", "108.100.IN-ADDR.ARPA",
371 "109.100.IN-ADDR.ARPA", "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
372 "112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA", "114.100.IN-ADDR.ARPA",
373 "115.100.IN-ADDR.ARPA", "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
374 "118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA", "120.100.IN-ADDR.ARPA",
375 "121.100.IN-ADDR.ARPA", "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
376 "124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA", "126.100.IN-ADDR.ARPA",
377 "127.100.IN-ADDR.ARPA",
378
379 /* RFC 5735 and RFC 5737 */
380 "0.IN-ADDR.ARPA", /* THIS NETWORK */
381 "127.IN-ADDR.ARPA", /* LOOPBACK */
382 "254.169.IN-ADDR.ARPA", /* LINK LOCAL */
383 "2.0.192.IN-ADDR.ARPA", /* TEST NET */
384 "100.51.198.IN-ADDR.ARPA", /* TEST NET 2 */
385 "113.0.203.IN-ADDR.ARPA", /* TEST NET 3 */
386 "255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
387
388 /* Local IPv6 Unicast Addresses */
389 "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6."
390 "ARPA",
391 "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6."
392 "ARPA",
393 /* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
394 "D.F.IP6.ARPA", "8.E.F.IP6.ARPA", /* LINK LOCAL */
395 "9.E.F.IP6.ARPA", /* LINK LOCAL */
396 "A.E.F.IP6.ARPA", /* LINK LOCAL */
397 "B.E.F.IP6.ARPA", /* LINK LOCAL */
398
399 /* Example Prefix, RFC 3849. */
400 "8.B.D.0.1.0.0.2.IP6.ARPA",
401
402 /* RFC 7534 */
403 "EMPTY.AS112.ARPA",
404
405 /* RFC 8375 */
406 "HOME.ARPA",
407
408 NULL
409 };
410
411 ISC_PLATFORM_NORETURN_PRE static void
412 fatal(named_server_t *server, const char *msg,
413 isc_result_t result) ISC_PLATFORM_NORETURN_POST;
414
415 static void
416 named_server_reload(isc_task_t *task, isc_event_t *event);
417
418 static isc_result_t
419 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
420 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
421 uint16_t family, ns_listenelt_t **target);
422 static isc_result_t
423 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
424 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
425 uint16_t family, ns_listenlist_t **target);
426
427 static isc_result_t
428 configure_forward(const cfg_obj_t *config, dns_view_t *view,
429 const dns_name_t *origin, const cfg_obj_t *forwarders,
430 const cfg_obj_t *forwardtype);
431
432 static isc_result_t
433 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
434 const cfg_obj_t *alternates);
435
436 static isc_result_t
437 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
438 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
439 dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
440 cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
441 bool modify);
442
443 static void
444 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
445 dns_view_t *view);
446
447 static isc_result_t
448 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
449 isc_mem_t *mctx, cfg_aclconfctx_t *actx);
450
451 static isc_result_t
452 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
453
454 static void
455 end_reserved_dispatches(named_server_t *server, bool all);
456
457 static void
458 newzone_cfgctx_destroy(void **cfgp);
459
460 static isc_result_t
461 putstr(isc_buffer_t **b, const char *str);
462
463 static isc_result_t
464 putmem(isc_buffer_t **b, const char *str, size_t len);
465
466 static isc_result_t
467 putuint8(isc_buffer_t **b, uint8_t val);
468
469 static isc_result_t
470 putnull(isc_buffer_t **b);
471
472 static int
473 count_zones(const cfg_obj_t *conf);
474
475 #ifdef HAVE_LMDB
476 static isc_result_t
477 migrate_nzf(dns_view_t *view);
478
479 static isc_result_t
480 nzd_writable(dns_view_t *view);
481
482 static isc_result_t
483 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
484
485 static isc_result_t
486 nzd_env_reopen(dns_view_t *view);
487
488 static void
489 nzd_env_close(dns_view_t *view);
490
491 static isc_result_t
492 nzd_close(MDB_txn **txnp, bool commit);
493
494 static isc_result_t
495 nzd_count(dns_view_t *view, int *countp);
496 #else /* ifdef HAVE_LMDB */
497 static isc_result_t
498 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
499 #endif /* ifdef HAVE_LMDB */
500
501 /*%
502 * Configure a single view ACL at '*aclp'. Get its configuration from
503 * 'vconfig' (for per-view configuration) and maybe from 'config'
504 */
505 static isc_result_t
configure_view_acl(const cfg_obj_t * vconfig,const cfg_obj_t * config,const cfg_obj_t * gconfig,const char * aclname,const char * acltuplename,cfg_aclconfctx_t * actx,isc_mem_t * mctx,dns_acl_t ** aclp)506 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
507 const cfg_obj_t *gconfig, const char *aclname,
508 const char *acltuplename, cfg_aclconfctx_t *actx,
509 isc_mem_t *mctx, dns_acl_t **aclp) {
510 isc_result_t result;
511 const cfg_obj_t *maps[4];
512 const cfg_obj_t *aclobj = NULL;
513 int i = 0;
514
515 if (*aclp != NULL) {
516 dns_acl_detach(aclp);
517 }
518 if (vconfig != NULL) {
519 maps[i++] = cfg_tuple_get(vconfig, "options");
520 }
521 if (config != NULL) {
522 const cfg_obj_t *options = NULL;
523 (void)cfg_map_get(config, "options", &options);
524 if (options != NULL) {
525 maps[i++] = options;
526 }
527 }
528 if (gconfig != NULL) {
529 const cfg_obj_t *options = NULL;
530 (void)cfg_map_get(gconfig, "options", &options);
531 if (options != NULL) {
532 maps[i++] = options;
533 }
534 }
535 maps[i] = NULL;
536
537 (void)named_config_get(maps, aclname, &aclobj);
538 if (aclobj == NULL) {
539 /*
540 * No value available. *aclp == NULL.
541 */
542 return (ISC_R_SUCCESS);
543 }
544
545 if (acltuplename != NULL) {
546 /*
547 * If the ACL is given in an optional tuple, retrieve it.
548 * The parser should have ensured that a valid object be
549 * returned.
550 */
551 aclobj = cfg_tuple_get(aclobj, acltuplename);
552 }
553
554 result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 0,
555 aclp);
556
557 return (result);
558 }
559
560 /*%
561 * Configure a sortlist at '*aclp'. Essentially the same as
562 * configure_view_acl() except it calls cfg_acl_fromconfig with a
563 * nest_level value of 2.
564 */
565 static isc_result_t
configure_view_sortlist(const cfg_obj_t * vconfig,const cfg_obj_t * config,cfg_aclconfctx_t * actx,isc_mem_t * mctx,dns_acl_t ** aclp)566 configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
567 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
568 dns_acl_t **aclp) {
569 isc_result_t result;
570 const cfg_obj_t *maps[3];
571 const cfg_obj_t *aclobj = NULL;
572 int i = 0;
573
574 if (*aclp != NULL) {
575 dns_acl_detach(aclp);
576 }
577 if (vconfig != NULL) {
578 maps[i++] = cfg_tuple_get(vconfig, "options");
579 }
580 if (config != NULL) {
581 const cfg_obj_t *options = NULL;
582 (void)cfg_map_get(config, "options", &options);
583 if (options != NULL) {
584 maps[i++] = options;
585 }
586 }
587 maps[i] = NULL;
588
589 (void)named_config_get(maps, "sortlist", &aclobj);
590 if (aclobj == NULL) {
591 return (ISC_R_SUCCESS);
592 }
593
594 /*
595 * Use a nest level of 3 for the "top level" of the sortlist;
596 * this means each entry in the top three levels will be stored
597 * as lists of separate, nested ACLs, rather than merged together
598 * into IP tables as is usually done with ACLs.
599 */
600 result = cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx, mctx, 3,
601 aclp);
602
603 return (result);
604 }
605
606 static isc_result_t
configure_view_nametable(const cfg_obj_t * vconfig,const cfg_obj_t * config,const char * confname,const char * conftuplename,isc_mem_t * mctx,dns_rbt_t ** rbtp)607 configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
608 const char *confname, const char *conftuplename,
609 isc_mem_t *mctx, dns_rbt_t **rbtp) {
610 isc_result_t result;
611 const cfg_obj_t *maps[3];
612 const cfg_obj_t *obj = NULL;
613 const cfg_listelt_t *element;
614 int i = 0;
615 dns_fixedname_t fixed;
616 dns_name_t *name;
617 isc_buffer_t b;
618 const char *str;
619 const cfg_obj_t *nameobj;
620
621 if (*rbtp != NULL) {
622 dns_rbt_destroy(rbtp);
623 }
624 if (vconfig != NULL) {
625 maps[i++] = cfg_tuple_get(vconfig, "options");
626 }
627 if (config != NULL) {
628 const cfg_obj_t *options = NULL;
629 (void)cfg_map_get(config, "options", &options);
630 if (options != NULL) {
631 maps[i++] = options;
632 }
633 }
634 maps[i] = NULL;
635
636 (void)named_config_get(maps, confname, &obj);
637 if (obj == NULL) {
638 /*
639 * No value available. *rbtp == NULL.
640 */
641 return (ISC_R_SUCCESS);
642 }
643
644 if (conftuplename != NULL) {
645 obj = cfg_tuple_get(obj, conftuplename);
646 if (cfg_obj_isvoid(obj)) {
647 return (ISC_R_SUCCESS);
648 }
649 }
650
651 result = dns_rbt_create(mctx, NULL, NULL, rbtp);
652 if (result != ISC_R_SUCCESS) {
653 return (result);
654 }
655
656 name = dns_fixedname_initname(&fixed);
657 for (element = cfg_list_first(obj); element != NULL;
658 element = cfg_list_next(element))
659 {
660 nameobj = cfg_listelt_value(element);
661 str = cfg_obj_asstring(nameobj);
662 isc_buffer_constinit(&b, str, strlen(str));
663 isc_buffer_add(&b, strlen(str));
664 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
665 /*
666 * We don't need the node data, but need to set dummy data to
667 * avoid a partial match with an empty node. For example, if
668 * we have foo.example.com and bar.example.com, we'd get a match
669 * for baz.example.com, which is not the expected result.
670 * We simply use (void *)1 as the dummy data.
671 */
672 result = dns_rbt_addname(*rbtp, name, (void *)1);
673 if (result != ISC_R_SUCCESS) {
674 cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
675 "failed to add %s for %s: %s", str,
676 confname, isc_result_totext(result));
677 goto cleanup;
678 }
679 }
680
681 return (result);
682
683 cleanup:
684 dns_rbt_destroy(rbtp);
685 return (result);
686 }
687
688 static isc_result_t
ta_fromconfig(const cfg_obj_t * key,bool * initialp,const char ** namestrp,unsigned char * digest,dns_rdata_ds_t * ds)689 ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp,
690 unsigned char *digest, dns_rdata_ds_t *ds) {
691 isc_result_t result;
692 dns_rdata_dnskey_t keystruct;
693 dns_rdata_t rdata = DNS_RDATA_INIT;
694 uint32_t rdata1, rdata2, rdata3;
695 const char *datastr = NULL, *namestr = NULL;
696 unsigned char data[4096];
697 isc_buffer_t databuf;
698 unsigned char rrdata[4096];
699 isc_buffer_t rrdatabuf;
700 isc_region_t r;
701 dns_fixedname_t fname;
702 dns_name_t *name = NULL;
703 isc_buffer_t namebuf;
704 const char *atstr = NULL;
705 enum {
706 INIT_DNSKEY,
707 STATIC_DNSKEY,
708 INIT_DS,
709 STATIC_DS,
710 TRUSTED
711 } anchortype;
712
713 REQUIRE(namestrp != NULL && *namestrp == NULL);
714 REQUIRE(ds != NULL);
715
716 /* if DNSKEY, flags; if DS, key tag */
717 rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1"));
718
719 /* if DNSKEY, protocol; if DS, algorithm */
720 rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2"));
721
722 /* if DNSKEY, algorithm; if DS, digest type */
723 rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3"));
724
725 namestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
726 *namestrp = namestr;
727
728 name = dns_fixedname_initname(&fname);
729 isc_buffer_constinit(&namebuf, namestr, strlen(namestr));
730 isc_buffer_add(&namebuf, strlen(namestr));
731 CHECK(dns_name_fromtext(name, &namebuf, dns_rootname, 0, NULL));
732
733 if (*initialp) {
734 atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype"));
735
736 if (strcasecmp(atstr, "static-key") == 0) {
737 *initialp = false;
738 anchortype = STATIC_DNSKEY;
739 } else if (strcasecmp(atstr, "static-ds") == 0) {
740 *initialp = false;
741 anchortype = STATIC_DS;
742 } else if (strcasecmp(atstr, "initial-key") == 0) {
743 anchortype = INIT_DNSKEY;
744 } else if (strcasecmp(atstr, "initial-ds") == 0) {
745 anchortype = INIT_DS;
746 } else {
747 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
748 "key '%s': "
749 "invalid initialization method '%s'",
750 namestr, atstr);
751 result = ISC_R_FAILURE;
752 goto cleanup;
753 }
754 } else {
755 anchortype = TRUSTED;
756 }
757
758 isc_buffer_init(&databuf, data, sizeof(data));
759 isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
760
761 *ds = (dns_rdata_ds_t){ .common.rdclass = dns_rdataclass_in,
762 .common.rdtype = dns_rdatatype_ds };
763
764 ISC_LINK_INIT(&ds->common, link);
765
766 switch (anchortype) {
767 case INIT_DNSKEY:
768 case STATIC_DNSKEY:
769 case TRUSTED:
770 /*
771 * This function should never be reached for view
772 * class other than IN
773 */
774 keystruct.common.rdclass = dns_rdataclass_in;
775 keystruct.common.rdtype = dns_rdatatype_dnskey;
776
777 /*
778 * The key data in keystruct is not dynamically allocated.
779 */
780 keystruct.mctx = NULL;
781
782 ISC_LINK_INIT(&keystruct.common, link);
783
784 if (rdata1 > 0xffff) {
785 CHECKM(ISC_R_RANGE, "key flags");
786 }
787 if (rdata1 & DNS_KEYFLAG_REVOKE) {
788 CHECKM(DST_R_BADKEYTYPE, "key flags revoke bit set");
789 }
790 if (rdata2 > 0xff) {
791 CHECKM(ISC_R_RANGE, "key protocol");
792 }
793 if (rdata3 > 0xff) {
794 CHECKM(ISC_R_RANGE, "key algorithm");
795 }
796
797 keystruct.flags = (uint16_t)rdata1;
798 keystruct.protocol = (uint8_t)rdata2;
799 keystruct.algorithm = (uint8_t)rdata3;
800
801 if (!dst_algorithm_supported(keystruct.algorithm)) {
802 CHECK(DST_R_UNSUPPORTEDALG);
803 }
804
805 datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
806 CHECK(isc_base64_decodestring(datastr, &databuf));
807 isc_buffer_usedregion(&databuf, &r);
808 keystruct.datalen = r.length;
809 keystruct.data = r.base;
810
811 CHECK(dns_rdata_fromstruct(&rdata, keystruct.common.rdclass,
812 keystruct.common.rdtype, &keystruct,
813 &rrdatabuf));
814 CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
815 digest, ds));
816 break;
817
818 case INIT_DS:
819 case STATIC_DS:
820 if (rdata1 > 0xffff) {
821 CHECKM(ISC_R_RANGE, "key tag");
822 }
823 if (rdata2 > 0xff) {
824 CHECKM(ISC_R_RANGE, "key algorithm");
825 }
826 if (rdata3 > 0xff) {
827 CHECKM(ISC_R_RANGE, "digest type");
828 }
829
830 ds->key_tag = (uint16_t)rdata1;
831 ds->algorithm = (uint8_t)rdata2;
832 ds->digest_type = (uint8_t)rdata3;
833
834 datastr = cfg_obj_asstring(cfg_tuple_get(key, "data"));
835 CHECK(isc_hex_decodestring(datastr, &databuf));
836 isc_buffer_usedregion(&databuf, &r);
837
838 switch (ds->digest_type) {
839 case DNS_DSDIGEST_SHA1:
840 if (r.length != ISC_SHA1_DIGESTLENGTH) {
841 CHECK(ISC_R_UNEXPECTEDEND);
842 }
843 break;
844 case DNS_DSDIGEST_SHA256:
845 if (r.length != ISC_SHA256_DIGESTLENGTH) {
846 CHECK(ISC_R_UNEXPECTEDEND);
847 }
848 break;
849 case DNS_DSDIGEST_SHA384:
850 if (r.length != ISC_SHA384_DIGESTLENGTH) {
851 CHECK(ISC_R_UNEXPECTEDEND);
852 }
853 break;
854 default:
855 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
856 "key '%s': "
857 "unknown ds digest type %u",
858 namestr, ds->digest_type);
859 result = ISC_R_FAILURE;
860 goto cleanup;
861 break;
862 }
863
864 ds->length = r.length;
865 ds->digest = digest;
866 memmove(ds->digest, r.base, r.length);
867
868 break;
869
870 default:
871 UNREACHABLE();
872 }
873
874 return (ISC_R_SUCCESS);
875
876 cleanup:
877 return (result);
878 }
879
880 /*%
881 * Parse 'key' in the context of view configuration 'vconfig'. If successful,
882 * add the key to 'secroots' if both of the following conditions are true:
883 *
884 * - 'keyname_match' is NULL or it matches the owner name of 'key',
885 * - support for the algorithm used by 'key' is not disabled by 'resolver'
886 * for the owner name of 'key'.
887 *
888 * 'managed' is true for managed keys and false for trusted keys. 'mctx' is
889 * the memory context to use for allocating memory.
890 */
891 static isc_result_t
process_key(const cfg_obj_t * key,dns_keytable_t * secroots,const dns_name_t * keyname_match,dns_resolver_t * resolver,bool managed)892 process_key(const cfg_obj_t *key, dns_keytable_t *secroots,
893 const dns_name_t *keyname_match, dns_resolver_t *resolver,
894 bool managed) {
895 dns_fixedname_t fkeyname;
896 dns_name_t *keyname = NULL;
897 const char *namestr = NULL;
898 dns_rdata_ds_t ds;
899 isc_result_t result;
900 bool initializing = managed;
901 unsigned char digest[ISC_MAX_MD_SIZE];
902 isc_buffer_t b;
903
904 result = ta_fromconfig(key, &initializing, &namestr, digest, &ds);
905
906 switch (result) {
907 case ISC_R_SUCCESS:
908 /*
909 * Trust anchor was parsed correctly.
910 */
911 isc_buffer_constinit(&b, namestr, strlen(namestr));
912 isc_buffer_add(&b, strlen(namestr));
913 keyname = dns_fixedname_initname(&fkeyname);
914 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
915 if (result != ISC_R_SUCCESS) {
916 return (result);
917 }
918 break;
919 case DST_R_UNSUPPORTEDALG:
920 case DST_R_BADKEYTYPE:
921 /*
922 * Key was parsed correctly, but it cannot be used; this is not
923 * a fatal error - log a warning about this key being ignored,
924 * but do not prevent any further ones from being processed.
925 */
926 cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
927 "ignoring %s for '%s': %s",
928 initializing ? "initial-key" : "static-key",
929 namestr, isc_result_totext(result));
930 return (ISC_R_SUCCESS);
931 case DST_R_NOCRYPTO:
932 /*
933 * Crypto support is not available.
934 */
935 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
936 "ignoring %s for '%s': no crypto support",
937 initializing ? "initial-key" : "static-key",
938 namestr);
939 return (result);
940 default:
941 /*
942 * Something unexpected happened; we have no choice but to
943 * indicate an error so that the configuration loading process
944 * is interrupted.
945 */
946 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
947 "configuring %s for '%s': %s",
948 initializing ? "initial-key" : "static-key",
949 namestr, isc_result_totext(result));
950 return (ISC_R_FAILURE);
951 }
952
953 /*
954 * If the caller requested to only load keys for a specific name and
955 * the owner name of this key does not match the requested name, do not
956 * load it.
957 */
958 if (keyname_match != NULL && !dns_name_equal(keyname_match, keyname)) {
959 goto done;
960 }
961
962 /*
963 * Ensure that 'resolver' allows using the algorithm of this key for
964 * its owner name. If it does not, do not load the key and log a
965 * warning, but do not prevent further keys from being processed.
966 */
967 if (!dns_resolver_algorithm_supported(resolver, keyname, ds.algorithm))
968 {
969 cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
970 "ignoring %s for '%s': algorithm is disabled",
971 initializing ? "initial-key" : "static-key",
972 namestr);
973 goto done;
974 }
975
976 /*
977 * Add the key to 'secroots'. Keys from a "trust-anchors" or
978 * "managed-keys" statement may be either static or initializing
979 * keys. If it's not initializing, we don't want to treat it as
980 * managed, so we use 'initializing' twice here, for both the
981 * 'managed' and 'initializing' arguments to dns_keytable_add().
982 */
983 result = dns_keytable_add(secroots, initializing, initializing, keyname,
984 &ds);
985
986 done:
987 return (result);
988 }
989
990 /*
991 * Load keys from configuration into key table. If 'keyname' is specified,
992 * only load keys matching that name. If 'managed' is true, load the key as
993 * an initializing key.
994 */
995 static isc_result_t
load_view_keys(const cfg_obj_t * keys,dns_view_t * view,bool managed,const dns_name_t * keyname)996 load_view_keys(const cfg_obj_t *keys, dns_view_t *view, bool managed,
997 const dns_name_t *keyname) {
998 const cfg_listelt_t *elt, *elt2;
999 const cfg_obj_t *keylist;
1000 isc_result_t result;
1001 dns_keytable_t *secroots = NULL;
1002
1003 CHECK(dns_view_getsecroots(view, &secroots));
1004
1005 for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt))
1006 {
1007 keylist = cfg_listelt_value(elt);
1008
1009 for (elt2 = cfg_list_first(keylist); elt2 != NULL;
1010 elt2 = cfg_list_next(elt2))
1011 {
1012 CHECK(process_key(cfg_listelt_value(elt2), secroots,
1013 keyname, view->resolver, managed));
1014 }
1015 }
1016
1017 cleanup:
1018 if (secroots != NULL) {
1019 dns_keytable_detach(&secroots);
1020 }
1021 if (result == DST_R_NOCRYPTO) {
1022 result = ISC_R_SUCCESS;
1023 }
1024 return (result);
1025 }
1026
1027 /*%
1028 * Check whether a key has been successfully loaded.
1029 */
1030 static bool
keyloaded(dns_view_t * view,const dns_name_t * name)1031 keyloaded(dns_view_t *view, const dns_name_t *name) {
1032 isc_result_t result;
1033 dns_keytable_t *secroots = NULL;
1034 dns_keynode_t *keynode = NULL;
1035
1036 result = dns_view_getsecroots(view, &secroots);
1037 if (result != ISC_R_SUCCESS) {
1038 return (false);
1039 }
1040
1041 result = dns_keytable_find(secroots, name, &keynode);
1042
1043 if (keynode != NULL) {
1044 dns_keytable_detachkeynode(secroots, &keynode);
1045 }
1046 if (secroots != NULL) {
1047 dns_keytable_detach(&secroots);
1048 }
1049
1050 return (result == ISC_R_SUCCESS);
1051 }
1052
1053 /*%
1054 * Configure DNSSEC keys for a view.
1055 *
1056 * The per-view configuration values and the server-global defaults are read
1057 * from 'vconfig' and 'config'.
1058 */
1059 static isc_result_t
configure_view_dnsseckeys(dns_view_t * view,const cfg_obj_t * vconfig,const cfg_obj_t * config,const cfg_obj_t * bindkeys,bool auto_root,isc_mem_t * mctx)1060 configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
1061 const cfg_obj_t *config, const cfg_obj_t *bindkeys,
1062 bool auto_root, isc_mem_t *mctx) {
1063 isc_result_t result = ISC_R_SUCCESS;
1064 const cfg_obj_t *view_keys = NULL;
1065 const cfg_obj_t *global_keys = NULL;
1066 const cfg_obj_t *view_managed_keys = NULL;
1067 const cfg_obj_t *view_trust_anchors = NULL;
1068 const cfg_obj_t *global_managed_keys = NULL;
1069 const cfg_obj_t *global_trust_anchors = NULL;
1070 const cfg_obj_t *maps[4];
1071 const cfg_obj_t *voptions = NULL;
1072 const cfg_obj_t *options = NULL;
1073 const cfg_obj_t *obj = NULL;
1074 const char *directory;
1075 int i = 0;
1076
1077 /* We don't need trust anchors for the _bind view */
1078 if (strcmp(view->name, "_bind") == 0 &&
1079 view->rdclass == dns_rdataclass_chaos)
1080 {
1081 return (ISC_R_SUCCESS);
1082 }
1083
1084 if (vconfig != NULL) {
1085 voptions = cfg_tuple_get(vconfig, "options");
1086 if (voptions != NULL) {
1087 (void)cfg_map_get(voptions, "trusted-keys", &view_keys);
1088
1089 /* managed-keys and trust-anchors are synonyms. */
1090 (void)cfg_map_get(voptions, "managed-keys",
1091 &view_managed_keys);
1092 (void)cfg_map_get(voptions, "trust-anchors",
1093 &view_trust_anchors);
1094
1095 maps[i++] = voptions;
1096 }
1097 }
1098
1099 if (config != NULL) {
1100 (void)cfg_map_get(config, "trusted-keys", &global_keys);
1101
1102 /* managed-keys and trust-anchors are synonyms. */
1103 (void)cfg_map_get(config, "managed-keys", &global_managed_keys);
1104 (void)cfg_map_get(config, "trust-anchors",
1105 &global_trust_anchors);
1106
1107 (void)cfg_map_get(config, "options", &options);
1108 if (options != NULL) {
1109 maps[i++] = options;
1110 }
1111 }
1112
1113 maps[i++] = named_g_defaults;
1114 maps[i] = NULL;
1115
1116 result = dns_view_initsecroots(view, mctx);
1117 if (result != ISC_R_SUCCESS) {
1118 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1119 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1120 "couldn't create keytable");
1121 return (ISC_R_UNEXPECTED);
1122 }
1123
1124 result = dns_view_initntatable(view, named_g_taskmgr, named_g_timermgr);
1125 if (result != ISC_R_SUCCESS) {
1126 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1127 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1128 "couldn't create NTA table");
1129 return (ISC_R_UNEXPECTED);
1130 }
1131
1132 if (auto_root && view->rdclass == dns_rdataclass_in) {
1133 const cfg_obj_t *builtin_keys = NULL;
1134
1135 /*
1136 * If bind.keys exists and is populated, it overrides
1137 * the trust-anchors clause hard-coded in named_g_config.
1138 */
1139 if (bindkeys != NULL) {
1140 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1141 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1142 "obtaining root key for view %s "
1143 "from '%s'",
1144 view->name, named_g_server->bindkeysfile);
1145
1146 (void)cfg_map_get(bindkeys, "trust-anchors",
1147 &builtin_keys);
1148
1149 if (builtin_keys == NULL) {
1150 isc_log_write(
1151 named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1152 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
1153 "dnssec-validation auto: "
1154 "WARNING: root zone key "
1155 "not found");
1156 }
1157 }
1158
1159 if (builtin_keys == NULL) {
1160 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1161 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1162 "using built-in root key for view %s",
1163 view->name);
1164
1165 (void)cfg_map_get(named_g_config, "trust-anchors",
1166 &builtin_keys);
1167 }
1168
1169 if (builtin_keys != NULL) {
1170 CHECK(load_view_keys(builtin_keys, view, true,
1171 dns_rootname));
1172 }
1173
1174 if (!keyloaded(view, dns_rootname)) {
1175 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1176 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1177 "root key not loaded");
1178 result = ISC_R_FAILURE;
1179 goto cleanup;
1180 }
1181 }
1182
1183 if (view->rdclass == dns_rdataclass_in) {
1184 CHECK(load_view_keys(view_keys, view, false, NULL));
1185 CHECK(load_view_keys(view_trust_anchors, view, true, NULL));
1186 CHECK(load_view_keys(view_managed_keys, view, true, NULL));
1187
1188 CHECK(load_view_keys(global_keys, view, false, NULL));
1189 CHECK(load_view_keys(global_trust_anchors, view, true, NULL));
1190 CHECK(load_view_keys(global_managed_keys, view, true, NULL));
1191 }
1192
1193 /*
1194 * Add key zone for managed keys.
1195 */
1196 obj = NULL;
1197 (void)named_config_get(maps, "managed-keys-directory", &obj);
1198 directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
1199 if (directory != NULL) {
1200 result = isc_file_isdirectory(directory);
1201 }
1202 if (result != ISC_R_SUCCESS) {
1203 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1204 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1205 "invalid managed-keys-directory %s: %s",
1206 directory, isc_result_totext(result));
1207 goto cleanup;
1208 } else if (directory != NULL) {
1209 if (!isc_file_isdirwritable(directory)) {
1210 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1211 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1212 "managed-keys-directory '%s' "
1213 "is not writable",
1214 directory);
1215 result = ISC_R_NOPERM;
1216 goto cleanup;
1217 }
1218 }
1219
1220 CHECK(add_keydata_zone(view, directory, named_g_mctx));
1221
1222 cleanup:
1223 return (result);
1224 }
1225
1226 static isc_result_t
mustbesecure(const cfg_obj_t * mbs,dns_resolver_t * resolver)1227 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
1228 const cfg_listelt_t *element;
1229 const cfg_obj_t *obj;
1230 const char *str;
1231 dns_fixedname_t fixed;
1232 dns_name_t *name;
1233 bool value;
1234 isc_result_t result;
1235 isc_buffer_t b;
1236
1237 name = dns_fixedname_initname(&fixed);
1238 for (element = cfg_list_first(mbs); element != NULL;
1239 element = cfg_list_next(element))
1240 {
1241 obj = cfg_listelt_value(element);
1242 str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
1243 isc_buffer_constinit(&b, str, strlen(str));
1244 isc_buffer_add(&b, strlen(str));
1245 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1246 value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
1247 CHECK(dns_resolver_setmustbesecure(resolver, name, value));
1248 }
1249
1250 result = ISC_R_SUCCESS;
1251
1252 cleanup:
1253 return (result);
1254 }
1255
1256 /*%
1257 * Get a dispatch appropriate for the resolver of a given view.
1258 */
1259 static isc_result_t
get_view_querysource_dispatch(const cfg_obj_t ** maps,int af,dns_dispatch_t ** dispatchp,isc_dscp_t * dscpp,bool is_firstview)1260 get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
1261 dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
1262 bool is_firstview) {
1263 isc_result_t result = ISC_R_FAILURE;
1264 dns_dispatch_t *disp;
1265 isc_sockaddr_t sa;
1266 unsigned int attrs, attrmask;
1267 const cfg_obj_t *obj = NULL;
1268 unsigned int maxdispatchbuffers = UDPBUFFERS;
1269 isc_dscp_t dscp = -1;
1270
1271 switch (af) {
1272 case AF_INET:
1273 result = named_config_get(maps, "query-source", &obj);
1274 INSIST(result == ISC_R_SUCCESS);
1275 break;
1276 case AF_INET6:
1277 result = named_config_get(maps, "query-source-v6", &obj);
1278 INSIST(result == ISC_R_SUCCESS);
1279 break;
1280 default:
1281 UNREACHABLE();
1282 }
1283
1284 sa = *(cfg_obj_assockaddr(obj));
1285 INSIST(isc_sockaddr_pf(&sa) == af);
1286
1287 dscp = cfg_obj_getdscp(obj);
1288 if (dscp != -1 && dscpp != NULL) {
1289 *dscpp = dscp;
1290 }
1291
1292 /*
1293 * If we don't support this address family, we're done!
1294 */
1295 switch (af) {
1296 case AF_INET:
1297 result = isc_net_probeipv4();
1298 break;
1299 case AF_INET6:
1300 result = isc_net_probeipv6();
1301 break;
1302 default:
1303 UNREACHABLE();
1304 }
1305 if (result != ISC_R_SUCCESS) {
1306 return (ISC_R_SUCCESS);
1307 }
1308
1309 /*
1310 * Try to find a dispatcher that we can share.
1311 */
1312 attrs = 0;
1313 attrs |= DNS_DISPATCHATTR_UDP;
1314 switch (af) {
1315 case AF_INET:
1316 attrs |= DNS_DISPATCHATTR_IPV4;
1317 break;
1318 case AF_INET6:
1319 attrs |= DNS_DISPATCHATTR_IPV6;
1320 break;
1321 }
1322 if (isc_sockaddr_getport(&sa) == 0) {
1323 attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
1324 maxdispatchbuffers = EXCLBUFFERS;
1325 } else {
1326 INSIST(obj != NULL);
1327 if (is_firstview) {
1328 cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
1329 "using specific query-source port "
1330 "suppresses port randomization and can be "
1331 "insecure.");
1332 }
1333 }
1334
1335 attrmask = 0;
1336 attrmask |= DNS_DISPATCHATTR_UDP;
1337 attrmask |= DNS_DISPATCHATTR_TCP;
1338 attrmask |= DNS_DISPATCHATTR_IPV4;
1339 attrmask |= DNS_DISPATCHATTR_IPV6;
1340
1341 disp = NULL;
1342 result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr,
1343 named_g_taskmgr, &sa, 4096,
1344 maxdispatchbuffers, 32768, 16411, 16433,
1345 attrs, attrmask, &disp);
1346 if (result != ISC_R_SUCCESS) {
1347 isc_sockaddr_t any;
1348 char buf[ISC_SOCKADDR_FORMATSIZE];
1349
1350 switch (af) {
1351 case AF_INET:
1352 isc_sockaddr_any(&any);
1353 break;
1354 case AF_INET6:
1355 isc_sockaddr_any6(&any);
1356 break;
1357 }
1358 if (isc_sockaddr_equal(&sa, &any)) {
1359 return (ISC_R_SUCCESS);
1360 }
1361 isc_sockaddr_format(&sa, buf, sizeof(buf));
1362 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1363 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1364 "could not get query source dispatcher (%s)",
1365 buf);
1366 return (result);
1367 }
1368
1369 *dispatchp = disp;
1370
1371 return (ISC_R_SUCCESS);
1372 }
1373
1374 static isc_result_t
configure_order(dns_order_t * order,const cfg_obj_t * ent)1375 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1376 dns_rdataclass_t rdclass;
1377 dns_rdatatype_t rdtype;
1378 const cfg_obj_t *obj;
1379 dns_fixedname_t fixed;
1380 unsigned int mode = 0;
1381 const char *str;
1382 isc_buffer_t b;
1383 isc_result_t result;
1384 bool addroot;
1385
1386 result = named_config_getclass(cfg_tuple_get(ent, "class"),
1387 dns_rdataclass_any, &rdclass);
1388 if (result != ISC_R_SUCCESS) {
1389 return (result);
1390 }
1391
1392 result = named_config_gettype(cfg_tuple_get(ent, "type"),
1393 dns_rdatatype_any, &rdtype);
1394 if (result != ISC_R_SUCCESS) {
1395 return (result);
1396 }
1397
1398 obj = cfg_tuple_get(ent, "name");
1399 if (cfg_obj_isstring(obj)) {
1400 str = cfg_obj_asstring(obj);
1401 } else {
1402 str = "*";
1403 }
1404 addroot = (strcmp(str, "*") == 0);
1405 isc_buffer_constinit(&b, str, strlen(str));
1406 isc_buffer_add(&b, strlen(str));
1407 dns_fixedname_init(&fixed);
1408 result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, dns_rootname,
1409 0, NULL);
1410 if (result != ISC_R_SUCCESS) {
1411 return (result);
1412 }
1413
1414 obj = cfg_tuple_get(ent, "ordering");
1415 INSIST(cfg_obj_isstring(obj));
1416 str = cfg_obj_asstring(obj);
1417 if (!strcasecmp(str, "fixed")) {
1418 #if DNS_RDATASET_FIXED
1419 mode = DNS_RDATASETATTR_FIXEDORDER;
1420 #else /* if DNS_RDATASET_FIXED */
1421 mode = DNS_RDATASETATTR_CYCLIC;
1422 #endif /* DNS_RDATASET_FIXED */
1423 } else if (!strcasecmp(str, "random")) {
1424 mode = DNS_RDATASETATTR_RANDOMIZE;
1425 } else if (!strcasecmp(str, "cyclic")) {
1426 mode = DNS_RDATASETATTR_CYCLIC;
1427 } else if (!strcasecmp(str, "none")) {
1428 mode = DNS_RDATASETATTR_NONE;
1429 } else {
1430 UNREACHABLE();
1431 }
1432
1433 /*
1434 * "*" should match everything including the root (BIND 8 compat).
1435 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1436 * explicit entry for "." when the name is "*".
1437 */
1438 if (addroot) {
1439 result = dns_order_add(order, dns_rootname, rdtype, rdclass,
1440 mode);
1441 if (result != ISC_R_SUCCESS) {
1442 return (result);
1443 }
1444 }
1445
1446 return (dns_order_add(order, dns_fixedname_name(&fixed), rdtype,
1447 rdclass, mode));
1448 }
1449
1450 static isc_result_t
configure_peer(const cfg_obj_t * cpeer,isc_mem_t * mctx,dns_peer_t ** peerp)1451 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1452 isc_netaddr_t na;
1453 dns_peer_t *peer;
1454 const cfg_obj_t *obj;
1455 const char *str;
1456 isc_result_t result;
1457 unsigned int prefixlen;
1458
1459 cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1460
1461 peer = NULL;
1462 result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1463 if (result != ISC_R_SUCCESS) {
1464 return (result);
1465 }
1466
1467 obj = NULL;
1468 (void)cfg_map_get(cpeer, "bogus", &obj);
1469 if (obj != NULL) {
1470 CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1471 }
1472
1473 obj = NULL;
1474 (void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1475 if (obj != NULL) {
1476 CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1477 }
1478
1479 obj = NULL;
1480 (void)cfg_map_get(cpeer, "request-expire", &obj);
1481 if (obj != NULL) {
1482 CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
1483 }
1484
1485 obj = NULL;
1486 (void)cfg_map_get(cpeer, "request-ixfr", &obj);
1487 if (obj != NULL) {
1488 CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1489 }
1490
1491 obj = NULL;
1492 (void)cfg_map_get(cpeer, "request-nsid", &obj);
1493 if (obj != NULL) {
1494 CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1495 }
1496
1497 obj = NULL;
1498 (void)cfg_map_get(cpeer, "send-cookie", &obj);
1499 if (obj != NULL) {
1500 CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj)));
1501 }
1502
1503 obj = NULL;
1504 (void)cfg_map_get(cpeer, "edns", &obj);
1505 if (obj != NULL) {
1506 CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1507 }
1508
1509 obj = NULL;
1510 (void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1511 if (obj != NULL) {
1512 uint32_t udpsize = cfg_obj_asuint32(obj);
1513 if (udpsize < 512U) {
1514 udpsize = 512U;
1515 }
1516 if (udpsize > 4096U) {
1517 udpsize = 4096U;
1518 }
1519 CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize));
1520 }
1521
1522 obj = NULL;
1523 (void)cfg_map_get(cpeer, "edns-version", &obj);
1524 if (obj != NULL) {
1525 uint32_t ednsversion = cfg_obj_asuint32(obj);
1526 if (ednsversion > 255U) {
1527 ednsversion = 255U;
1528 }
1529 CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion));
1530 }
1531
1532 obj = NULL;
1533 (void)cfg_map_get(cpeer, "max-udp-size", &obj);
1534 if (obj != NULL) {
1535 uint32_t udpsize = cfg_obj_asuint32(obj);
1536 if (udpsize < 512U) {
1537 udpsize = 512U;
1538 }
1539 if (udpsize > 4096U) {
1540 udpsize = 4096U;
1541 }
1542 CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize));
1543 }
1544
1545 obj = NULL;
1546 (void)cfg_map_get(cpeer, "padding", &obj);
1547 if (obj != NULL) {
1548 uint32_t padding = cfg_obj_asuint32(obj);
1549 if (padding > 512U) {
1550 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
1551 "server padding value cannot "
1552 "exceed 512: lowering");
1553 padding = 512U;
1554 }
1555 CHECK(dns_peer_setpadding(peer, (uint16_t)padding));
1556 }
1557
1558 obj = NULL;
1559 (void)cfg_map_get(cpeer, "tcp-only", &obj);
1560 if (obj != NULL) {
1561 CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
1562 }
1563
1564 obj = NULL;
1565 (void)cfg_map_get(cpeer, "tcp-keepalive", &obj);
1566 if (obj != NULL) {
1567 CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj)));
1568 }
1569
1570 obj = NULL;
1571 (void)cfg_map_get(cpeer, "transfers", &obj);
1572 if (obj != NULL) {
1573 CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1574 }
1575
1576 obj = NULL;
1577 (void)cfg_map_get(cpeer, "transfer-format", &obj);
1578 if (obj != NULL) {
1579 str = cfg_obj_asstring(obj);
1580 if (strcasecmp(str, "many-answers") == 0) {
1581 CHECK(dns_peer_settransferformat(peer,
1582 dns_many_answers));
1583 } else if (strcasecmp(str, "one-answer") == 0) {
1584 CHECK(dns_peer_settransferformat(peer, dns_one_answer));
1585 } else {
1586 UNREACHABLE();
1587 }
1588 }
1589
1590 obj = NULL;
1591 (void)cfg_map_get(cpeer, "keys", &obj);
1592 if (obj != NULL) {
1593 result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1594 if (result != ISC_R_SUCCESS) {
1595 goto cleanup;
1596 }
1597 }
1598
1599 obj = NULL;
1600 if (na.family == AF_INET) {
1601 (void)cfg_map_get(cpeer, "transfer-source", &obj);
1602 } else {
1603 (void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1604 }
1605 if (obj != NULL) {
1606 result = dns_peer_settransfersource(peer,
1607 cfg_obj_assockaddr(obj));
1608 if (result != ISC_R_SUCCESS) {
1609 goto cleanup;
1610 }
1611 result = dns_peer_settransferdscp(peer, cfg_obj_getdscp(obj));
1612 if (result != ISC_R_SUCCESS) {
1613 goto cleanup;
1614 }
1615 named_add_reserved_dispatch(named_g_server,
1616 cfg_obj_assockaddr(obj));
1617 }
1618
1619 obj = NULL;
1620 if (na.family == AF_INET) {
1621 (void)cfg_map_get(cpeer, "notify-source", &obj);
1622 } else {
1623 (void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1624 }
1625 if (obj != NULL) {
1626 result = dns_peer_setnotifysource(peer,
1627 cfg_obj_assockaddr(obj));
1628 if (result != ISC_R_SUCCESS) {
1629 goto cleanup;
1630 }
1631 result = dns_peer_setnotifydscp(peer, cfg_obj_getdscp(obj));
1632 if (result != ISC_R_SUCCESS) {
1633 goto cleanup;
1634 }
1635 named_add_reserved_dispatch(named_g_server,
1636 cfg_obj_assockaddr(obj));
1637 }
1638
1639 obj = NULL;
1640 if (na.family == AF_INET) {
1641 (void)cfg_map_get(cpeer, "query-source", &obj);
1642 } else {
1643 (void)cfg_map_get(cpeer, "query-source-v6", &obj);
1644 }
1645 if (obj != NULL) {
1646 result = dns_peer_setquerysource(peer, cfg_obj_assockaddr(obj));
1647 if (result != ISC_R_SUCCESS) {
1648 goto cleanup;
1649 }
1650 result = dns_peer_setquerydscp(peer, cfg_obj_getdscp(obj));
1651 if (result != ISC_R_SUCCESS) {
1652 goto cleanup;
1653 }
1654 named_add_reserved_dispatch(named_g_server,
1655 cfg_obj_assockaddr(obj));
1656 }
1657
1658 *peerp = peer;
1659 return (ISC_R_SUCCESS);
1660
1661 cleanup:
1662 dns_peer_detach(&peer);
1663 return (result);
1664 }
1665
1666 #ifdef HAVE_DLOPEN
1667 static isc_result_t
configure_dyndb(const cfg_obj_t * dyndb,isc_mem_t * mctx,const dns_dyndbctx_t * dctx)1668 configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
1669 const dns_dyndbctx_t *dctx) {
1670 isc_result_t result = ISC_R_SUCCESS;
1671 const cfg_obj_t *obj;
1672 const char *name, *library;
1673
1674 /* Get the name of the dyndb instance and the library path . */
1675 name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name"));
1676 library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library"));
1677
1678 obj = cfg_tuple_get(dyndb, "parameters");
1679 if (obj != NULL) {
1680 result = dns_dyndb_load(library, name, cfg_obj_asstring(obj),
1681 cfg_obj_file(obj), cfg_obj_line(obj),
1682 mctx, dctx);
1683 }
1684
1685 if (result != ISC_R_SUCCESS) {
1686 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1687 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1688 "dynamic database '%s' configuration failed: %s",
1689 name, isc_result_totext(result));
1690 }
1691 return (result);
1692 }
1693 #endif /* ifdef HAVE_DLOPEN */
1694
1695 static isc_result_t
disable_algorithms(const cfg_obj_t * disabled,dns_resolver_t * resolver)1696 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1697 isc_result_t result;
1698 const cfg_obj_t *algorithms;
1699 const cfg_listelt_t *element;
1700 const char *str;
1701 dns_fixedname_t fixed;
1702 dns_name_t *name;
1703 isc_buffer_t b;
1704
1705 name = dns_fixedname_initname(&fixed);
1706 str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1707 isc_buffer_constinit(&b, str, strlen(str));
1708 isc_buffer_add(&b, strlen(str));
1709 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1710
1711 algorithms = cfg_tuple_get(disabled, "algorithms");
1712 for (element = cfg_list_first(algorithms); element != NULL;
1713 element = cfg_list_next(element))
1714 {
1715 isc_textregion_t r;
1716 dns_secalg_t alg;
1717
1718 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1719 r.length = strlen(r.base);
1720
1721 result = dns_secalg_fromtext(&alg, &r);
1722 if (result != ISC_R_SUCCESS) {
1723 uint8_t ui;
1724 result = isc_parse_uint8(&ui, r.base, 10);
1725 alg = ui;
1726 }
1727 if (result != ISC_R_SUCCESS) {
1728 cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1729 ISC_LOG_ERROR, "invalid algorithm");
1730 CHECK(result);
1731 }
1732 CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1733 }
1734 cleanup:
1735 return (result);
1736 }
1737
1738 static isc_result_t
disable_ds_digests(const cfg_obj_t * disabled,dns_resolver_t * resolver)1739 disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1740 isc_result_t result;
1741 const cfg_obj_t *digests;
1742 const cfg_listelt_t *element;
1743 const char *str;
1744 dns_fixedname_t fixed;
1745 dns_name_t *name;
1746 isc_buffer_t b;
1747
1748 name = dns_fixedname_initname(&fixed);
1749 str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1750 isc_buffer_constinit(&b, str, strlen(str));
1751 isc_buffer_add(&b, strlen(str));
1752 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1753
1754 digests = cfg_tuple_get(disabled, "digests");
1755 for (element = cfg_list_first(digests); element != NULL;
1756 element = cfg_list_next(element))
1757 {
1758 isc_textregion_t r;
1759 dns_dsdigest_t digest;
1760
1761 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1762 r.length = strlen(r.base);
1763
1764 /* disable_ds_digests handles numeric values. */
1765 result = dns_dsdigest_fromtext(&digest, &r);
1766 if (result != ISC_R_SUCCESS) {
1767 cfg_obj_log(cfg_listelt_value(element), named_g_lctx,
1768 ISC_LOG_ERROR, "invalid algorithm");
1769 CHECK(result);
1770 }
1771 CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
1772 }
1773 cleanup:
1774 return (result);
1775 }
1776
1777 static bool
on_disable_list(const cfg_obj_t * disablelist,dns_name_t * zonename)1778 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1779 const cfg_listelt_t *element;
1780 dns_fixedname_t fixed;
1781 dns_name_t *name;
1782 isc_result_t result;
1783 const cfg_obj_t *value;
1784 const char *str;
1785 isc_buffer_t b;
1786
1787 name = dns_fixedname_initname(&fixed);
1788
1789 for (element = cfg_list_first(disablelist); element != NULL;
1790 element = cfg_list_next(element))
1791 {
1792 value = cfg_listelt_value(element);
1793 str = cfg_obj_asstring(value);
1794 isc_buffer_constinit(&b, str, strlen(str));
1795 isc_buffer_add(&b, strlen(str));
1796 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
1797 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1798 if (dns_name_equal(name, zonename)) {
1799 return (true);
1800 }
1801 }
1802 return (false);
1803 }
1804
1805 static isc_result_t
check_dbtype(dns_zone_t * zone,unsigned int dbtypec,const char ** dbargv,isc_mem_t * mctx)1806 check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
1807 isc_mem_t *mctx) {
1808 char **argv = NULL;
1809 unsigned int i;
1810 isc_result_t result = ISC_R_SUCCESS;
1811
1812 CHECK(dns_zone_getdbtype(zone, &argv, mctx));
1813
1814 /*
1815 * Check that all the arguments match.
1816 */
1817 for (i = 0; i < dbtypec; i++) {
1818 if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
1819 CHECK(ISC_R_FAILURE);
1820
1821 /*
1822 * Check that there are not extra arguments.
1823 */
1824 }
1825 }
1826
1827 /*
1828 * Check that there are not extra arguments.
1829 */
1830 if (i == dbtypec && argv[i] != NULL) {
1831 result = ISC_R_FAILURE;
1832 }
1833
1834 cleanup:
1835 isc_mem_free(mctx, argv);
1836 return (result);
1837 }
1838
1839 static isc_result_t
setquerystats(dns_zone_t * zone,isc_mem_t * mctx,dns_zonestat_level_t level)1840 setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
1841 isc_result_t result;
1842 isc_stats_t *zoneqrystats;
1843
1844 dns_zone_setstatlevel(zone, level);
1845
1846 zoneqrystats = NULL;
1847 if (level == dns_zonestat_full) {
1848 result = isc_stats_create(mctx, &zoneqrystats,
1849 ns_statscounter_max);
1850 if (result != ISC_R_SUCCESS) {
1851 return (result);
1852 }
1853 }
1854 dns_zone_setrequeststats(zone, zoneqrystats);
1855 if (zoneqrystats != NULL) {
1856 isc_stats_detach(&zoneqrystats);
1857 }
1858
1859 return (ISC_R_SUCCESS);
1860 }
1861
1862 static named_cache_t *
cachelist_find(named_cachelist_t * cachelist,const char * cachename,dns_rdataclass_t rdclass)1863 cachelist_find(named_cachelist_t *cachelist, const char *cachename,
1864 dns_rdataclass_t rdclass) {
1865 named_cache_t *nsc;
1866
1867 for (nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
1868 nsc = ISC_LIST_NEXT(nsc, link))
1869 {
1870 if (nsc->rdclass == rdclass &&
1871 strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1872 {
1873 return (nsc);
1874 }
1875 }
1876
1877 return (NULL);
1878 }
1879
1880 static bool
cache_reusable(dns_view_t * originview,dns_view_t * view,bool new_zero_no_soattl)1881 cache_reusable(dns_view_t *originview, dns_view_t *view,
1882 bool new_zero_no_soattl) {
1883 if (originview->rdclass != view->rdclass ||
1884 originview->checknames != view->checknames ||
1885 dns_resolver_getzeronosoattl(originview->resolver) !=
1886 new_zero_no_soattl ||
1887 originview->acceptexpired != view->acceptexpired ||
1888 originview->enablevalidation != view->enablevalidation ||
1889 originview->maxcachettl != view->maxcachettl ||
1890 originview->maxncachettl != view->maxncachettl)
1891 {
1892 return (false);
1893 }
1894
1895 return (true);
1896 }
1897
1898 static bool
cache_sharable(dns_view_t * originview,dns_view_t * view,bool new_zero_no_soattl,uint64_t new_max_cache_size,uint32_t new_stale_ttl,uint32_t new_stale_refresh_time)1899 cache_sharable(dns_view_t *originview, dns_view_t *view,
1900 bool new_zero_no_soattl, uint64_t new_max_cache_size,
1901 uint32_t new_stale_ttl, uint32_t new_stale_refresh_time) {
1902 /*
1903 * If the cache cannot even reused for the same view, it cannot be
1904 * shared with other views.
1905 */
1906 if (!cache_reusable(originview, view, new_zero_no_soattl)) {
1907 return (false);
1908 }
1909
1910 /*
1911 * Check other cache related parameters that must be consistent among
1912 * the sharing views.
1913 */
1914 if (dns_cache_getservestalettl(originview->cache) != new_stale_ttl ||
1915 dns_cache_getservestalerefresh(originview->cache) !=
1916 new_stale_refresh_time ||
1917 dns_cache_getcachesize(originview->cache) != new_max_cache_size)
1918 {
1919 return (false);
1920 }
1921
1922 return (true);
1923 }
1924
1925 /*
1926 * Callback from DLZ configure when the driver sets up a writeable zone
1927 */
1928 static isc_result_t
dlzconfigure_callback(dns_view_t * view,dns_dlzdb_t * dlzdb,dns_zone_t * zone)1929 dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
1930 dns_name_t *origin = dns_zone_getorigin(zone);
1931 dns_rdataclass_t zclass = view->rdclass;
1932 isc_result_t result;
1933
1934 result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
1935 if (result != ISC_R_SUCCESS) {
1936 return (result);
1937 }
1938 dns_zone_setstats(zone, named_g_server->zonestats);
1939
1940 return (named_zone_configure_writeable_dlz(dlzdb, zone, zclass,
1941 origin));
1942 }
1943
1944 static isc_result_t
dns64_reverse(dns_view_t * view,isc_mem_t * mctx,isc_netaddr_t * na,unsigned int prefixlen,const char * server,const char * contact)1945 dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1946 unsigned int prefixlen, const char *server, const char *contact) {
1947 char reverse[48 + sizeof("ip6.arpa.")] = { 0 };
1948 char buf[sizeof("x.x.")];
1949 const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1950 const char *sep = ": view ";
1951 const char *viewname = view->name;
1952 const unsigned char *s6;
1953 dns_fixedname_t fixed;
1954 dns_name_t *name;
1955 dns_zone_t *zone = NULL;
1956 int dns64_dbtypec = 4;
1957 isc_buffer_t b;
1958 isc_result_t result;
1959
1960 REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1961 prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1962
1963 if (!strcmp(viewname, "_default")) {
1964 sep = "";
1965 viewname = "";
1966 }
1967
1968 /*
1969 * Construct the reverse name of the zone.
1970 */
1971 s6 = na->type.in6.s6_addr;
1972 while (prefixlen > 0) {
1973 prefixlen -= 8;
1974 snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen / 8] & 0xf,
1975 (s6[prefixlen / 8] >> 4) & 0xf);
1976 strlcat(reverse, buf, sizeof(reverse));
1977 }
1978 strlcat(reverse, "ip6.arpa.", sizeof(reverse));
1979
1980 /*
1981 * Create the actual zone.
1982 */
1983 if (server != NULL) {
1984 dns64_dbtype[2] = server;
1985 }
1986 if (contact != NULL) {
1987 dns64_dbtype[3] = contact;
1988 }
1989 name = dns_fixedname_initname(&fixed);
1990 isc_buffer_constinit(&b, reverse, strlen(reverse));
1991 isc_buffer_add(&b, strlen(reverse));
1992 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1993 CHECK(dns_zone_create(&zone, mctx));
1994 CHECK(dns_zone_setorigin(zone, name));
1995 dns_zone_setview(zone, view);
1996 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
1997 dns_zone_setclass(zone, view->rdclass);
1998 dns_zone_settype(zone, dns_zone_primary);
1999 dns_zone_setstats(zone, named_g_server->zonestats);
2000 dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype);
2001 if (view->queryacl != NULL) {
2002 dns_zone_setqueryacl(zone, view->queryacl);
2003 }
2004 if (view->queryonacl != NULL) {
2005 dns_zone_setqueryonacl(zone, view->queryonacl);
2006 }
2007 dns_zone_setdialup(zone, dns_dialuptype_no);
2008 dns_zone_setnotifytype(zone, dns_notifytype_no);
2009 dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
2010 CHECK(setquerystats(zone, mctx, dns_zonestat_none)); /* XXXMPA */
2011 CHECK(dns_view_addzone(view, zone));
2012 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2013 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
2014 "dns64 reverse zone%s%s: %s", sep, viewname, reverse);
2015
2016 cleanup:
2017 if (zone != NULL) {
2018 dns_zone_detach(&zone);
2019 }
2020 return (result);
2021 }
2022
2023 #ifdef USE_DNSRPS
2024 typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
2025 struct conf_dnsrps_ctx {
2026 isc_result_t result;
2027 char *cstr;
2028 size_t cstr_size;
2029 isc_mem_t *mctx;
2030 };
2031
2032 /*
2033 * Add to the DNSRPS configuration string.
2034 */
2035 static bool
conf_dnsrps_sadd(conf_dnsrps_ctx_t * ctx,const char * p,...)2036 conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
2037 size_t new_len, cur_len, new_cstr_size;
2038 char *new_cstr;
2039 va_list args;
2040
2041 if (ctx->cstr == NULL) {
2042 ctx->cstr = isc_mem_get(ctx->mctx, 256);
2043 ctx->cstr[0] = '\0';
2044 ctx->cstr_size = 256;
2045 }
2046
2047 cur_len = strlen(ctx->cstr);
2048 va_start(args, p);
2049 new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p,
2050 args) +
2051 1;
2052 va_end(args);
2053
2054 if (cur_len + new_len <= ctx->cstr_size) {
2055 return (true);
2056 }
2057
2058 new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256;
2059 new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
2060
2061 memmove(new_cstr, ctx->cstr, cur_len);
2062 isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
2063 ctx->cstr_size = new_cstr_size;
2064 ctx->cstr = new_cstr;
2065
2066 /* cannot use args twice after a single va_start()on some systems */
2067 va_start(args, p);
2068 vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
2069 va_end(args);
2070 return (true);
2071 }
2072
2073 /*
2074 * Get an DNSRPS configuration value using the global and view options
2075 * for the default. Return false upon failure.
2076 */
2077 static bool
conf_dnsrps_get(const cfg_obj_t ** sub_obj,const cfg_obj_t ** maps,const cfg_obj_t * obj,const char * name,conf_dnsrps_ctx_t * ctx)2078 conf_dnsrps_get(const cfg_obj_t **sub_obj, const cfg_obj_t **maps,
2079 const cfg_obj_t *obj, const char *name,
2080 conf_dnsrps_ctx_t *ctx) {
2081 if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
2082 *sub_obj = NULL;
2083 return (false);
2084 }
2085
2086 *sub_obj = cfg_tuple_get(obj, name);
2087 if (cfg_obj_isvoid(*sub_obj)) {
2088 *sub_obj = NULL;
2089 if (maps != NULL &&
2090 ISC_R_SUCCESS != named_config_get(maps, name, sub_obj))
2091 {
2092 *sub_obj = NULL;
2093 }
2094 }
2095 return (true);
2096 }
2097
2098 /*
2099 * Handle a DNSRPS boolean configuration value with the global and view
2100 * options providing the default.
2101 */
2102 static void
conf_dnsrps_yes_no(const cfg_obj_t * obj,const char * name,conf_dnsrps_ctx_t * ctx)2103 conf_dnsrps_yes_no(const cfg_obj_t *obj, const char *name,
2104 conf_dnsrps_ctx_t *ctx) {
2105 const cfg_obj_t *sub_obj;
2106
2107 if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2108 return;
2109 }
2110 if (sub_obj == NULL) {
2111 return;
2112 }
2113 if (ctx == NULL) {
2114 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2115 "\"%s\" without \"dnsrps-enable yes\"", name);
2116 return;
2117 }
2118
2119 conf_dnsrps_sadd(ctx, " %s %s", name,
2120 cfg_obj_asboolean(sub_obj) ? "yes" : "no");
2121 }
2122
2123 static void
conf_dnsrps_num(const cfg_obj_t * obj,const char * name,conf_dnsrps_ctx_t * ctx)2124 conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
2125 conf_dnsrps_ctx_t *ctx) {
2126 const cfg_obj_t *sub_obj;
2127
2128 if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx)) {
2129 return;
2130 }
2131 if (sub_obj == NULL) {
2132 return;
2133 }
2134 if (ctx == NULL) {
2135 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
2136 "\"%s\" without \"dnsrps-enable yes\"", name);
2137 return;
2138 }
2139
2140 if (cfg_obj_isduration(sub_obj)) {
2141 conf_dnsrps_sadd(ctx, " %s %d", name,
2142 cfg_obj_asduration(sub_obj));
2143 } else {
2144 conf_dnsrps_sadd(ctx, " %s %d", name,
2145 cfg_obj_asuint32(sub_obj));
2146 }
2147 }
2148
2149 /*
2150 * Convert the parsed RPZ configuration statement to a string for
2151 * dns_rpz_new_zones().
2152 */
2153 static isc_result_t
conf_dnsrps(dns_view_t * view,const cfg_obj_t ** maps,bool nsip_enabled,bool nsdname_enabled,dns_rpz_zbits_t * nsip_on,dns_rpz_zbits_t * nsdname_on,char ** rps_cstr,size_t * rps_cstr_size,const cfg_obj_t * rpz_obj,const cfg_listelt_t * zone_element)2154 conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps, bool nsip_enabled,
2155 bool nsdname_enabled, dns_rpz_zbits_t *nsip_on,
2156 dns_rpz_zbits_t *nsdname_on, char **rps_cstr, size_t *rps_cstr_size,
2157 const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element) {
2158 conf_dnsrps_ctx_t ctx;
2159 const cfg_obj_t *zone_obj, *obj;
2160 dns_rpz_num_t rpz_num;
2161 bool on;
2162 const char *s;
2163
2164 memset(&ctx, 0, sizeof(ctx));
2165 ctx.result = ISC_R_SUCCESS;
2166 ctx.mctx = view->mctx;
2167
2168 for (rpz_num = 0; zone_element != NULL && ctx.result == ISC_R_SUCCESS;
2169 ++rpz_num)
2170 {
2171 zone_obj = cfg_listelt_value(zone_element);
2172
2173 s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
2174 conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
2175
2176 obj = cfg_tuple_get(zone_obj, "policy");
2177 if (!cfg_obj_isvoid(obj)) {
2178 s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2179 conf_dnsrps_sadd(&ctx, " policy %s", s);
2180 if (strcasecmp(s, "cname") == 0) {
2181 s = cfg_obj_asstring(
2182 cfg_tuple_get(obj, "cname"));
2183 conf_dnsrps_sadd(&ctx, " %s", s);
2184 }
2185 }
2186
2187 conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
2188 conf_dnsrps_yes_no(zone_obj, "log", &ctx);
2189 conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
2190 obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2191 if (!cfg_obj_isvoid(obj)) {
2192 if (cfg_obj_asboolean(obj)) {
2193 *nsip_on |= DNS_RPZ_ZBIT(rpz_num);
2194 } else {
2195 *nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
2196 }
2197 }
2198 on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2199 if (nsip_enabled != on) {
2200 conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes "
2201 : " nsip-enable no ");
2202 }
2203 obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2204 if (!cfg_obj_isvoid(obj)) {
2205 if (cfg_obj_asboolean(obj)) {
2206 *nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
2207 } else {
2208 *nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
2209 }
2210 }
2211 on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2212 if (nsdname_enabled != on) {
2213 conf_dnsrps_sadd(&ctx, on ? " nsdname-enable yes "
2214 : " nsdname-enable no ");
2215 }
2216 conf_dnsrps_sadd(&ctx, ";\n");
2217 zone_element = cfg_list_next(zone_element);
2218 }
2219
2220 conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
2221 conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
2222 conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
2223 conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
2224 conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
2225 if (!nsip_enabled) {
2226 conf_dnsrps_sadd(&ctx, " nsip-enable no ");
2227 }
2228 if (!nsdname_enabled) {
2229 conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
2230 }
2231
2232 /*
2233 * Get the general dnsrpzd parameters from the response-policy
2234 * statement in the view and the general options.
2235 */
2236 if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
2237 obj != NULL)
2238 {
2239 conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
2240 }
2241
2242 if (ctx.result == ISC_R_SUCCESS) {
2243 *rps_cstr = ctx.cstr;
2244 *rps_cstr_size = ctx.cstr_size;
2245 } else {
2246 if (ctx.cstr != NULL) {
2247 isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
2248 }
2249 *rps_cstr = NULL;
2250 *rps_cstr_size = 0;
2251 }
2252 return (ctx.result);
2253 }
2254 #endif /* ifdef USE_DNSRPS */
2255
2256 static isc_result_t
configure_rpz_name(dns_view_t * view,const cfg_obj_t * obj,dns_name_t * name,const char * str,const char * msg)2257 configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2258 const char *str, const char *msg) {
2259 isc_result_t result;
2260
2261 result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx);
2262 if (result != ISC_R_SUCCESS) {
2263 cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2264 "invalid %s '%s'", msg, str);
2265 }
2266 return (result);
2267 }
2268
2269 static isc_result_t
configure_rpz_name2(dns_view_t * view,const cfg_obj_t * obj,dns_name_t * name,const char * str,const dns_name_t * origin)2270 configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2271 const char *str, const dns_name_t *origin) {
2272 isc_result_t result;
2273
2274 result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE,
2275 view->mctx);
2276 if (result != ISC_R_SUCCESS) {
2277 cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2278 "invalid zone '%s'", str);
2279 }
2280 return (result);
2281 }
2282
2283 static isc_result_t
configure_rpz_zone(dns_view_t * view,const cfg_listelt_t * element,bool recursive_only_default,bool add_soa_default,dns_ttl_t ttl_default,uint32_t minupdateinterval_default,const dns_rpz_zone_t * old,bool * old_rpz_okp)2284 configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
2285 bool recursive_only_default, bool add_soa_default,
2286 dns_ttl_t ttl_default, uint32_t minupdateinterval_default,
2287 const dns_rpz_zone_t *old, bool *old_rpz_okp) {
2288 const cfg_obj_t *rpz_obj, *obj;
2289 const char *str;
2290 dns_rpz_zone_t *zone = NULL;
2291 isc_result_t result;
2292 dns_rpz_num_t rpz_num;
2293
2294 REQUIRE(old != NULL || !*old_rpz_okp);
2295
2296 rpz_obj = cfg_listelt_value(element);
2297
2298 if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
2299 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2300 "limit of %d response policy zones exceeded",
2301 DNS_RPZ_MAX_ZONES);
2302 return (ISC_R_FAILURE);
2303 }
2304
2305 result = dns_rpz_new_zone(view->rpzs, &zone);
2306 if (result != ISC_R_SUCCESS) {
2307 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2308 "Error creating new RPZ zone : %s",
2309 isc_result_totext(result));
2310 return (result);
2311 }
2312
2313 obj = cfg_tuple_get(rpz_obj, "recursive-only");
2314 if (cfg_obj_isvoid(obj) ? recursive_only_default
2315 : cfg_obj_asboolean(obj))
2316 {
2317 view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num);
2318 } else {
2319 view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num);
2320 }
2321
2322 obj = cfg_tuple_get(rpz_obj, "log");
2323 if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) {
2324 view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num);
2325 } else {
2326 view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num);
2327 }
2328
2329 obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2330 if (cfg_obj_isduration(obj)) {
2331 zone->max_policy_ttl = cfg_obj_asduration(obj);
2332 } else {
2333 zone->max_policy_ttl = ttl_default;
2334 }
2335 if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl) {
2336 *old_rpz_okp = false;
2337 }
2338
2339 obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2340 if (cfg_obj_isduration(obj)) {
2341 zone->min_update_interval = cfg_obj_asduration(obj);
2342 } else {
2343 zone->min_update_interval = minupdateinterval_default;
2344 }
2345 if (*old_rpz_okp &&
2346 zone->min_update_interval != old->min_update_interval)
2347 {
2348 *old_rpz_okp = false;
2349 }
2350
2351 str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
2352 result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone");
2353 if (result != ISC_R_SUCCESS) {
2354 return (result);
2355 }
2356 if (dns_name_equal(&zone->origin, dns_rootname)) {
2357 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2358 "invalid zone name '%s'", str);
2359 return (DNS_R_EMPTYLABEL);
2360 }
2361 if (!view->rpzs->p.dnsrps_enabled) {
2362 for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1;
2363 ++rpz_num)
2364 {
2365 if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
2366 &zone->origin))
2367 {
2368 cfg_obj_log(rpz_obj, named_g_lctx,
2369 DNS_RPZ_ERROR_LEVEL,
2370 "duplicate '%s'", str);
2371 result = DNS_R_DUPLICATE;
2372 return (result);
2373 }
2374 }
2375 }
2376 if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) {
2377 *old_rpz_okp = false;
2378 }
2379
2380 result = configure_rpz_name2(view, rpz_obj, &zone->client_ip,
2381 DNS_RPZ_CLIENT_IP_ZONE, &zone->origin);
2382 if (result != ISC_R_SUCCESS) {
2383 return (result);
2384 }
2385
2386 result = configure_rpz_name2(view, rpz_obj, &zone->ip, DNS_RPZ_IP_ZONE,
2387 &zone->origin);
2388 if (result != ISC_R_SUCCESS) {
2389 return (result);
2390 }
2391
2392 result = configure_rpz_name2(view, rpz_obj, &zone->nsdname,
2393 DNS_RPZ_NSDNAME_ZONE, &zone->origin);
2394 if (result != ISC_R_SUCCESS) {
2395 return (result);
2396 }
2397
2398 result = configure_rpz_name2(view, rpz_obj, &zone->nsip,
2399 DNS_RPZ_NSIP_ZONE, &zone->origin);
2400 if (result != ISC_R_SUCCESS) {
2401 return (result);
2402 }
2403
2404 result = configure_rpz_name(view, rpz_obj, &zone->passthru,
2405 DNS_RPZ_PASSTHRU_NAME, "name");
2406 if (result != ISC_R_SUCCESS) {
2407 return (result);
2408 }
2409
2410 result = configure_rpz_name(view, rpz_obj, &zone->drop,
2411 DNS_RPZ_DROP_NAME, "name");
2412 if (result != ISC_R_SUCCESS) {
2413 return (result);
2414 }
2415
2416 result = configure_rpz_name(view, rpz_obj, &zone->tcp_only,
2417 DNS_RPZ_TCP_ONLY_NAME, "name");
2418 if (result != ISC_R_SUCCESS) {
2419 return (result);
2420 }
2421
2422 obj = cfg_tuple_get(rpz_obj, "policy");
2423 if (cfg_obj_isvoid(obj)) {
2424 zone->policy = DNS_RPZ_POLICY_GIVEN;
2425 } else {
2426 str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2427 zone->policy = dns_rpz_str2policy(str);
2428 INSIST(zone->policy != DNS_RPZ_POLICY_ERROR);
2429 if (zone->policy == DNS_RPZ_POLICY_CNAME) {
2430 str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
2431 result = configure_rpz_name(view, rpz_obj, &zone->cname,
2432 str, "cname");
2433 if (result != ISC_R_SUCCESS) {
2434 return (result);
2435 }
2436 }
2437 }
2438 if (*old_rpz_okp && (zone->policy != old->policy ||
2439 !dns_name_equal(&old->cname, &zone->cname)))
2440 {
2441 *old_rpz_okp = false;
2442 }
2443
2444 obj = cfg_tuple_get(rpz_obj, "add-soa");
2445 if (cfg_obj_isvoid(obj)) {
2446 zone->addsoa = add_soa_default;
2447 } else {
2448 zone->addsoa = cfg_obj_asboolean(obj);
2449 }
2450 if (*old_rpz_okp && zone->addsoa != old->addsoa) {
2451 *old_rpz_okp = false;
2452 }
2453
2454 return (ISC_R_SUCCESS);
2455 }
2456
2457 static isc_result_t
configure_rpz(dns_view_t * view,dns_view_t * pview,const cfg_obj_t ** maps,const cfg_obj_t * rpz_obj,bool * old_rpz_okp)2458 configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
2459 const cfg_obj_t *rpz_obj, bool *old_rpz_okp) {
2460 bool dnsrps_enabled;
2461 const cfg_listelt_t *zone_element;
2462 char *rps_cstr;
2463 size_t rps_cstr_size;
2464 const cfg_obj_t *sub_obj;
2465 bool recursive_only_default, add_soa_default;
2466 bool nsip_enabled, nsdname_enabled;
2467 dns_rpz_zbits_t nsip_on, nsdname_on;
2468 dns_ttl_t ttl_default;
2469 uint32_t minupdateinterval_default;
2470 dns_rpz_zones_t *zones;
2471 const dns_rpz_zones_t *old;
2472 bool pview_must_detach = false;
2473 const dns_rpz_zone_t *old_zone;
2474 isc_result_t result;
2475 int i;
2476
2477 *old_rpz_okp = false;
2478
2479 zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
2480 if (zone_element == NULL) {
2481 return (ISC_R_SUCCESS);
2482 }
2483
2484 nsip_enabled = true;
2485 sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2486 if (!cfg_obj_isvoid(sub_obj)) {
2487 nsip_enabled = cfg_obj_asboolean(sub_obj);
2488 }
2489 nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2490
2491 nsdname_enabled = true;
2492 sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2493 if (!cfg_obj_isvoid(sub_obj)) {
2494 nsdname_enabled = cfg_obj_asboolean(sub_obj);
2495 }
2496 nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2497
2498 /*
2499 * "dnsrps-enable yes|no" can be either a global or response-policy
2500 * clause.
2501 */
2502 dnsrps_enabled = false;
2503 rps_cstr = NULL;
2504 rps_cstr_size = 0;
2505 sub_obj = NULL;
2506 (void)named_config_get(maps, "dnsrps-enable", &sub_obj);
2507 if (sub_obj != NULL) {
2508 dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2509 }
2510 sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
2511 if (!cfg_obj_isvoid(sub_obj)) {
2512 dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2513 }
2514 #ifndef USE_DNSRPS
2515 if (dnsrps_enabled) {
2516 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2517 "\"dnsrps-enable yes\" but"
2518 " without `./configure --enable-dnsrps`");
2519 return (ISC_R_FAILURE);
2520 }
2521 #else /* ifndef USE_DNSRPS */
2522 if (dnsrps_enabled) {
2523 if (librpz == NULL) {
2524 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2525 "\"dnsrps-enable yes\" but %s",
2526 librpz_lib_open_emsg.c);
2527 return (ISC_R_FAILURE);
2528 }
2529
2530 /*
2531 * Generate the DNS Response Policy Service
2532 * configuration string.
2533 */
2534 result = conf_dnsrps(view, maps, nsip_enabled, nsdname_enabled,
2535 &nsip_on, &nsdname_on, &rps_cstr,
2536 &rps_cstr_size, rpz_obj, zone_element);
2537 if (result != ISC_R_SUCCESS) {
2538 return (result);
2539 }
2540 }
2541 #endif /* ifndef USE_DNSRPS */
2542
2543 result = dns_rpz_new_zones(&view->rpzs, rps_cstr, rps_cstr_size,
2544 view->mctx, named_g_taskmgr,
2545 named_g_timermgr);
2546 if (result != ISC_R_SUCCESS) {
2547 return (result);
2548 }
2549
2550 zones = view->rpzs;
2551
2552 zones->p.nsip_on = nsip_on;
2553 zones->p.nsdname_on = nsdname_on;
2554
2555 sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
2556 if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2557 recursive_only_default = false;
2558 } else {
2559 recursive_only_default = true;
2560 }
2561
2562 sub_obj = cfg_tuple_get(rpz_obj, "add-soa");
2563 if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2564 add_soa_default = false;
2565 } else {
2566 add_soa_default = true;
2567 }
2568
2569 sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
2570 if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
2571 zones->p.break_dnssec = true;
2572 } else {
2573 zones->p.break_dnssec = false;
2574 }
2575
2576 sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2577 if (cfg_obj_isduration(sub_obj)) {
2578 ttl_default = cfg_obj_asduration(sub_obj);
2579 } else {
2580 ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
2581 }
2582
2583 sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2584 if (cfg_obj_isduration(sub_obj)) {
2585 minupdateinterval_default = cfg_obj_asduration(sub_obj);
2586 } else {
2587 minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
2588 }
2589
2590 sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
2591 if (cfg_obj_isuint32(sub_obj)) {
2592 zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
2593 } else {
2594 zones->p.min_ns_labels = 2;
2595 }
2596
2597 sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
2598 if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2599 zones->p.qname_wait_recurse = true;
2600 } else {
2601 zones->p.qname_wait_recurse = false;
2602 }
2603
2604 sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse");
2605 if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj)) {
2606 zones->p.nsip_wait_recurse = true;
2607 } else {
2608 zones->p.nsip_wait_recurse = false;
2609 }
2610
2611 if (pview != NULL) {
2612 old = pview->rpzs;
2613 } else {
2614 result = dns_viewlist_find(&named_g_server->viewlist,
2615 view->name, view->rdclass, &pview);
2616 if (result == ISC_R_SUCCESS) {
2617 pview_must_detach = true;
2618 old = pview->rpzs;
2619 } else {
2620 old = NULL;
2621 }
2622 }
2623
2624 if (old == NULL) {
2625 *old_rpz_okp = false;
2626 } else {
2627 *old_rpz_okp = true;
2628 }
2629
2630 for (i = 0; zone_element != NULL;
2631 ++i, zone_element = cfg_list_next(zone_element))
2632 {
2633 INSIST(!*old_rpz_okp || old != NULL);
2634 if (*old_rpz_okp && i < old->p.num_zones) {
2635 old_zone = old->zones[i];
2636 } else {
2637 *old_rpz_okp = false;
2638 old_zone = NULL;
2639 }
2640 result = configure_rpz_zone(
2641 view, zone_element, recursive_only_default,
2642 add_soa_default, ttl_default, minupdateinterval_default,
2643 old_zone, old_rpz_okp);
2644 if (result != ISC_R_SUCCESS) {
2645 if (pview_must_detach) {
2646 dns_view_detach(&pview);
2647 }
2648 return (result);
2649 }
2650 }
2651
2652 /*
2653 * If this is a reloading and the parameters and list of policy
2654 * zones are unchanged, then use the same policy data.
2655 * Data for individual zones that must be reloaded will be merged.
2656 */
2657 if (*old_rpz_okp) {
2658 if (old != NULL &&
2659 memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
2660 {
2661 *old_rpz_okp = false;
2662 } else if ((old == NULL || old->rps_cstr == NULL) !=
2663 (zones->rps_cstr == NULL))
2664 {
2665 *old_rpz_okp = false;
2666 } else if (old != NULL && zones->rps_cstr != NULL &&
2667 strcmp(old->rps_cstr, zones->rps_cstr) != 0)
2668 {
2669 *old_rpz_okp = false;
2670 }
2671 }
2672
2673 if (*old_rpz_okp) {
2674 dns_rpz_detach_rpzs(&view->rpzs);
2675 dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
2676 dns_rpz_detach_rpzs(&pview->rpzs);
2677 } else if (old != NULL && pview != NULL) {
2678 ++pview->rpzs->rpz_ver;
2679 view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
2680 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
2681 "updated RPZ policy: version %d",
2682 view->rpzs->rpz_ver);
2683 }
2684
2685 if (pview_must_detach) {
2686 dns_view_detach(&pview);
2687 }
2688
2689 return (ISC_R_SUCCESS);
2690 }
2691
2692 static void
catz_addmodzone_taskaction(isc_task_t * task,isc_event_t * event0)2693 catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2694 catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2695 isc_result_t result;
2696 isc_buffer_t namebuf;
2697 isc_buffer_t *confbuf;
2698 char nameb[DNS_NAME_FORMATSIZE];
2699 const cfg_obj_t *zlist = NULL;
2700 cfg_obj_t *zoneconf = NULL;
2701 cfg_obj_t *zoneobj = NULL;
2702 ns_cfgctx_t *cfg;
2703 dns_zone_t *zone = NULL;
2704
2705 cfg = (ns_cfgctx_t *)ev->view->new_zone_config;
2706 if (cfg == NULL) {
2707 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2708 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2709 "catz: allow-new-zones statement missing from "
2710 "config; cannot add zone from the catalog");
2711 goto cleanup;
2712 }
2713
2714 isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
2715 dns_name_totext(dns_catz_entry_getname(ev->entry), true, &namebuf);
2716 isc_buffer_putuint8(&namebuf, 0);
2717
2718 /* Zone shouldn't already exist */
2719 result = dns_zt_find(ev->view->zonetable,
2720 dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
2721
2722 if (ev->mod) {
2723 if (result != ISC_R_SUCCESS) {
2724 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2725 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2726 "catz: error \"%s\" while trying to "
2727 "modify zone \"%s\"",
2728 isc_result_totext(result), nameb);
2729 goto cleanup;
2730 } else {
2731 if (!dns_zone_getadded(zone)) {
2732 isc_log_write(
2733 named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2734 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2735 "catz: "
2736 "catz_addmodzone_taskaction: "
2737 "zone '%s' is not a dynamically "
2738 "added zone",
2739 nameb);
2740 goto cleanup;
2741 }
2742 if (dns_zone_get_parentcatz(zone) != ev->origin) {
2743 isc_log_write(
2744 named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2745 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2746 "catz: catz_delzone_taskaction: "
2747 "zone '%s' exists in multiple "
2748 "catalog zones",
2749 nameb);
2750 goto cleanup;
2751 }
2752 dns_zone_detach(&zone);
2753 }
2754 } else {
2755 if (result == ISC_R_SUCCESS) {
2756 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2757 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
2758 "catz: zone \"%s\" is overridden "
2759 "by explicitly configured zone",
2760 nameb);
2761 goto cleanup;
2762 } else if (result != ISC_R_NOTFOUND &&
2763 result != DNS_R_PARTIALMATCH)
2764 {
2765 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2766 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2767 "catz: error \"%s\" while trying to "
2768 "add zone \"%s\"",
2769 isc_result_totext(result), nameb);
2770 goto cleanup;
2771 } else { /* this can happen in case of DNS_R_PARTIALMATCH */
2772 if (zone != NULL) {
2773 dns_zone_detach(&zone);
2774 }
2775 }
2776 }
2777 RUNTIME_CHECK(zone == NULL);
2778 /* Create a config for new zone */
2779 confbuf = NULL;
2780 result = dns_catz_generate_zonecfg(ev->origin, ev->entry, &confbuf);
2781 if (result == ISC_R_SUCCESS) {
2782 cfg_parser_reset(cfg->add_parser);
2783 result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
2784 &cfg_type_addzoneconf, 0, &zoneconf);
2785 isc_buffer_free(&confbuf);
2786 }
2787 /*
2788 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer3()
2789 * failed.
2790 */
2791 if (result != ISC_R_SUCCESS) {
2792 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2793 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2794 "catz: error \"%s\" while trying to generate "
2795 "config for zone \"%s\"",
2796 isc_result_totext(result), nameb);
2797 goto cleanup;
2798 }
2799 CHECK(cfg_map_get(zoneconf, "zone", &zlist));
2800 if (!cfg_obj_islist(zlist)) {
2801 CHECK(ISC_R_FAILURE);
2802 }
2803
2804 /* For now we only support adding one zone at a time */
2805 zoneobj = cfg_listelt_value(cfg_list_first(zlist));
2806
2807 /* Mark view unfrozen so that zone can be added */
2808
2809 result = isc_task_beginexclusive(task);
2810 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2811 dns_view_thaw(ev->view);
2812 result = configure_zone(
2813 cfg->config, zoneobj, cfg->vconfig, ev->cbd->server->mctx,
2814 ev->view, &ev->cbd->server->viewlist,
2815 &ev->cbd->server->kasplist, cfg->actx, true, false, ev->mod);
2816 dns_view_freeze(ev->view);
2817 isc_task_endexclusive(task);
2818
2819 if (result != ISC_R_SUCCESS) {
2820 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2821 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2822 "catz: failed to configure zone \"%s\" - %d",
2823 nameb, result);
2824 goto cleanup;
2825 }
2826
2827 /* Is it there yet? */
2828 CHECK(dns_zt_find(ev->view->zonetable,
2829 dns_catz_entry_getname(ev->entry), 0, NULL, &zone));
2830
2831 /*
2832 * Load the zone from the master file. If this fails, we'll
2833 * need to undo the configuration we've done already.
2834 */
2835 result = dns_zone_load(zone, true);
2836 if (result != ISC_R_SUCCESS) {
2837 dns_db_t *dbp = NULL;
2838 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2839 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2840 "catz: dns_zone_load() failed "
2841 "with %s; reverting.",
2842 isc_result_totext(result));
2843
2844 /* If the zone loaded partially, unload it */
2845 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2846 dns_db_detach(&dbp);
2847 dns_zone_unload(zone);
2848 }
2849
2850 /* Remove the zone from the zone table */
2851 dns_zt_unmount(ev->view->zonetable, zone);
2852 goto cleanup;
2853 }
2854
2855 /* Flag the zone as having been added at runtime */
2856 dns_zone_setadded(zone, true);
2857 dns_zone_set_parentcatz(zone, ev->origin);
2858
2859 cleanup:
2860 if (zone != NULL) {
2861 dns_zone_detach(&zone);
2862 }
2863 if (zoneconf != NULL) {
2864 cfg_obj_destroy(cfg->add_parser, &zoneconf);
2865 }
2866 dns_catz_entry_detach(ev->origin, &ev->entry);
2867 dns_catz_zone_detach(&ev->origin);
2868 dns_view_detach(&ev->view);
2869 isc_event_free(ISC_EVENT_PTR(&ev));
2870 }
2871
2872 static void
catz_delzone_taskaction(isc_task_t * task,isc_event_t * event0)2873 catz_delzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2874 catz_chgzone_event_t *ev = (catz_chgzone_event_t *)event0;
2875 isc_result_t result;
2876 dns_zone_t *zone = NULL;
2877 dns_db_t *dbp = NULL;
2878 char cname[DNS_NAME_FORMATSIZE];
2879 const char *file;
2880
2881 result = isc_task_beginexclusive(task);
2882 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2883
2884 dns_name_format(dns_catz_entry_getname(ev->entry), cname,
2885 DNS_NAME_FORMATSIZE);
2886 result = dns_zt_find(ev->view->zonetable,
2887 dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
2888 if (result != ISC_R_SUCCESS) {
2889 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2890 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2891 "catz: catz_delzone_taskaction: "
2892 "zone '%s' not found",
2893 cname);
2894 goto cleanup;
2895 }
2896
2897 if (!dns_zone_getadded(zone)) {
2898 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2899 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2900 "catz: catz_delzone_taskaction: "
2901 "zone '%s' is not a dynamically added zone",
2902 cname);
2903 goto cleanup;
2904 }
2905
2906 if (dns_zone_get_parentcatz(zone) != ev->origin) {
2907 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2908 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2909 "catz: catz_delzone_taskaction: zone "
2910 "'%s' exists in multiple catalog zones",
2911 cname);
2912 goto cleanup;
2913 }
2914
2915 /* Stop answering for this zone */
2916 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2917 dns_db_detach(&dbp);
2918 dns_zone_unload(zone);
2919 }
2920
2921 CHECK(dns_zt_unmount(ev->view->zonetable, zone));
2922 file = dns_zone_getfile(zone);
2923 if (file != NULL) {
2924 isc_file_remove(file);
2925 file = dns_zone_getjournal(zone);
2926 if (file != NULL) {
2927 isc_file_remove(file);
2928 }
2929 }
2930
2931 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2932 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2933 "catz: catz_delzone_taskaction: "
2934 "zone '%s' deleted",
2935 cname);
2936 cleanup:
2937 isc_task_endexclusive(task);
2938 if (zone != NULL) {
2939 dns_zone_detach(&zone);
2940 }
2941 dns_catz_entry_detach(ev->origin, &ev->entry);
2942 dns_catz_zone_detach(&ev->origin);
2943 dns_view_detach(&ev->view);
2944 isc_event_free(ISC_EVENT_PTR(&ev));
2945 }
2946
2947 static isc_result_t
catz_create_chg_task(dns_catz_entry_t * entry,dns_catz_zone_t * origin,dns_view_t * view,isc_taskmgr_t * taskmgr,void * udata,isc_eventtype_t type)2948 catz_create_chg_task(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
2949 dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata,
2950 isc_eventtype_t type) {
2951 catz_chgzone_event_t *event = NULL;
2952 isc_task_t *task = NULL;
2953 isc_result_t result;
2954 isc_taskaction_t action = NULL;
2955
2956 result = isc_taskmgr_excltask(taskmgr, &task);
2957 if (result != ISC_R_SUCCESS) {
2958 return (result);
2959 }
2960
2961 switch (type) {
2962 case DNS_EVENT_CATZADDZONE:
2963 case DNS_EVENT_CATZMODZONE:
2964 action = catz_addmodzone_taskaction;
2965 break;
2966 case DNS_EVENT_CATZDELZONE:
2967 action = catz_delzone_taskaction;
2968 break;
2969 default:
2970 REQUIRE(0);
2971 UNREACHABLE();
2972 }
2973
2974 event = (catz_chgzone_event_t *)isc_event_allocate(
2975 view->mctx, origin, type, action, NULL, sizeof(*event));
2976
2977 event->cbd = (catz_cb_data_t *)udata;
2978 event->entry = NULL;
2979 event->origin = NULL;
2980 event->view = NULL;
2981 event->mod = (type == DNS_EVENT_CATZMODZONE);
2982
2983 dns_catz_entry_attach(entry, &event->entry);
2984 dns_catz_zone_attach(origin, &event->origin);
2985 dns_view_attach(view, &event->view);
2986
2987 isc_task_send(task, ISC_EVENT_PTR(&event));
2988 isc_task_detach(&task);
2989
2990 return (ISC_R_SUCCESS);
2991 }
2992
2993 static isc_result_t
catz_addzone(dns_catz_entry_t * entry,dns_catz_zone_t * origin,dns_view_t * view,isc_taskmgr_t * taskmgr,void * udata)2994 catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
2995 isc_taskmgr_t *taskmgr, void *udata) {
2996 return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
2997 DNS_EVENT_CATZADDZONE));
2998 }
2999
3000 static isc_result_t
catz_delzone(dns_catz_entry_t * entry,dns_catz_zone_t * origin,dns_view_t * view,isc_taskmgr_t * taskmgr,void * udata)3001 catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3002 isc_taskmgr_t *taskmgr, void *udata) {
3003 return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3004 DNS_EVENT_CATZDELZONE));
3005 }
3006
3007 static isc_result_t
catz_modzone(dns_catz_entry_t * entry,dns_catz_zone_t * origin,dns_view_t * view,isc_taskmgr_t * taskmgr,void * udata)3008 catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin, dns_view_t *view,
3009 isc_taskmgr_t *taskmgr, void *udata) {
3010 return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
3011 DNS_EVENT_CATZMODZONE));
3012 }
3013
3014 static isc_result_t
configure_catz_zone(dns_view_t * view,dns_view_t * pview,const cfg_obj_t * config,const cfg_listelt_t * element)3015 configure_catz_zone(dns_view_t *view, dns_view_t *pview,
3016 const cfg_obj_t *config, const cfg_listelt_t *element) {
3017 const cfg_obj_t *catz_obj, *obj;
3018 dns_catz_zone_t *zone = NULL;
3019 const char *str;
3020 isc_result_t result;
3021 dns_name_t origin;
3022 dns_catz_options_t *opts;
3023
3024 dns_name_init(&origin, NULL);
3025 catz_obj = cfg_listelt_value(element);
3026
3027 str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
3028
3029 result = dns_name_fromstring(&origin, str, DNS_NAME_DOWNCASE,
3030 view->mctx);
3031 if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname)) {
3032 result = DNS_R_EMPTYLABEL;
3033 }
3034
3035 if (result != ISC_R_SUCCESS) {
3036 cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3037 "catz: invalid zone name '%s'", str);
3038 goto cleanup;
3039 }
3040
3041 result = dns_catz_add_zone(view->catzs, &origin, &zone);
3042 if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
3043 cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3044 "catz: unable to create catalog zone '%s', "
3045 "error %s",
3046 str, isc_result_totext(result));
3047 goto cleanup;
3048 }
3049
3050 if (result == ISC_R_EXISTS) {
3051 isc_ht_iter_t *it = NULL;
3052
3053 RUNTIME_CHECK(pview != NULL);
3054
3055 /*
3056 * xxxwpk todo: reconfigure the zone!!!!
3057 */
3058 cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3059 "catz: catalog zone '%s' will not be reconfigured",
3060 str);
3061 /*
3062 * We have to walk through all the member zones and attach
3063 * them to current view
3064 */
3065 dns_catz_get_iterator(zone, &it);
3066
3067 for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
3068 result = isc_ht_iter_next(it))
3069 {
3070 dns_name_t *name = NULL;
3071 dns_zone_t *dnszone = NULL;
3072 dns_catz_entry_t *entry = NULL;
3073 isc_result_t tresult;
3074
3075 isc_ht_iter_current(it, (void **)&entry);
3076 name = dns_catz_entry_getname(entry);
3077
3078 tresult = dns_view_findzone(pview, name, &dnszone);
3079 if (tresult != ISC_R_SUCCESS) {
3080 continue;
3081 }
3082
3083 dns_zone_setview(dnszone, view);
3084 dns_view_addzone(view, dnszone);
3085
3086 /*
3087 * The dns_view_findzone() call above increments the
3088 * zone's reference count, which we need to decrement
3089 * back. However, as dns_zone_detach() sets the
3090 * supplied pointer to NULL, calling it is deferred
3091 * until the dnszone variable is no longer used.
3092 */
3093 dns_zone_detach(&dnszone);
3094 }
3095
3096 isc_ht_iter_destroy(&it);
3097
3098 result = ISC_R_SUCCESS;
3099 }
3100
3101 dns_catz_zone_resetdefoptions(zone);
3102 opts = dns_catz_zone_getdefoptions(zone);
3103
3104 obj = cfg_tuple_get(catz_obj, "default-masters");
3105 if (obj != NULL && cfg_obj_istuple(obj)) {
3106 result = named_config_getipandkeylist(
3107 config, "primaries", obj, view->mctx, &opts->masters);
3108 }
3109
3110 obj = cfg_tuple_get(catz_obj, "in-memory");
3111 if (obj != NULL && cfg_obj_isboolean(obj)) {
3112 opts->in_memory = cfg_obj_asboolean(obj);
3113 }
3114
3115 obj = cfg_tuple_get(catz_obj, "zone-directory");
3116 if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) {
3117 opts->zonedir = isc_mem_strdup(view->mctx,
3118 cfg_obj_asstring(obj));
3119 if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) {
3120 cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
3121 "catz: zone-directory '%s' "
3122 "not found; zone files will not be "
3123 "saved",
3124 opts->zonedir);
3125 opts->in_memory = true;
3126 }
3127 }
3128
3129 obj = cfg_tuple_get(catz_obj, "min-update-interval");
3130 if (obj != NULL && cfg_obj_isduration(obj)) {
3131 opts->min_update_interval = cfg_obj_asduration(obj);
3132 }
3133
3134 cleanup:
3135 dns_name_free(&origin, view->mctx);
3136
3137 return (result);
3138 }
3139
3140 static catz_cb_data_t ns_catz_cbdata;
3141 static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
3142 catz_addzone, catz_modzone, catz_delzone, &ns_catz_cbdata
3143 };
3144
3145 static isc_result_t
configure_catz(dns_view_t * view,dns_view_t * pview,const cfg_obj_t * config,const cfg_obj_t * catz_obj)3146 configure_catz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t *config,
3147 const cfg_obj_t *catz_obj) {
3148 const cfg_listelt_t *zone_element;
3149 const dns_catz_zones_t *old = NULL;
3150 bool pview_must_detach = false;
3151 isc_result_t result;
3152
3153 /* xxxwpk TODO do it cleaner, once, somewhere */
3154 ns_catz_cbdata.server = named_g_server;
3155
3156 zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
3157 if (zone_element == NULL) {
3158 return (ISC_R_SUCCESS);
3159 }
3160
3161 CHECK(dns_catz_new_zones(&view->catzs, &ns_catz_zonemodmethods,
3162 view->mctx, named_g_taskmgr,
3163 named_g_timermgr));
3164
3165 if (pview != NULL) {
3166 old = pview->catzs;
3167 } else {
3168 result = dns_viewlist_find(&named_g_server->viewlist,
3169 view->name, view->rdclass, &pview);
3170 if (result == ISC_R_SUCCESS) {
3171 pview_must_detach = true;
3172 old = pview->catzs;
3173 }
3174 }
3175
3176 if (old != NULL) {
3177 dns_catz_catzs_detach(&view->catzs);
3178 dns_catz_catzs_attach(pview->catzs, &view->catzs);
3179 dns_catz_catzs_detach(&pview->catzs);
3180 dns_catz_prereconfig(view->catzs);
3181 }
3182
3183 while (zone_element != NULL) {
3184 CHECK(configure_catz_zone(view, pview, config, zone_element));
3185 zone_element = cfg_list_next(zone_element);
3186 }
3187
3188 if (old != NULL) {
3189 dns_catz_postreconfig(view->catzs);
3190 }
3191
3192 result = ISC_R_SUCCESS;
3193
3194 cleanup:
3195 if (pview_must_detach) {
3196 dns_view_detach(&pview);
3197 }
3198
3199 return (result);
3200 }
3201
3202 #define CHECK_RRL(cond, pat, val1, val2) \
3203 do { \
3204 if (!(cond)) { \
3205 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, pat, \
3206 val1, val2); \
3207 result = ISC_R_RANGE; \
3208 goto cleanup; \
3209 } \
3210 } while (0)
3211
3212 #define CHECK_RRL_RATE(rate, def, max_rate, name) \
3213 do { \
3214 obj = NULL; \
3215 rrl->rate.str = name; \
3216 result = cfg_map_get(map, name, &obj); \
3217 if (result == ISC_R_SUCCESS) { \
3218 rrl->rate.r = cfg_obj_asuint32(obj); \
3219 CHECK_RRL(rrl->rate.r <= max_rate, name " %d > %d", \
3220 rrl->rate.r, max_rate); \
3221 } else { \
3222 rrl->rate.r = def; \
3223 } \
3224 rrl->rate.scaled = rrl->rate.r; \
3225 } while (0)
3226
3227 static isc_result_t
configure_rrl(dns_view_t * view,const cfg_obj_t * config,const cfg_obj_t * map)3228 configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
3229 const cfg_obj_t *obj;
3230 dns_rrl_t *rrl;
3231 isc_result_t result;
3232 int min_entries, i, j;
3233
3234 /*
3235 * Most DNS servers have few clients, but intentinally open
3236 * recursive and authoritative servers often have many.
3237 * So start with a small number of entries unless told otherwise
3238 * to reduce cold-start costs.
3239 */
3240 min_entries = 500;
3241 obj = NULL;
3242 result = cfg_map_get(map, "min-table-size", &obj);
3243 if (result == ISC_R_SUCCESS) {
3244 min_entries = cfg_obj_asuint32(obj);
3245 if (min_entries < 1) {
3246 min_entries = 1;
3247 }
3248 }
3249 result = dns_rrl_init(&rrl, view, min_entries);
3250 if (result != ISC_R_SUCCESS) {
3251 return (result);
3252 }
3253
3254 i = ISC_MAX(20000, min_entries);
3255 obj = NULL;
3256 result = cfg_map_get(map, "max-table-size", &obj);
3257 if (result == ISC_R_SUCCESS) {
3258 i = cfg_obj_asuint32(obj);
3259 CHECK_RRL(i >= min_entries,
3260 "max-table-size %d < min-table-size %d", i,
3261 min_entries);
3262 }
3263 rrl->max_entries = i;
3264
3265 CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
3266 "responses-per-second");
3267 CHECK_RRL_RATE(referrals_per_second, rrl->responses_per_second.r,
3268 DNS_RRL_MAX_RATE, "referrals-per-second");
3269 CHECK_RRL_RATE(nodata_per_second, rrl->responses_per_second.r,
3270 DNS_RRL_MAX_RATE, "nodata-per-second");
3271 CHECK_RRL_RATE(nxdomains_per_second, rrl->responses_per_second.r,
3272 DNS_RRL_MAX_RATE, "nxdomains-per-second");
3273 CHECK_RRL_RATE(errors_per_second, rrl->responses_per_second.r,
3274 DNS_RRL_MAX_RATE, "errors-per-second");
3275
3276 CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
3277
3278 CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
3279
3280 i = 15;
3281 obj = NULL;
3282 result = cfg_map_get(map, "window", &obj);
3283 if (result == ISC_R_SUCCESS) {
3284 i = cfg_obj_asuint32(obj);
3285 CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
3286 "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
3287 }
3288 rrl->window = i;
3289
3290 i = 0;
3291 obj = NULL;
3292 result = cfg_map_get(map, "qps-scale", &obj);
3293 if (result == ISC_R_SUCCESS) {
3294 i = cfg_obj_asuint32(obj);
3295 CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
3296 }
3297 rrl->qps_scale = i;
3298 rrl->qps = 1.0;
3299
3300 i = 24;
3301 obj = NULL;
3302 result = cfg_map_get(map, "ipv4-prefix-length", &obj);
3303 if (result == ISC_R_SUCCESS) {
3304 i = cfg_obj_asuint32(obj);
3305 CHECK_RRL(i >= 8 && i <= 32,
3306 "invalid 'ipv4-prefix-length %d'%s", i, "");
3307 }
3308 rrl->ipv4_prefixlen = i;
3309 if (i == 32) {
3310 rrl->ipv4_mask = 0xffffffff;
3311 } else {
3312 rrl->ipv4_mask = htonl(0xffffffff << (32 - i));
3313 }
3314
3315 i = 56;
3316 obj = NULL;
3317 result = cfg_map_get(map, "ipv6-prefix-length", &obj);
3318 if (result == ISC_R_SUCCESS) {
3319 i = cfg_obj_asuint32(obj);
3320 CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
3321 "ipv6-prefix-length %d < 16 or > %d", i,
3322 DNS_RRL_MAX_PREFIX);
3323 }
3324 rrl->ipv6_prefixlen = i;
3325 for (j = 0; j < 4; ++j) {
3326 if (i <= 0) {
3327 rrl->ipv6_mask[j] = 0;
3328 } else if (i < 32) {
3329 rrl->ipv6_mask[j] = htonl(0xffffffff << (32 - i));
3330 } else {
3331 rrl->ipv6_mask[j] = 0xffffffff;
3332 }
3333 i -= 32;
3334 }
3335
3336 obj = NULL;
3337 result = cfg_map_get(map, "exempt-clients", &obj);
3338 if (result == ISC_R_SUCCESS) {
3339 result = cfg_acl_fromconfig(obj, config, named_g_lctx,
3340 named_g_aclconfctx, named_g_mctx, 0,
3341 &rrl->exempt);
3342 CHECK_RRL(result == ISC_R_SUCCESS, "invalid %s%s",
3343 "address match list", "");
3344 }
3345
3346 obj = NULL;
3347 result = cfg_map_get(map, "log-only", &obj);
3348 if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) {
3349 rrl->log_only = true;
3350 } else {
3351 rrl->log_only = false;
3352 }
3353
3354 return (ISC_R_SUCCESS);
3355
3356 cleanup:
3357 dns_rrl_view_destroy(view);
3358 return (result);
3359 }
3360
3361 static isc_result_t
add_soa(dns_db_t * db,dns_dbversion_t * version,const dns_name_t * name,const dns_name_t * origin,const dns_name_t * contact)3362 add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3363 const dns_name_t *origin, const dns_name_t *contact) {
3364 dns_dbnode_t *node = NULL;
3365 dns_rdata_t rdata = DNS_RDATA_INIT;
3366 dns_rdatalist_t rdatalist;
3367 dns_rdataset_t rdataset;
3368 isc_result_t result;
3369 unsigned char buf[DNS_SOA_BUFFERSIZE];
3370
3371 CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), 0, 28800,
3372 7200, 604800, 86400, buf, &rdata));
3373
3374 dns_rdatalist_init(&rdatalist);
3375 rdatalist.type = rdata.type;
3376 rdatalist.rdclass = rdata.rdclass;
3377 rdatalist.ttl = 86400;
3378 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3379
3380 dns_rdataset_init(&rdataset);
3381 CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3382 CHECK(dns_db_findnode(db, name, true, &node));
3383 CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3384
3385 cleanup:
3386 if (node != NULL) {
3387 dns_db_detachnode(db, &node);
3388 }
3389 return (result);
3390 }
3391
3392 static isc_result_t
add_ns(dns_db_t * db,dns_dbversion_t * version,const dns_name_t * name,const dns_name_t * nsname)3393 add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3394 const dns_name_t *nsname) {
3395 dns_dbnode_t *node = NULL;
3396 dns_rdata_ns_t ns;
3397 dns_rdata_t rdata = DNS_RDATA_INIT;
3398 dns_rdatalist_t rdatalist;
3399 dns_rdataset_t rdataset;
3400 isc_result_t result;
3401 isc_buffer_t b;
3402 unsigned char buf[DNS_NAME_MAXWIRE];
3403
3404 isc_buffer_init(&b, buf, sizeof(buf));
3405
3406 ns.common.rdtype = dns_rdatatype_ns;
3407 ns.common.rdclass = dns_db_class(db);
3408 ns.mctx = NULL;
3409 dns_name_init(&ns.name, NULL);
3410 dns_name_clone(nsname, &ns.name);
3411 CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
3412 &ns, &b));
3413
3414 dns_rdatalist_init(&rdatalist);
3415 rdatalist.type = rdata.type;
3416 rdatalist.rdclass = rdata.rdclass;
3417 rdatalist.ttl = 86400;
3418 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3419
3420 dns_rdataset_init(&rdataset);
3421 CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3422 CHECK(dns_db_findnode(db, name, true, &node));
3423 CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3424
3425 cleanup:
3426 if (node != NULL) {
3427 dns_db_detachnode(db, &node);
3428 }
3429 return (result);
3430 }
3431
3432 static isc_result_t
create_empty_zone(dns_zone_t * zone,dns_name_t * name,dns_view_t * view,const cfg_obj_t * zonelist,const char ** empty_dbtype,int empty_dbtypec,dns_zonestat_level_t statlevel)3433 create_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view,
3434 const cfg_obj_t *zonelist, const char **empty_dbtype,
3435 int empty_dbtypec, dns_zonestat_level_t statlevel) {
3436 char namebuf[DNS_NAME_FORMATSIZE];
3437 const cfg_listelt_t *element;
3438 const cfg_obj_t *obj;
3439 const cfg_obj_t *zconfig;
3440 const cfg_obj_t *zoptions;
3441 const char *rbt_dbtype[4] = { "rbt" };
3442 const char *sep = ": view ";
3443 const char *str;
3444 const char *viewname = view->name;
3445 dns_db_t *db = NULL;
3446 dns_dbversion_t *version = NULL;
3447 dns_fixedname_t cfixed;
3448 dns_fixedname_t fixed;
3449 dns_fixedname_t nsfixed;
3450 dns_name_t *contact;
3451 dns_name_t *ns;
3452 dns_name_t *zname;
3453 dns_zone_t *myzone = NULL;
3454 int rbt_dbtypec = 1;
3455 isc_result_t result;
3456 dns_namereln_t namereln;
3457 int order;
3458 unsigned int nlabels;
3459
3460 zname = dns_fixedname_initname(&fixed);
3461 ns = dns_fixedname_initname(&nsfixed);
3462 contact = dns_fixedname_initname(&cfixed);
3463
3464 /*
3465 * Look for forward "zones" beneath this empty zone and if so
3466 * create a custom db for the empty zone.
3467 */
3468 for (element = cfg_list_first(zonelist); element != NULL;
3469 element = cfg_list_next(element))
3470 {
3471 zconfig = cfg_listelt_value(element);
3472 str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3473 CHECK(dns_name_fromstring(zname, str, 0, NULL));
3474 namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
3475 if (namereln != dns_namereln_subdomain) {
3476 continue;
3477 }
3478
3479 zoptions = cfg_tuple_get(zconfig, "options");
3480
3481 obj = NULL;
3482 (void)cfg_map_get(zoptions, "type", &obj);
3483 if (obj != NULL &&
3484 strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
3485 {
3486 obj = NULL;
3487 (void)cfg_map_get(zoptions, "forward", &obj);
3488 if (obj == NULL) {
3489 continue;
3490 }
3491 if (strcasecmp(cfg_obj_asstring(obj), "only") != 0) {
3492 continue;
3493 }
3494 }
3495 if (db == NULL) {
3496 CHECK(dns_db_create(view->mctx, "rbt", name,
3497 dns_dbtype_zone, view->rdclass, 0,
3498 NULL, &db));
3499 CHECK(dns_db_newversion(db, &version));
3500 if (strcmp(empty_dbtype[2], "@") == 0) {
3501 dns_name_clone(name, ns);
3502 } else {
3503 CHECK(dns_name_fromstring(ns, empty_dbtype[2],
3504 0, NULL));
3505 }
3506 CHECK(dns_name_fromstring(contact, empty_dbtype[3], 0,
3507 NULL));
3508 CHECK(add_soa(db, version, name, ns, contact));
3509 CHECK(add_ns(db, version, name, ns));
3510 }
3511 CHECK(add_ns(db, version, zname, dns_rootname));
3512 }
3513
3514 /*
3515 * Is the existing zone the ok to use?
3516 */
3517 if (zone != NULL) {
3518 unsigned int typec;
3519 const char **dbargv;
3520
3521 if (db != NULL) {
3522 typec = rbt_dbtypec;
3523 dbargv = rbt_dbtype;
3524 } else {
3525 typec = empty_dbtypec;
3526 dbargv = empty_dbtype;
3527 }
3528
3529 result = check_dbtype(zone, typec, dbargv, view->mctx);
3530 if (result != ISC_R_SUCCESS) {
3531 zone = NULL;
3532 }
3533
3534 if (zone != NULL && dns_zone_gettype(zone) != dns_zone_primary)
3535 {
3536 zone = NULL;
3537 }
3538 if (zone != NULL && dns_zone_getfile(zone) != NULL) {
3539 zone = NULL;
3540 }
3541 if (zone != NULL) {
3542 dns_zone_getraw(zone, &myzone);
3543 if (myzone != NULL) {
3544 dns_zone_detach(&myzone);
3545 zone = NULL;
3546 }
3547 }
3548 }
3549
3550 if (zone == NULL) {
3551 CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &myzone));
3552 zone = myzone;
3553 CHECK(dns_zone_setorigin(zone, name));
3554 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3555 if (db == NULL) {
3556 dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype);
3557 }
3558 dns_zone_setclass(zone, view->rdclass);
3559 dns_zone_settype(zone, dns_zone_primary);
3560 dns_zone_setstats(zone, named_g_server->zonestats);
3561 }
3562
3563 dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
3564 dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3565 dns_zone_setnotifytype(zone, dns_notifytype_no);
3566 dns_zone_setdialup(zone, dns_dialuptype_no);
3567 dns_zone_setautomatic(zone, true);
3568 if (view->queryacl != NULL) {
3569 dns_zone_setqueryacl(zone, view->queryacl);
3570 } else {
3571 dns_zone_clearqueryacl(zone);
3572 }
3573 if (view->queryonacl != NULL) {
3574 dns_zone_setqueryonacl(zone, view->queryonacl);
3575 } else {
3576 dns_zone_clearqueryonacl(zone);
3577 }
3578 dns_zone_clearupdateacl(zone);
3579 if (view->transferacl != NULL) {
3580 dns_zone_setxfracl(zone, view->transferacl);
3581 } else {
3582 dns_zone_clearxfracl(zone);
3583 }
3584
3585 CHECK(setquerystats(zone, view->mctx, statlevel));
3586 if (db != NULL) {
3587 dns_db_closeversion(db, &version, true);
3588 CHECK(dns_zone_replacedb(zone, db, false));
3589 }
3590 dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true);
3591 dns_zone_setview(zone, view);
3592 CHECK(dns_view_addzone(view, zone));
3593
3594 if (!strcmp(viewname, "_default")) {
3595 sep = "";
3596 viewname = "";
3597 }
3598 dns_name_format(name, namebuf, sizeof(namebuf));
3599 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD,
3600 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3601 "automatic empty zone%s%s: %s", sep, viewname, namebuf);
3602
3603 cleanup:
3604 if (myzone != NULL) {
3605 dns_zone_detach(&myzone);
3606 }
3607 if (version != NULL) {
3608 dns_db_closeversion(db, &version, false);
3609 }
3610 if (db != NULL) {
3611 dns_db_detach(&db);
3612 }
3613
3614 INSIST(version == NULL);
3615
3616 return (result);
3617 }
3618
3619 #ifdef HAVE_DNSTAP
3620 static isc_result_t
configure_dnstap(const cfg_obj_t ** maps,dns_view_t * view)3621 configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
3622 isc_result_t result;
3623 const cfg_obj_t *obj, *obj2;
3624 const cfg_listelt_t *element;
3625 const char *dpath;
3626 const cfg_obj_t *dlist = NULL;
3627 dns_dtmsgtype_t dttypes = 0;
3628 unsigned int i;
3629 struct fstrm_iothr_options *fopt = NULL;
3630
3631 result = named_config_get(maps, "dnstap", &dlist);
3632 if (result != ISC_R_SUCCESS) {
3633 return (ISC_R_SUCCESS);
3634 }
3635
3636 for (element = cfg_list_first(dlist); element != NULL;
3637 element = cfg_list_next(element))
3638 {
3639 const char *str;
3640 dns_dtmsgtype_t dt = 0;
3641
3642 obj = cfg_listelt_value(element);
3643 obj2 = cfg_tuple_get(obj, "type");
3644 str = cfg_obj_asstring(obj2);
3645 if (strcasecmp(str, "client") == 0) {
3646 dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR;
3647 } else if (strcasecmp(str, "auth") == 0) {
3648 dt |= DNS_DTTYPE_AQ | DNS_DTTYPE_AR;
3649 } else if (strcasecmp(str, "resolver") == 0) {
3650 dt |= DNS_DTTYPE_RQ | DNS_DTTYPE_RR;
3651 } else if (strcasecmp(str, "forwarder") == 0) {
3652 dt |= DNS_DTTYPE_FQ | DNS_DTTYPE_FR;
3653 } else if (strcasecmp(str, "update") == 0) {
3654 dt |= DNS_DTTYPE_UQ | DNS_DTTYPE_UR;
3655 } else if (strcasecmp(str, "all") == 0) {
3656 dt |= DNS_DTTYPE_CQ | DNS_DTTYPE_CR | DNS_DTTYPE_AQ |
3657 DNS_DTTYPE_AR | DNS_DTTYPE_RQ | DNS_DTTYPE_RR |
3658 DNS_DTTYPE_FQ | DNS_DTTYPE_FR | DNS_DTTYPE_UQ |
3659 DNS_DTTYPE_UR;
3660 }
3661
3662 obj2 = cfg_tuple_get(obj, "mode");
3663 if (obj2 == NULL || cfg_obj_isvoid(obj2)) {
3664 dttypes |= dt;
3665 continue;
3666 }
3667
3668 str = cfg_obj_asstring(obj2);
3669 if (strcasecmp(str, "query") == 0) {
3670 dt &= ~DNS_DTTYPE_RESPONSE;
3671 } else if (strcasecmp(str, "response") == 0) {
3672 dt &= ~DNS_DTTYPE_QUERY;
3673 }
3674
3675 dttypes |= dt;
3676 }
3677
3678 if (named_g_server->dtenv == NULL && dttypes != 0) {
3679 dns_dtmode_t dmode;
3680 uint64_t max_size = 0;
3681 uint32_t rolls = 0;
3682 isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment;
3683
3684 obj = NULL;
3685 CHECKM(named_config_get(maps, "dnstap-output", &obj),
3686 "'dnstap-output' must be set if 'dnstap' is set");
3687
3688 obj2 = cfg_tuple_get(obj, "mode");
3689 if (obj2 == NULL) {
3690 CHECKM(ISC_R_FAILURE, "dnstap-output mode not found");
3691 }
3692 if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) {
3693 dmode = dns_dtmode_file;
3694 } else {
3695 dmode = dns_dtmode_unix;
3696 }
3697
3698 obj2 = cfg_tuple_get(obj, "path");
3699 if (obj2 == NULL) {
3700 CHECKM(ISC_R_FAILURE, "dnstap-output path not found");
3701 }
3702
3703 dpath = cfg_obj_asstring(obj2);
3704
3705 obj2 = cfg_tuple_get(obj, "size");
3706 if (obj2 != NULL && cfg_obj_isuint64(obj2)) {
3707 max_size = cfg_obj_asuint64(obj2);
3708 if (max_size > SIZE_MAX) {
3709 cfg_obj_log(obj2, named_g_lctx, ISC_LOG_WARNING,
3710 "'dnstap-output size "
3711 "%" PRIu64 "' "
3712 "is too large for this "
3713 "system; reducing to %lu",
3714 max_size, (unsigned long)SIZE_MAX);
3715 max_size = SIZE_MAX;
3716 }
3717 }
3718
3719 obj2 = cfg_tuple_get(obj, "versions");
3720 if (obj2 != NULL && cfg_obj_isuint32(obj2)) {
3721 rolls = cfg_obj_asuint32(obj2);
3722 } else {
3723 rolls = ISC_LOG_ROLLINFINITE;
3724 }
3725
3726 obj2 = cfg_tuple_get(obj, "suffix");
3727 if (obj2 != NULL && cfg_obj_isstring(obj2) &&
3728 strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0)
3729 {
3730 suffix = isc_log_rollsuffix_timestamp;
3731 }
3732
3733 fopt = fstrm_iothr_options_init();
3734 /*
3735 * Both network threads and worker threads may log dnstap data.
3736 */
3737 fstrm_iothr_options_set_num_input_queues(fopt,
3738 2 * named_g_cpus);
3739 fstrm_iothr_options_set_queue_model(
3740 fopt, FSTRM_IOTHR_QUEUE_MODEL_MPSC);
3741
3742 obj = NULL;
3743 result = named_config_get(maps, "fstrm-set-buffer-hint", &obj);
3744 if (result == ISC_R_SUCCESS) {
3745 i = cfg_obj_asuint32(obj);
3746 fstrm_iothr_options_set_buffer_hint(fopt, i);
3747 }
3748
3749 obj = NULL;
3750 result = named_config_get(maps, "fstrm-set-flush-timeout",
3751 &obj);
3752 if (result == ISC_R_SUCCESS) {
3753 i = cfg_obj_asuint32(obj);
3754 fstrm_iothr_options_set_flush_timeout(fopt, i);
3755 }
3756
3757 obj = NULL;
3758 result = named_config_get(maps, "fstrm-set-input-queue-size",
3759 &obj);
3760 if (result == ISC_R_SUCCESS) {
3761 i = cfg_obj_asuint32(obj);
3762 fstrm_iothr_options_set_input_queue_size(fopt, i);
3763 }
3764
3765 obj = NULL;
3766 result = named_config_get(
3767 maps, "fstrm-set-output-notify-threshold", &obj);
3768 if (result == ISC_R_SUCCESS) {
3769 i = cfg_obj_asuint32(obj);
3770 fstrm_iothr_options_set_queue_notify_threshold(fopt, i);
3771 }
3772
3773 obj = NULL;
3774 result = named_config_get(maps, "fstrm-set-output-queue-model",
3775 &obj);
3776 if (result == ISC_R_SUCCESS) {
3777 if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0) {
3778 i = FSTRM_IOTHR_QUEUE_MODEL_SPSC;
3779 } else {
3780 i = FSTRM_IOTHR_QUEUE_MODEL_MPSC;
3781 }
3782 fstrm_iothr_options_set_queue_model(fopt, i);
3783 }
3784
3785 obj = NULL;
3786 result = named_config_get(maps, "fstrm-set-output-queue-size",
3787 &obj);
3788 if (result == ISC_R_SUCCESS) {
3789 i = cfg_obj_asuint32(obj);
3790 fstrm_iothr_options_set_output_queue_size(fopt, i);
3791 }
3792
3793 obj = NULL;
3794 result = named_config_get(maps, "fstrm-set-reopen-interval",
3795 &obj);
3796 if (result == ISC_R_SUCCESS) {
3797 i = cfg_obj_asduration(obj);
3798 fstrm_iothr_options_set_reopen_interval(fopt, i);
3799 }
3800
3801 CHECKM(dns_dt_create(named_g_mctx, dmode, dpath, &fopt,
3802 named_g_server->task,
3803 &named_g_server->dtenv),
3804 "unable to create dnstap environment");
3805
3806 CHECKM(dns_dt_setupfile(named_g_server->dtenv, max_size, rolls,
3807 suffix),
3808 "unable to set up dnstap logfile");
3809 }
3810
3811 if (named_g_server->dtenv == NULL) {
3812 return (ISC_R_SUCCESS);
3813 }
3814
3815 obj = NULL;
3816 result = named_config_get(maps, "dnstap-version", &obj);
3817 if (result != ISC_R_SUCCESS) {
3818 /* not specified; use the product and version */
3819 dns_dt_setversion(named_g_server->dtenv, PRODUCT " " VERSION);
3820 } else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3821 /* Quoted string */
3822 dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj));
3823 }
3824
3825 obj = NULL;
3826 result = named_config_get(maps, "dnstap-identity", &obj);
3827 if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
3828 /* "hostname" is interpreted as boolean true */
3829 char buf[256];
3830 result = named_os_gethostname(buf, sizeof(buf));
3831 if (result == ISC_R_SUCCESS) {
3832 dns_dt_setidentity(named_g_server->dtenv, buf);
3833 }
3834 } else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3835 /* Quoted string */
3836 dns_dt_setidentity(named_g_server->dtenv,
3837 cfg_obj_asstring(obj));
3838 }
3839
3840 dns_dt_attach(named_g_server->dtenv, &view->dtenv);
3841 view->dttypes = dttypes;
3842
3843 result = ISC_R_SUCCESS;
3844
3845 cleanup:
3846 if (fopt != NULL) {
3847 fstrm_iothr_options_destroy(&fopt);
3848 }
3849
3850 return (result);
3851 }
3852 #endif /* HAVE_DNSTAP */
3853
3854 static isc_result_t
create_mapped_acl(void)3855 create_mapped_acl(void) {
3856 isc_result_t result;
3857 dns_acl_t *acl = NULL;
3858 struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT;
3859 isc_netaddr_t addr;
3860
3861 isc_netaddr_fromin6(&addr, &in6);
3862
3863 result = dns_acl_create(named_g_mctx, 1, &acl);
3864 if (result != ISC_R_SUCCESS) {
3865 return (result);
3866 }
3867
3868 result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
3869 if (result == ISC_R_SUCCESS) {
3870 dns_acl_attach(acl, &named_g_mapped);
3871 }
3872 dns_acl_detach(&acl);
3873 return (result);
3874 }
3875
3876 #ifdef HAVE_DLOPEN
3877 /*%
3878 * A callback for the cfg_pluginlist_foreach() call in configure_view() below.
3879 * If registering any plugin fails, registering subsequent ones is not
3880 * attempted.
3881 */
3882 static isc_result_t
register_one_plugin(const cfg_obj_t * config,const cfg_obj_t * obj,const char * plugin_path,const char * parameters,void * callback_data)3883 register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
3884 const char *plugin_path, const char *parameters,
3885 void *callback_data) {
3886 dns_view_t *view = callback_data;
3887 char full_path[PATH_MAX];
3888 isc_result_t result;
3889
3890 result = ns_plugin_expandpath(plugin_path, full_path,
3891 sizeof(full_path));
3892 if (result != ISC_R_SUCCESS) {
3893 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3894 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3895 "%s: plugin configuration failed: "
3896 "unable to get full plugin path: %s",
3897 plugin_path, isc_result_totext(result));
3898 return (result);
3899 }
3900
3901 result = ns_plugin_register(full_path, parameters, config,
3902 cfg_obj_file(obj), cfg_obj_line(obj),
3903 named_g_mctx, named_g_lctx,
3904 named_g_aclconfctx, view);
3905 if (result != ISC_R_SUCCESS) {
3906 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3907 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3908 "%s: plugin configuration failed: %s", full_path,
3909 isc_result_totext(result));
3910 }
3911
3912 return (result);
3913 }
3914 #endif /* ifdef HAVE_DLOPEN */
3915
3916 /*
3917 * Determine if a minimal-sized cache can be used for a given view, according
3918 * to 'maps' (implicit defaults, global options, view options) and 'optionmaps'
3919 * (global options, view options). This is only allowed for views which have
3920 * recursion disabled and do not have "max-cache-size" set explicitly. Using
3921 * minimal-sized caches prevents a situation in which all explicitly configured
3922 * and built-in views inherit the default "max-cache-size 90%;" setting, which
3923 * could lead to memory exhaustion with multiple views configured.
3924 */
3925 static bool
minimal_cache_allowed(const cfg_obj_t * maps[4],const cfg_obj_t * optionmaps[3])3926 minimal_cache_allowed(const cfg_obj_t *maps[4],
3927 const cfg_obj_t *optionmaps[3]) {
3928 const cfg_obj_t *obj;
3929
3930 /*
3931 * Do not use a minimal-sized cache for a view with recursion enabled.
3932 */
3933 obj = NULL;
3934 (void)named_config_get(maps, "recursion", &obj);
3935 INSIST(obj != NULL);
3936 if (cfg_obj_asboolean(obj)) {
3937 return (false);
3938 }
3939
3940 /*
3941 * Do not use a minimal-sized cache if a specific size was requested.
3942 */
3943 obj = NULL;
3944 (void)named_config_get(optionmaps, "max-cache-size", &obj);
3945 if (obj != NULL) {
3946 return (false);
3947 }
3948
3949 return (true);
3950 }
3951
3952 static const char *const response_synonyms[] = { "response", NULL };
3953
3954 /*
3955 * Configure 'view' according to 'vconfig', taking defaults from 'config'
3956 * where values are missing in 'vconfig'.
3957 *
3958 * When configuring the default view, 'vconfig' will be NULL and the
3959 * global defaults in 'config' used exclusively.
3960 */
3961 static isc_result_t
configure_view(dns_view_t * view,dns_viewlist_t * viewlist,cfg_obj_t * config,cfg_obj_t * vconfig,named_cachelist_t * cachelist,dns_kasplist_t * kasplist,const cfg_obj_t * bindkeys,isc_mem_t * mctx,cfg_aclconfctx_t * actx,bool need_hints)3962 configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
3963 cfg_obj_t *vconfig, named_cachelist_t *cachelist,
3964 dns_kasplist_t *kasplist, const cfg_obj_t *bindkeys,
3965 isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints) {
3966 const cfg_obj_t *maps[4];
3967 const cfg_obj_t *cfgmaps[3];
3968 const cfg_obj_t *optionmaps[3];
3969 const cfg_obj_t *options = NULL;
3970 const cfg_obj_t *voptions = NULL;
3971 const cfg_obj_t *forwardtype;
3972 const cfg_obj_t *forwarders;
3973 const cfg_obj_t *alternates;
3974 const cfg_obj_t *zonelist;
3975 const cfg_obj_t *dlzlist;
3976 const cfg_obj_t *dlz;
3977 const cfg_obj_t *prefetch_trigger;
3978 const cfg_obj_t *prefetch_eligible;
3979 unsigned int dlzargc;
3980 char **dlzargv;
3981 const cfg_obj_t *dyndb_list, *plugin_list;
3982 const cfg_obj_t *disabled;
3983 const cfg_obj_t *obj, *obj2;
3984 const cfg_listelt_t *element = NULL;
3985 const cfg_listelt_t *zone_element_latest = NULL;
3986 in_port_t port;
3987 dns_cache_t *cache = NULL;
3988 isc_result_t result;
3989 size_t max_cache_size;
3990 uint32_t max_cache_size_percent = 0;
3991 size_t max_adb_size;
3992 uint32_t lame_ttl, fail_ttl;
3993 uint32_t max_stale_ttl = 0;
3994 uint32_t stale_refresh_time = 0;
3995 dns_tsig_keyring_t *ring = NULL;
3996 dns_view_t *pview = NULL; /* Production view */
3997 isc_mem_t *cmctx = NULL, *hmctx = NULL;
3998 dns_dispatch_t *dispatch4 = NULL;
3999 dns_dispatch_t *dispatch6 = NULL;
4000 bool rpz_configured = false;
4001 bool catz_configured = false;
4002 bool reused_cache = false;
4003 bool shared_cache = false;
4004 int i = 0, j = 0, k = 0;
4005 const char *str;
4006 const char *cachename = NULL;
4007 dns_order_t *order = NULL;
4008 uint32_t udpsize;
4009 uint32_t maxbits;
4010 unsigned int resopts = 0;
4011 dns_zone_t *zone = NULL;
4012 uint32_t max_clients_per_query;
4013 bool empty_zones_enable;
4014 const cfg_obj_t *disablelist = NULL;
4015 isc_stats_t *resstats = NULL;
4016 dns_stats_t *resquerystats = NULL;
4017 bool auto_root = false;
4018 named_cache_t *nsc;
4019 bool zero_no_soattl;
4020 dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
4021 unsigned int query_timeout, ndisp;
4022 bool old_rpz_ok = false;
4023 isc_dscp_t dscp4 = -1, dscp6 = -1;
4024 dns_dyndbctx_t *dctx = NULL;
4025 unsigned int resolver_param;
4026 dns_ntatable_t *ntatable = NULL;
4027 const char *qminmode = NULL;
4028
4029 REQUIRE(DNS_VIEW_VALID(view));
4030
4031 if (config != NULL) {
4032 (void)cfg_map_get(config, "options", &options);
4033 }
4034
4035 /*
4036 * maps: view options, options, defaults
4037 * cfgmaps: view options, config
4038 * optionmaps: view options, options
4039 */
4040 if (vconfig != NULL) {
4041 voptions = cfg_tuple_get(vconfig, "options");
4042 maps[i++] = voptions;
4043 optionmaps[j++] = voptions;
4044 cfgmaps[k++] = voptions;
4045 }
4046 if (options != NULL) {
4047 maps[i++] = options;
4048 optionmaps[j++] = options;
4049 }
4050
4051 maps[i++] = named_g_defaults;
4052 maps[i] = NULL;
4053 optionmaps[j] = NULL;
4054 if (config != NULL) {
4055 cfgmaps[k++] = config;
4056 }
4057 cfgmaps[k] = NULL;
4058
4059 /*
4060 * Set the view's port number for outgoing queries.
4061 */
4062 CHECKM(named_config_getport(config, &port), "port");
4063 dns_view_setdstport(view, port);
4064
4065 /*
4066 * Make the list of response policy zone names for a view that
4067 * is used for real lookups and so cares about hints.
4068 */
4069 obj = NULL;
4070 if (view->rdclass == dns_rdataclass_in && need_hints &&
4071 named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS)
4072 {
4073 CHECK(configure_rpz(view, NULL, maps, obj, &old_rpz_ok));
4074 rpz_configured = true;
4075 }
4076
4077 obj = NULL;
4078 if (view->rdclass == dns_rdataclass_in && need_hints &&
4079 named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS)
4080 {
4081 CHECK(configure_catz(view, NULL, config, obj));
4082 catz_configured = true;
4083 }
4084
4085 /*
4086 * Configure the zones.
4087 */
4088 zonelist = NULL;
4089 if (voptions != NULL) {
4090 (void)cfg_map_get(voptions, "zone", &zonelist);
4091 } else {
4092 (void)cfg_map_get(config, "zone", &zonelist);
4093 }
4094
4095 /*
4096 * Load zone configuration
4097 */
4098 for (element = cfg_list_first(zonelist); element != NULL;
4099 element = cfg_list_next(element))
4100 {
4101 const cfg_obj_t *zconfig = cfg_listelt_value(element);
4102 CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
4103 viewlist, kasplist, actx, false,
4104 old_rpz_ok, false));
4105 zone_element_latest = element;
4106 }
4107
4108 /*
4109 * Check that a master or slave zone was found for each
4110 * zone named in the response policy statement
4111 * unless we are using RPZ service interface.
4112 */
4113 if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
4114 dns_rpz_num_t n;
4115
4116 for (n = 0; n < view->rpzs->p.num_zones; ++n) {
4117 if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
4118 char namebuf[DNS_NAME_FORMATSIZE];
4119
4120 dns_name_format(&view->rpzs->zones[n]->origin,
4121 namebuf, sizeof(namebuf));
4122 isc_log_write(named_g_lctx,
4123 NAMED_LOGCATEGORY_GENERAL,
4124 NAMED_LOGMODULE_SERVER,
4125 DNS_RPZ_ERROR_LEVEL,
4126 "rpz '%s'"
4127 " is not a master or slave zone",
4128 namebuf);
4129 result = ISC_R_NOTFOUND;
4130 goto cleanup;
4131 }
4132 }
4133 }
4134
4135 /*
4136 * If we're allowing added zones, then load zone configuration
4137 * from the newzone file for zones that were added during previous
4138 * runs.
4139 */
4140 CHECK(configure_newzones(view, config, vconfig, mctx, actx));
4141
4142 /*
4143 * Create Dynamically Loadable Zone driver.
4144 */
4145 dlzlist = NULL;
4146 if (voptions != NULL) {
4147 (void)cfg_map_get(voptions, "dlz", &dlzlist);
4148 } else {
4149 (void)cfg_map_get(config, "dlz", &dlzlist);
4150 }
4151
4152 for (element = cfg_list_first(dlzlist); element != NULL;
4153 element = cfg_list_next(element))
4154 {
4155 dlz = cfg_listelt_value(element);
4156
4157 obj = NULL;
4158 (void)cfg_map_get(dlz, "database", &obj);
4159 if (obj != NULL) {
4160 dns_dlzdb_t *dlzdb = NULL;
4161 const cfg_obj_t *name, *search = NULL;
4162 char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
4163
4164 if (s == NULL) {
4165 result = ISC_R_NOMEMORY;
4166 goto cleanup;
4167 }
4168
4169 result = isc_commandline_strtoargv(mctx, s, &dlzargc,
4170 &dlzargv, 0);
4171 if (result != ISC_R_SUCCESS) {
4172 isc_mem_free(mctx, s);
4173 goto cleanup;
4174 }
4175
4176 name = cfg_map_getname(dlz);
4177 result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
4178 dlzargv[0], dlzargc, dlzargv,
4179 &dlzdb);
4180 isc_mem_free(mctx, s);
4181 isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
4182 if (result != ISC_R_SUCCESS) {
4183 goto cleanup;
4184 }
4185
4186 /*
4187 * If the DLZ backend supports configuration,
4188 * and is searchable, then call its configure
4189 * method now. If not searchable, we'll take
4190 * care of it when we process the zone statement.
4191 */
4192 (void)cfg_map_get(dlz, "search", &search);
4193 if (search == NULL || cfg_obj_asboolean(search)) {
4194 dlzdb->search = true;
4195 result = dns_dlzconfigure(
4196 view, dlzdb, dlzconfigure_callback);
4197 if (result != ISC_R_SUCCESS) {
4198 goto cleanup;
4199 }
4200 ISC_LIST_APPEND(view->dlz_searched, dlzdb,
4201 link);
4202 } else {
4203 dlzdb->search = false;
4204 ISC_LIST_APPEND(view->dlz_unsearched, dlzdb,
4205 link);
4206 }
4207 }
4208 }
4209
4210 /*
4211 * Obtain configuration parameters that affect the decision of whether
4212 * we can reuse/share an existing cache.
4213 */
4214 obj = NULL;
4215 result = named_config_get(maps, "max-cache-size", &obj);
4216 INSIST(result == ISC_R_SUCCESS);
4217 /*
4218 * If "-T maxcachesize=..." is in effect, it overrides any other
4219 * "max-cache-size" setting found in configuration, either implicit or
4220 * explicit. For simplicity, the value passed to that command line
4221 * option is always treated as the number of bytes to set
4222 * "max-cache-size" to.
4223 */
4224 if (named_g_maxcachesize != 0) {
4225 max_cache_size = named_g_maxcachesize;
4226 } else if (minimal_cache_allowed(maps, optionmaps)) {
4227 /*
4228 * dns_cache_setcachesize() will adjust this to the smallest
4229 * allowed value.
4230 */
4231 max_cache_size = 1;
4232 } else if (cfg_obj_isstring(obj)) {
4233 str = cfg_obj_asstring(obj);
4234 INSIST(strcasecmp(str, "unlimited") == 0);
4235 max_cache_size = 0;
4236 } else if (cfg_obj_ispercentage(obj)) {
4237 max_cache_size = SIZE_AS_PERCENT;
4238 max_cache_size_percent = cfg_obj_aspercentage(obj);
4239 } else {
4240 isc_resourcevalue_t value;
4241 value = cfg_obj_asuint64(obj);
4242 if (value > SIZE_MAX) {
4243 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4244 "'max-cache-size "
4245 "%" PRIu64 "' "
4246 "is too large for this "
4247 "system; reducing to %lu",
4248 value, (unsigned long)SIZE_MAX);
4249 value = SIZE_MAX;
4250 }
4251 max_cache_size = (size_t)value;
4252 }
4253
4254 if (max_cache_size == SIZE_AS_PERCENT) {
4255 uint64_t totalphys = isc_meminfo_totalphys();
4256
4257 max_cache_size =
4258 (size_t)(totalphys * max_cache_size_percent / 100);
4259 if (totalphys == 0) {
4260 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4261 "Unable to determine amount of physical "
4262 "memory, setting 'max-cache-size' to "
4263 "unlimited");
4264 } else {
4265 cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
4266 "'max-cache-size %d%%' "
4267 "- setting to %" PRIu64 "MB "
4268 "(out of %" PRIu64 "MB)",
4269 max_cache_size_percent,
4270 (uint64_t)(max_cache_size / (1024 * 1024)),
4271 totalphys / (1024 * 1024));
4272 }
4273 }
4274
4275 /* Check-names. */
4276 obj = NULL;
4277 result = named_checknames_get(maps, response_synonyms, &obj);
4278 INSIST(result == ISC_R_SUCCESS);
4279
4280 str = cfg_obj_asstring(obj);
4281 if (strcasecmp(str, "fail") == 0) {
4282 resopts |= DNS_RESOLVER_CHECKNAMES |
4283 DNS_RESOLVER_CHECKNAMESFAIL;
4284 view->checknames = true;
4285 } else if (strcasecmp(str, "warn") == 0) {
4286 resopts |= DNS_RESOLVER_CHECKNAMES;
4287 view->checknames = false;
4288 } else if (strcasecmp(str, "ignore") == 0) {
4289 view->checknames = false;
4290 } else {
4291 UNREACHABLE();
4292 }
4293
4294 obj = NULL;
4295 result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj);
4296 INSIST(result == ISC_R_SUCCESS);
4297 zero_no_soattl = cfg_obj_asboolean(obj);
4298
4299 obj = NULL;
4300 result = named_config_get(maps, "dns64", &obj);
4301 if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
4302 strcmp(view->name, "_meta"))
4303 {
4304 isc_netaddr_t na, suffix, *sp;
4305 unsigned int prefixlen;
4306 const char *server, *contact;
4307 const cfg_obj_t *myobj;
4308
4309 myobj = NULL;
4310 result = named_config_get(maps, "dns64-server", &myobj);
4311 if (result == ISC_R_SUCCESS) {
4312 server = cfg_obj_asstring(myobj);
4313 } else {
4314 server = NULL;
4315 }
4316
4317 myobj = NULL;
4318 result = named_config_get(maps, "dns64-contact", &myobj);
4319 if (result == ISC_R_SUCCESS) {
4320 contact = cfg_obj_asstring(myobj);
4321 } else {
4322 contact = NULL;
4323 }
4324
4325 for (element = cfg_list_first(obj); element != NULL;
4326 element = cfg_list_next(element))
4327 {
4328 const cfg_obj_t *map = cfg_listelt_value(element);
4329 dns_dns64_t *dns64 = NULL;
4330 unsigned int dns64options = 0;
4331
4332 cfg_obj_asnetprefix(cfg_map_getname(map), &na,
4333 &prefixlen);
4334
4335 obj = NULL;
4336 (void)cfg_map_get(map, "suffix", &obj);
4337 if (obj != NULL) {
4338 sp = &suffix;
4339 isc_netaddr_fromsockaddr(
4340 sp, cfg_obj_assockaddr(obj));
4341 } else {
4342 sp = NULL;
4343 }
4344
4345 clients = mapped = excluded = NULL;
4346 obj = NULL;
4347 (void)cfg_map_get(map, "clients", &obj);
4348 if (obj != NULL) {
4349 result = cfg_acl_fromconfig(obj, config,
4350 named_g_lctx, actx,
4351 mctx, 0, &clients);
4352 if (result != ISC_R_SUCCESS) {
4353 goto cleanup;
4354 }
4355 }
4356 obj = NULL;
4357 (void)cfg_map_get(map, "mapped", &obj);
4358 if (obj != NULL) {
4359 result = cfg_acl_fromconfig(obj, config,
4360 named_g_lctx, actx,
4361 mctx, 0, &mapped);
4362 if (result != ISC_R_SUCCESS) {
4363 goto cleanup;
4364 }
4365 }
4366 obj = NULL;
4367 (void)cfg_map_get(map, "exclude", &obj);
4368 if (obj != NULL) {
4369 result = cfg_acl_fromconfig(obj, config,
4370 named_g_lctx, actx,
4371 mctx, 0, &excluded);
4372 if (result != ISC_R_SUCCESS) {
4373 goto cleanup;
4374 }
4375 } else {
4376 if (named_g_mapped == NULL) {
4377 result = create_mapped_acl();
4378 if (result != ISC_R_SUCCESS) {
4379 goto cleanup;
4380 }
4381 }
4382 dns_acl_attach(named_g_mapped, &excluded);
4383 }
4384
4385 obj = NULL;
4386 (void)cfg_map_get(map, "recursive-only", &obj);
4387 if (obj != NULL && cfg_obj_asboolean(obj)) {
4388 dns64options |= DNS_DNS64_RECURSIVE_ONLY;
4389 }
4390
4391 obj = NULL;
4392 (void)cfg_map_get(map, "break-dnssec", &obj);
4393 if (obj != NULL && cfg_obj_asboolean(obj)) {
4394 dns64options |= DNS_DNS64_BREAK_DNSSEC;
4395 }
4396
4397 result = dns_dns64_create(mctx, &na, prefixlen, sp,
4398 clients, mapped, excluded,
4399 dns64options, &dns64);
4400 if (result != ISC_R_SUCCESS) {
4401 goto cleanup;
4402 }
4403 dns_dns64_append(&view->dns64, dns64);
4404 view->dns64cnt++;
4405 result = dns64_reverse(view, mctx, &na, prefixlen,
4406 server, contact);
4407 if (result != ISC_R_SUCCESS) {
4408 goto cleanup;
4409 }
4410 if (clients != NULL) {
4411 dns_acl_detach(&clients);
4412 }
4413 if (mapped != NULL) {
4414 dns_acl_detach(&mapped);
4415 }
4416 if (excluded != NULL) {
4417 dns_acl_detach(&excluded);
4418 }
4419 }
4420 }
4421
4422 obj = NULL;
4423 result = named_config_get(maps, "dnssec-accept-expired", &obj);
4424 INSIST(result == ISC_R_SUCCESS);
4425 view->acceptexpired = cfg_obj_asboolean(obj);
4426
4427 obj = NULL;
4428 /* 'optionmaps', not 'maps': don't check named_g_defaults yet */
4429 (void)named_config_get(optionmaps, "dnssec-validation", &obj);
4430 if (obj == NULL) {
4431 /*
4432 * Default to VALIDATION_DEFAULT as set in config.c.
4433 */
4434 (void)cfg_map_get(named_g_defaults, "dnssec-validation", &obj);
4435 INSIST(obj != NULL);
4436 }
4437 if (obj != NULL) {
4438 if (cfg_obj_isboolean(obj)) {
4439 view->enablevalidation = cfg_obj_asboolean(obj);
4440 } else {
4441 /*
4442 * If dnssec-validation is set but not boolean,
4443 * then it must be "auto"
4444 */
4445 view->enablevalidation = true;
4446 auto_root = true;
4447 }
4448 }
4449
4450 obj = NULL;
4451 result = named_config_get(maps, "max-cache-ttl", &obj);
4452 INSIST(result == ISC_R_SUCCESS);
4453 view->maxcachettl = cfg_obj_asduration(obj);
4454
4455 obj = NULL;
4456 result = named_config_get(maps, "max-ncache-ttl", &obj);
4457 INSIST(result == ISC_R_SUCCESS);
4458 view->maxncachettl = cfg_obj_asduration(obj);
4459
4460 obj = NULL;
4461 result = named_config_get(maps, "min-cache-ttl", &obj);
4462 INSIST(result == ISC_R_SUCCESS);
4463 view->mincachettl = cfg_obj_asduration(obj);
4464
4465 obj = NULL;
4466 result = named_config_get(maps, "min-ncache-ttl", &obj);
4467 INSIST(result == ISC_R_SUCCESS);
4468 view->minncachettl = cfg_obj_asduration(obj);
4469
4470 obj = NULL;
4471 result = named_config_get(maps, "synth-from-dnssec", &obj);
4472 INSIST(result == ISC_R_SUCCESS);
4473 view->synthfromdnssec = cfg_obj_asboolean(obj);
4474
4475 obj = NULL;
4476 result = named_config_get(maps, "stale-cache-enable", &obj);
4477 INSIST(result == ISC_R_SUCCESS);
4478 if (cfg_obj_asboolean(obj)) {
4479 obj = NULL;
4480 result = named_config_get(maps, "max-stale-ttl", &obj);
4481 INSIST(result == ISC_R_SUCCESS);
4482 max_stale_ttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4483 }
4484 /*
4485 * If 'stale-cache-enable' is false, max_stale_ttl is set to 0,
4486 * meaning keeping stale RRsets in cache is disabled.
4487 */
4488
4489 obj = NULL;
4490 result = named_config_get(maps, "stale-answer-enable", &obj);
4491 INSIST(result == ISC_R_SUCCESS);
4492 view->staleanswersenable = cfg_obj_asboolean(obj);
4493
4494 result = dns_viewlist_find(&named_g_server->viewlist, view->name,
4495 view->rdclass, &pview);
4496 if (result == ISC_R_SUCCESS) {
4497 view->staleanswersok = pview->staleanswersok;
4498 dns_view_detach(&pview);
4499 } else {
4500 view->staleanswersok = dns_stale_answer_conf;
4501 }
4502
4503 obj = NULL;
4504 result = named_config_get(maps, "stale-answer-client-timeout", &obj);
4505 INSIST(result == ISC_R_SUCCESS);
4506 if (cfg_obj_isstring(obj)) {
4507 /*
4508 * The only string values available for this option
4509 * are "disabled" and "off".
4510 * We use (uint32_t) -1 to represent disabled since
4511 * a value of zero means that stale data can be used
4512 * to promptly answer the query, while an attempt to
4513 * refresh the RRset will still be made in background.
4514 */
4515 view->staleanswerclienttimeout = (uint32_t)-1;
4516 } else {
4517 view->staleanswerclienttimeout = cfg_obj_asuint32(obj);
4518 }
4519
4520 obj = NULL;
4521 result = named_config_get(maps, "stale-refresh-time", &obj);
4522 INSIST(result == ISC_R_SUCCESS);
4523 stale_refresh_time = cfg_obj_asduration(obj);
4524
4525 /*
4526 * Configure the view's cache.
4527 *
4528 * First, check to see if there are any attach-cache options. If yes,
4529 * attempt to lookup an existing cache at attach it to the view. If
4530 * there is not one, then try to reuse an existing cache if possible;
4531 * otherwise create a new cache.
4532 *
4533 * Note that the ADB is not preserved or shared in either case.
4534 *
4535 * When a matching view is found, the associated statistics are also
4536 * retrieved and reused.
4537 *
4538 * XXX Determining when it is safe to reuse or share a cache is tricky.
4539 * When the view's configuration changes, the cached data may become
4540 * invalid because it reflects our old view of the world. We check
4541 * some of the configuration parameters that could invalidate the cache
4542 * or otherwise make it unshareable, but there are other configuration
4543 * options that should be checked. For example, if a view uses a
4544 * forwarder, changes in the forwarder configuration may invalidate
4545 * the cache. At the moment, it's the administrator's responsibility to
4546 * ensure these configuration options don't invalidate reusing/sharing.
4547 */
4548 obj = NULL;
4549 result = named_config_get(maps, "attach-cache", &obj);
4550 if (result == ISC_R_SUCCESS) {
4551 cachename = cfg_obj_asstring(obj);
4552 } else {
4553 cachename = view->name;
4554 }
4555 cache = NULL;
4556 nsc = cachelist_find(cachelist, cachename, view->rdclass);
4557 if (nsc != NULL) {
4558 if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
4559 max_cache_size, max_stale_ttl,
4560 stale_refresh_time))
4561 {
4562 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4563 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4564 "views %s and %s can't share the cache "
4565 "due to configuration parameter mismatch",
4566 nsc->primaryview->name, view->name);
4567 result = ISC_R_FAILURE;
4568 goto cleanup;
4569 }
4570 dns_cache_attach(nsc->cache, &cache);
4571 shared_cache = true;
4572 } else {
4573 if (strcmp(cachename, view->name) == 0) {
4574 result = dns_viewlist_find(&named_g_server->viewlist,
4575 cachename, view->rdclass,
4576 &pview);
4577 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4578 {
4579 goto cleanup;
4580 }
4581 if (pview != NULL) {
4582 if (!cache_reusable(pview, view,
4583 zero_no_soattl))
4584 {
4585 isc_log_write(named_g_lctx,
4586 NAMED_LOGCATEGORY_GENERAL,
4587 NAMED_LOGMODULE_SERVER,
4588 ISC_LOG_DEBUG(1),
4589 "cache cannot be reused "
4590 "for view %s due to "
4591 "configuration parameter "
4592 "mismatch",
4593 view->name);
4594 } else {
4595 INSIST(pview->cache != NULL);
4596 isc_log_write(named_g_lctx,
4597 NAMED_LOGCATEGORY_GENERAL,
4598 NAMED_LOGMODULE_SERVER,
4599 ISC_LOG_DEBUG(3),
4600 "reusing existing cache");
4601 reused_cache = true;
4602 dns_cache_attach(pview->cache, &cache);
4603 }
4604 dns_view_getresstats(pview, &resstats);
4605 dns_view_getresquerystats(pview,
4606 &resquerystats);
4607 dns_view_detach(&pview);
4608 }
4609 }
4610 if (cache == NULL) {
4611 /*
4612 * Create a cache with the desired name. This normally
4613 * equals the view name, but may also be a forward
4614 * reference to a view that share the cache with this
4615 * view but is not yet configured. If it is not the
4616 * view name but not a forward reference either, then it
4617 * is simply a named cache that is not shared.
4618 *
4619 * We use two separate memory contexts for the
4620 * cache, for the main cache memory and the heap
4621 * memory.
4622 */
4623 isc_mem_create(&cmctx);
4624 isc_mem_setname(cmctx, "cache", NULL);
4625 isc_mem_create(&hmctx);
4626 isc_mem_setname(hmctx, "cache_heap", NULL);
4627 CHECK(dns_cache_create(cmctx, hmctx, named_g_taskmgr,
4628 named_g_timermgr, view->rdclass,
4629 cachename, "rbt", 0, NULL,
4630 &cache));
4631 isc_mem_detach(&cmctx);
4632 isc_mem_detach(&hmctx);
4633 }
4634 nsc = isc_mem_get(mctx, sizeof(*nsc));
4635 nsc->cache = NULL;
4636 dns_cache_attach(cache, &nsc->cache);
4637 nsc->primaryview = view;
4638 nsc->needflush = false;
4639 nsc->adbsizeadjusted = false;
4640 nsc->rdclass = view->rdclass;
4641 ISC_LINK_INIT(nsc, link);
4642 ISC_LIST_APPEND(*cachelist, nsc, link);
4643 }
4644 dns_view_setcache(view, cache, shared_cache);
4645
4646 /*
4647 * cache-file cannot be inherited if views are present, but this
4648 * should be caught by the configuration checking stage.
4649 */
4650 obj = NULL;
4651 result = named_config_get(maps, "cache-file", &obj);
4652 if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
4653 CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
4654 if (!reused_cache && !shared_cache) {
4655 CHECK(dns_cache_load(cache));
4656 }
4657 }
4658
4659 dns_cache_setcachesize(cache, max_cache_size);
4660 dns_cache_setservestalettl(cache, max_stale_ttl);
4661 dns_cache_setservestalerefresh(cache, stale_refresh_time);
4662
4663 dns_cache_detach(&cache);
4664
4665 obj = NULL;
4666 result = named_config_get(maps, "stale-answer-ttl", &obj);
4667 INSIST(result == ISC_R_SUCCESS);
4668 view->staleanswerttl = ISC_MAX(cfg_obj_asduration(obj), 1);
4669
4670 /*
4671 * Resolver.
4672 *
4673 * XXXRTH Hardwired number of tasks.
4674 */
4675 CHECK(get_view_querysource_dispatch(
4676 maps, AF_INET, &dispatch4, &dscp4,
4677 (ISC_LIST_PREV(view, link) == NULL)));
4678 CHECK(get_view_querysource_dispatch(
4679 maps, AF_INET6, &dispatch6, &dscp6,
4680 (ISC_LIST_PREV(view, link) == NULL)));
4681 if (dispatch4 == NULL && dispatch6 == NULL) {
4682 UNEXPECTED_ERROR(__FILE__, __LINE__,
4683 "unable to obtain neither an IPv4 nor"
4684 " an IPv6 dispatch");
4685 result = ISC_R_UNEXPECTED;
4686 goto cleanup;
4687 }
4688
4689 if (resstats == NULL) {
4690 CHECK(isc_stats_create(mctx, &resstats,
4691 dns_resstatscounter_max));
4692 }
4693 dns_view_setresstats(view, resstats);
4694 if (resquerystats == NULL) {
4695 CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
4696 }
4697 dns_view_setresquerystats(view, resquerystats);
4698
4699 ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH);
4700 CHECK(dns_view_createresolver(
4701 view, named_g_taskmgr, RESOLVER_NTASKS_PERCPU * named_g_cpus,
4702 ndisp, named_g_socketmgr, named_g_timermgr, resopts,
4703 named_g_dispatchmgr, dispatch4, dispatch6));
4704
4705 if (dscp4 == -1) {
4706 dscp4 = named_g_dscp;
4707 }
4708 if (dscp6 == -1) {
4709 dscp6 = named_g_dscp;
4710 }
4711 if (dscp4 != -1) {
4712 dns_resolver_setquerydscp4(view->resolver, dscp4);
4713 }
4714 if (dscp6 != -1) {
4715 dns_resolver_setquerydscp6(view->resolver, dscp6);
4716 }
4717
4718 /*
4719 * Set the ADB cache size to 1/8th of the max-cache-size or
4720 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
4721 */
4722 max_adb_size = 0;
4723 if (max_cache_size != 0U) {
4724 max_adb_size = max_cache_size / 8;
4725 if (max_adb_size == 0U) {
4726 max_adb_size = 1; /* Force minimum. */
4727 }
4728 if (view != nsc->primaryview &&
4729 max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE)
4730 {
4731 max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
4732 if (!nsc->adbsizeadjusted) {
4733 dns_adb_setadbsize(nsc->primaryview->adb,
4734 MAX_ADB_SIZE_FOR_CACHESHARE);
4735 nsc->adbsizeadjusted = true;
4736 }
4737 }
4738 }
4739 dns_adb_setadbsize(view->adb, max_adb_size);
4740
4741 /*
4742 * Set up ADB quotas
4743 */
4744 {
4745 uint32_t fps, freq;
4746 double low, high, discount;
4747
4748 obj = NULL;
4749 result = named_config_get(maps, "fetches-per-server", &obj);
4750 INSIST(result == ISC_R_SUCCESS);
4751 obj2 = cfg_tuple_get(obj, "fetches");
4752 fps = cfg_obj_asuint32(obj2);
4753 obj2 = cfg_tuple_get(obj, "response");
4754 if (!cfg_obj_isvoid(obj2)) {
4755 const char *resp = cfg_obj_asstring(obj2);
4756 isc_result_t r = DNS_R_SERVFAIL;
4757
4758 if (strcasecmp(resp, "drop") == 0) {
4759 r = DNS_R_DROP;
4760 } else if (strcasecmp(resp, "fail") == 0) {
4761 r = DNS_R_SERVFAIL;
4762 } else {
4763 UNREACHABLE();
4764 }
4765
4766 dns_resolver_setquotaresponse(view->resolver,
4767 dns_quotatype_server, r);
4768 }
4769
4770 obj = NULL;
4771 result = named_config_get(maps, "fetch-quota-params", &obj);
4772 INSIST(result == ISC_R_SUCCESS);
4773
4774 obj2 = cfg_tuple_get(obj, "frequency");
4775 freq = cfg_obj_asuint32(obj2);
4776
4777 obj2 = cfg_tuple_get(obj, "low");
4778 low = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4779
4780 obj2 = cfg_tuple_get(obj, "high");
4781 high = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4782
4783 obj2 = cfg_tuple_get(obj, "discount");
4784 discount = (double)cfg_obj_asfixedpoint(obj2) / 100.0;
4785
4786 dns_adb_setquota(view->adb, fps, freq, low, high, discount);
4787 }
4788
4789 /*
4790 * Set resolver's lame-ttl.
4791 */
4792 obj = NULL;
4793 result = named_config_get(maps, "lame-ttl", &obj);
4794 INSIST(result == ISC_R_SUCCESS);
4795 lame_ttl = cfg_obj_asduration(obj);
4796 if (lame_ttl > 0) {
4797 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
4798 "disabling lame cache despite lame-ttl > 0 as it "
4799 "may cause performance issues");
4800 lame_ttl = 0;
4801 }
4802 dns_resolver_setlamettl(view->resolver, lame_ttl);
4803
4804 /*
4805 * Set the resolver's query timeout.
4806 */
4807 obj = NULL;
4808 result = named_config_get(maps, "resolver-query-timeout", &obj);
4809 INSIST(result == ISC_R_SUCCESS);
4810 query_timeout = cfg_obj_asuint32(obj);
4811 dns_resolver_settimeout(view->resolver, query_timeout);
4812
4813 /*
4814 * Adjust stale-answer-client-timeout upper bound
4815 * to be resolver-query-timeout - 1s.
4816 * This assignment is safe as dns_resolver_settimeout()
4817 * ensures that resolver->querytimeout value will be in the
4818 * [MINIMUM_QUERY_TIMEOUT, MAXIMUM_QUERY_TIMEOUT] range and
4819 * MINIMUM_QUERY_TIMEOUT is > 1000 (in ms).
4820 */
4821 if (view->staleanswerclienttimeout != (uint32_t)-1 &&
4822 view->staleanswerclienttimeout >
4823 (dns_resolver_gettimeout(view->resolver) - 1000))
4824 {
4825 view->staleanswerclienttimeout =
4826 dns_resolver_gettimeout(view->resolver) - 1000;
4827 isc_log_write(
4828 named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4829 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
4830 "stale-answer-client-timeout adjusted to %" PRIu32,
4831 view->staleanswerclienttimeout);
4832 }
4833
4834 /* Specify whether to use 0-TTL for negative response for SOA query */
4835 dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
4836
4837 /*
4838 * Set the resolver's EDNS UDP size.
4839 */
4840 obj = NULL;
4841 result = named_config_get(maps, "edns-udp-size", &obj);
4842 INSIST(result == ISC_R_SUCCESS);
4843 udpsize = cfg_obj_asuint32(obj);
4844 if (udpsize < 512) {
4845 udpsize = 512;
4846 }
4847 if (udpsize > 4096) {
4848 udpsize = 4096;
4849 }
4850 dns_resolver_setudpsize(view->resolver, (uint16_t)udpsize);
4851
4852 /*
4853 * Set the maximum UDP response size.
4854 */
4855 obj = NULL;
4856 result = named_config_get(maps, "max-udp-size", &obj);
4857 INSIST(result == ISC_R_SUCCESS);
4858 udpsize = cfg_obj_asuint32(obj);
4859 if (udpsize < 512) {
4860 udpsize = 512;
4861 }
4862 if (udpsize > 4096) {
4863 udpsize = 4096;
4864 }
4865 view->maxudp = udpsize;
4866
4867 /*
4868 * Set the maximum UDP when a COOKIE is not provided.
4869 */
4870 obj = NULL;
4871 result = named_config_get(maps, "nocookie-udp-size", &obj);
4872 INSIST(result == ISC_R_SUCCESS);
4873 udpsize = cfg_obj_asuint32(obj);
4874 if (udpsize < 128) {
4875 udpsize = 128;
4876 }
4877 if (udpsize > view->maxudp) {
4878 udpsize = view->maxudp;
4879 }
4880 view->nocookieudp = udpsize;
4881
4882 /*
4883 * Set the maximum rsa exponent bits.
4884 */
4885 obj = NULL;
4886 result = named_config_get(maps, "max-rsa-exponent-size", &obj);
4887 INSIST(result == ISC_R_SUCCESS);
4888 maxbits = cfg_obj_asuint32(obj);
4889 if (maxbits != 0 && maxbits < 35) {
4890 maxbits = 35;
4891 }
4892 if (maxbits > 4096) {
4893 maxbits = 4096;
4894 }
4895 view->maxbits = maxbits;
4896
4897 /*
4898 * Set resolver retry parameters.
4899 */
4900 obj = NULL;
4901 CHECK(named_config_get(maps, "resolver-retry-interval", &obj));
4902 resolver_param = cfg_obj_asuint32(obj);
4903 if (resolver_param > 0) {
4904 dns_resolver_setretryinterval(view->resolver, resolver_param);
4905 }
4906
4907 obj = NULL;
4908 CHECK(named_config_get(maps, "resolver-nonbackoff-tries", &obj));
4909 resolver_param = cfg_obj_asuint32(obj);
4910 if (resolver_param > 0) {
4911 dns_resolver_setnonbackofftries(view->resolver, resolver_param);
4912 }
4913
4914 /*
4915 * Set supported DNSSEC algorithms.
4916 */
4917 dns_resolver_reset_algorithms(view->resolver);
4918 disabled = NULL;
4919 (void)named_config_get(maps, "disable-algorithms", &disabled);
4920 if (disabled != NULL) {
4921 for (element = cfg_list_first(disabled); element != NULL;
4922 element = cfg_list_next(element))
4923 {
4924 CHECK(disable_algorithms(cfg_listelt_value(element),
4925 view->resolver));
4926 }
4927 }
4928
4929 /*
4930 * Set supported DS digest types.
4931 */
4932 dns_resolver_reset_ds_digests(view->resolver);
4933 disabled = NULL;
4934 (void)named_config_get(maps, "disable-ds-digests", &disabled);
4935 if (disabled != NULL) {
4936 for (element = cfg_list_first(disabled); element != NULL;
4937 element = cfg_list_next(element))
4938 {
4939 CHECK(disable_ds_digests(cfg_listelt_value(element),
4940 view->resolver));
4941 }
4942 }
4943
4944 /*
4945 * A global or view "forwarders" option, if present,
4946 * creates an entry for "." in the forwarding table.
4947 */
4948 forwardtype = NULL;
4949 forwarders = NULL;
4950 (void)named_config_get(maps, "forward", &forwardtype);
4951 (void)named_config_get(maps, "forwarders", &forwarders);
4952 if (forwarders != NULL) {
4953 CHECK(configure_forward(config, view, dns_rootname, forwarders,
4954 forwardtype));
4955 }
4956
4957 /*
4958 * Dual Stack Servers.
4959 */
4960 alternates = NULL;
4961 (void)named_config_get(maps, "dual-stack-servers", &alternates);
4962 if (alternates != NULL) {
4963 CHECK(configure_alternates(config, view, alternates));
4964 }
4965
4966 /*
4967 * We have default hints for class IN if we need them.
4968 */
4969 if (view->rdclass == dns_rdataclass_in && view->hints == NULL) {
4970 dns_view_sethints(view, named_g_server->in_roothints);
4971 }
4972
4973 /*
4974 * If we still have no hints, this is a non-IN view with no
4975 * "hints zone" configured. Issue a warning, except if this
4976 * is a root server. Root servers never need to consult
4977 * their hints, so it's no point requiring users to configure
4978 * them.
4979 */
4980 if (view->hints == NULL) {
4981 dns_zone_t *rootzone = NULL;
4982 (void)dns_view_findzone(view, dns_rootname, &rootzone);
4983 if (rootzone != NULL) {
4984 dns_zone_detach(&rootzone);
4985 need_hints = false;
4986 }
4987 if (need_hints) {
4988 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4989 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
4990 "no root hints for view '%s'",
4991 view->name);
4992 }
4993 }
4994
4995 /*
4996 * Configure the view's TSIG keys.
4997 */
4998 CHECK(named_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
4999 if (named_g_server->sessionkey != NULL) {
5000 CHECK(dns_tsigkeyring_add(ring, named_g_server->session_keyname,
5001 named_g_server->sessionkey));
5002 }
5003 dns_view_setkeyring(view, ring);
5004 dns_tsigkeyring_detach(&ring);
5005
5006 /*
5007 * See if we can re-use a dynamic key ring.
5008 */
5009 result = dns_viewlist_find(&named_g_server->viewlist, view->name,
5010 view->rdclass, &pview);
5011 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
5012 goto cleanup;
5013 }
5014 if (pview != NULL) {
5015 dns_view_getdynamickeyring(pview, &ring);
5016 if (ring != NULL) {
5017 dns_view_setdynamickeyring(view, ring);
5018 }
5019 dns_tsigkeyring_detach(&ring);
5020 dns_view_detach(&pview);
5021 } else {
5022 dns_view_restorekeyring(view);
5023 }
5024
5025 /*
5026 * Configure the view's peer list.
5027 */
5028 {
5029 const cfg_obj_t *peers = NULL;
5030 dns_peerlist_t *newpeers = NULL;
5031
5032 (void)named_config_get(cfgmaps, "server", &peers);
5033 CHECK(dns_peerlist_new(mctx, &newpeers));
5034 for (element = cfg_list_first(peers); element != NULL;
5035 element = cfg_list_next(element))
5036 {
5037 const cfg_obj_t *cpeer = cfg_listelt_value(element);
5038 dns_peer_t *peer;
5039
5040 CHECK(configure_peer(cpeer, mctx, &peer));
5041 dns_peerlist_addpeer(newpeers, peer);
5042 dns_peer_detach(&peer);
5043 }
5044 dns_peerlist_detach(&view->peers);
5045 view->peers = newpeers; /* Transfer ownership. */
5046 }
5047
5048 /*
5049 * Configure the views rrset-order.
5050 */
5051 {
5052 const cfg_obj_t *rrsetorder = NULL;
5053
5054 (void)named_config_get(maps, "rrset-order", &rrsetorder);
5055 CHECK(dns_order_create(mctx, &order));
5056 for (element = cfg_list_first(rrsetorder); element != NULL;
5057 element = cfg_list_next(element))
5058 {
5059 const cfg_obj_t *ent = cfg_listelt_value(element);
5060
5061 CHECK(configure_order(order, ent));
5062 }
5063 if (view->order != NULL) {
5064 dns_order_detach(&view->order);
5065 }
5066 dns_order_attach(order, &view->order);
5067 dns_order_detach(&order);
5068 }
5069 /*
5070 * Copy the aclenv object.
5071 */
5072 dns_aclenv_copy(&view->aclenv, ns_interfacemgr_getaclenv(
5073 named_g_server->interfacemgr));
5074
5075 /*
5076 * Configure the "match-clients" and "match-destinations" ACL.
5077 * (These are only meaningful at the view level, but 'config'
5078 * must be passed so that named ACLs defined at the global level
5079 * can be retrieved.)
5080 */
5081 CHECK(configure_view_acl(vconfig, config, NULL, "match-clients", NULL,
5082 actx, named_g_mctx, &view->matchclients));
5083 CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations",
5084 NULL, actx, named_g_mctx,
5085 &view->matchdestinations));
5086
5087 /*
5088 * Configure the "match-recursive-only" option.
5089 */
5090 obj = NULL;
5091 (void)named_config_get(maps, "match-recursive-only", &obj);
5092 if (obj != NULL && cfg_obj_asboolean(obj)) {
5093 view->matchrecursiveonly = true;
5094 } else {
5095 view->matchrecursiveonly = false;
5096 }
5097
5098 /*
5099 * Configure other configurable data.
5100 */
5101 obj = NULL;
5102 result = named_config_get(maps, "recursion", &obj);
5103 INSIST(result == ISC_R_SUCCESS);
5104 view->recursion = cfg_obj_asboolean(obj);
5105
5106 obj = NULL;
5107 result = named_config_get(maps, "qname-minimization", &obj);
5108 INSIST(result == ISC_R_SUCCESS);
5109 qminmode = cfg_obj_asstring(obj);
5110 INSIST(qminmode != NULL);
5111 if (!strcmp(qminmode, "strict")) {
5112 view->qminimization = true;
5113 view->qmin_strict = true;
5114 } else if (!strcmp(qminmode, "relaxed")) {
5115 view->qminimization = true;
5116 view->qmin_strict = false;
5117 } else { /* "disabled" or "off" */
5118 view->qminimization = false;
5119 view->qmin_strict = false;
5120 }
5121
5122 obj = NULL;
5123 result = named_config_get(maps, "auth-nxdomain", &obj);
5124 INSIST(result == ISC_R_SUCCESS);
5125 view->auth_nxdomain = cfg_obj_asboolean(obj);
5126
5127 obj = NULL;
5128 result = named_config_get(maps, "glue-cache", &obj);
5129 INSIST(result == ISC_R_SUCCESS);
5130 view->use_glue_cache = cfg_obj_asboolean(obj);
5131
5132 obj = NULL;
5133 result = named_config_get(maps, "minimal-any", &obj);
5134 INSIST(result == ISC_R_SUCCESS);
5135 view->minimal_any = cfg_obj_asboolean(obj);
5136
5137 obj = NULL;
5138 result = named_config_get(maps, "minimal-responses", &obj);
5139 INSIST(result == ISC_R_SUCCESS);
5140 if (cfg_obj_isboolean(obj)) {
5141 if (cfg_obj_asboolean(obj)) {
5142 view->minimalresponses = dns_minimal_yes;
5143 } else {
5144 view->minimalresponses = dns_minimal_no;
5145 }
5146 } else {
5147 str = cfg_obj_asstring(obj);
5148 if (strcasecmp(str, "no-auth") == 0) {
5149 view->minimalresponses = dns_minimal_noauth;
5150 } else if (strcasecmp(str, "no-auth-recursive") == 0) {
5151 view->minimalresponses = dns_minimal_noauthrec;
5152 } else {
5153 UNREACHABLE();
5154 }
5155 }
5156
5157 obj = NULL;
5158 result = named_config_get(maps, "transfer-format", &obj);
5159 INSIST(result == ISC_R_SUCCESS);
5160 str = cfg_obj_asstring(obj);
5161 if (strcasecmp(str, "many-answers") == 0) {
5162 view->transfer_format = dns_many_answers;
5163 } else if (strcasecmp(str, "one-answer") == 0) {
5164 view->transfer_format = dns_one_answer;
5165 } else {
5166 UNREACHABLE();
5167 }
5168
5169 obj = NULL;
5170 result = named_config_get(maps, "trust-anchor-telemetry", &obj);
5171 INSIST(result == ISC_R_SUCCESS);
5172 view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
5173
5174 obj = NULL;
5175 result = named_config_get(maps, "root-key-sentinel", &obj);
5176 INSIST(result == ISC_R_SUCCESS);
5177 view->root_key_sentinel = cfg_obj_asboolean(obj);
5178
5179 /*
5180 * Set the "allow-query", "allow-query-cache", "allow-recursion",
5181 * "allow-recursion-on" and "allow-query-cache-on" ACLs if
5182 * configured in named.conf, but NOT from the global defaults.
5183 * This is done by leaving the third argument to configure_view_acl()
5184 * NULL.
5185 *
5186 * We ignore the global defaults here because these ACLs
5187 * can inherit from each other. If any are still unset after
5188 * applying the inheritance rules, we'll look up the defaults at
5189 * that time.
5190 */
5191
5192 /* named.conf only */
5193 CHECK(configure_view_acl(vconfig, config, NULL, "allow-query", NULL,
5194 actx, named_g_mctx, &view->queryacl));
5195
5196 /* named.conf only */
5197 CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache",
5198 NULL, actx, named_g_mctx, &view->cacheacl));
5199 /* named.conf only */
5200 CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
5201 NULL, actx, named_g_mctx, &view->cacheonacl));
5202
5203 if (strcmp(view->name, "_bind") != 0 &&
5204 view->rdclass != dns_rdataclass_chaos)
5205 {
5206 /* named.conf only */
5207 CHECK(configure_view_acl(vconfig, config, NULL,
5208 "allow-recursion", NULL, actx,
5209 named_g_mctx, &view->recursionacl));
5210 /* named.conf only */
5211 CHECK(configure_view_acl(vconfig, config, NULL,
5212 "allow-recursion-on", NULL, actx,
5213 named_g_mctx, &view->recursiononacl));
5214 }
5215
5216 if (view->recursion) {
5217 /*
5218 * "allow-query-cache" inherits from "allow-recursion" if set,
5219 * otherwise from "allow-query" if set.
5220 */
5221 if (view->cacheacl == NULL) {
5222 if (view->recursionacl != NULL) {
5223 dns_acl_attach(view->recursionacl,
5224 &view->cacheacl);
5225 } else if (view->queryacl != NULL) {
5226 dns_acl_attach(view->queryacl, &view->cacheacl);
5227 }
5228 }
5229
5230 /*
5231 * "allow-recursion" inherits from "allow-query-cache" if set,
5232 * otherwise from "allow-query" if set.
5233 */
5234 if (view->recursionacl == NULL) {
5235 if (view->cacheacl != NULL) {
5236 dns_acl_attach(view->cacheacl,
5237 &view->recursionacl);
5238 } else if (view->queryacl != NULL) {
5239 dns_acl_attach(view->queryacl,
5240 &view->recursionacl);
5241 }
5242 }
5243
5244 /*
5245 * "allow-query-cache-on" inherits from "allow-recursion-on"
5246 * if set.
5247 */
5248 if (view->cacheonacl == NULL) {
5249 if (view->recursiononacl != NULL) {
5250 dns_acl_attach(view->recursiononacl,
5251 &view->cacheonacl);
5252 }
5253 }
5254
5255 /*
5256 * "allow-recursion-on" inherits from "allow-query-cache-on"
5257 * if set.
5258 */
5259 if (view->recursiononacl == NULL) {
5260 if (view->cacheonacl != NULL) {
5261 dns_acl_attach(view->cacheonacl,
5262 &view->recursiononacl);
5263 }
5264 }
5265
5266 /*
5267 * If any are still unset at this point, we now get default
5268 * values for from the global config.
5269 */
5270
5271 if (view->recursionacl == NULL) {
5272 /* global default only */
5273 CHECK(configure_view_acl(
5274 NULL, NULL, named_g_config, "allow-recursion",
5275 NULL, actx, named_g_mctx, &view->recursionacl));
5276 }
5277 if (view->recursiononacl == NULL) {
5278 /* global default only */
5279 CHECK(configure_view_acl(NULL, NULL, named_g_config,
5280 "allow-recursion-on", NULL,
5281 actx, named_g_mctx,
5282 &view->recursiononacl));
5283 }
5284 if (view->cacheacl == NULL) {
5285 /* global default only */
5286 CHECK(configure_view_acl(
5287 NULL, NULL, named_g_config, "allow-query-cache",
5288 NULL, actx, named_g_mctx, &view->cacheacl));
5289 }
5290 if (view->cacheonacl == NULL) {
5291 /* global default only */
5292 CHECK(configure_view_acl(NULL, NULL, named_g_config,
5293 "allow-query-cache-on", NULL,
5294 actx, named_g_mctx,
5295 &view->cacheonacl));
5296 }
5297 } else {
5298 /*
5299 * We're not recursive; if the query-cache ACLs haven't
5300 * been set at the options/view level, set them to none.
5301 */
5302 if (view->cacheacl == NULL) {
5303 CHECK(dns_acl_none(mctx, &view->cacheacl));
5304 }
5305 if (view->cacheonacl == NULL) {
5306 CHECK(dns_acl_none(mctx, &view->cacheonacl));
5307 }
5308 }
5309
5310 /*
5311 * Finished setting recursion and query-cache ACLs, so now we
5312 * can get the allow-query default if it wasn't set in named.conf
5313 */
5314 if (view->queryacl == NULL) {
5315 /* global default only */
5316 CHECK(configure_view_acl(NULL, NULL, named_g_config,
5317 "allow-query", NULL, actx,
5318 named_g_mctx, &view->queryacl));
5319 }
5320
5321 /*
5322 * Ignore case when compressing responses to the specified
5323 * clients. This causes case not always to be preserved,
5324 * and is needed by some broken clients.
5325 */
5326 CHECK(configure_view_acl(vconfig, config, named_g_config,
5327 "no-case-compress", NULL, actx, named_g_mctx,
5328 &view->nocasecompress));
5329
5330 /*
5331 * Disable name compression completely, this is a tradeoff
5332 * between CPU and network usage.
5333 */
5334 obj = NULL;
5335 result = named_config_get(maps, "message-compression", &obj);
5336 INSIST(result == ISC_R_SUCCESS);
5337 view->msgcompression = cfg_obj_asboolean(obj);
5338
5339 /*
5340 * Filter setting on addresses in the answer section.
5341 */
5342 CHECK(configure_view_acl(vconfig, config, named_g_config,
5343 "deny-answer-addresses", "acl", actx,
5344 named_g_mctx, &view->denyansweracl));
5345 CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
5346 "except-from", named_g_mctx,
5347 &view->answeracl_exclude));
5348
5349 /*
5350 * Filter setting on names (CNAME/DNAME targets) in the answer section.
5351 */
5352 CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5353 "name", named_g_mctx,
5354 &view->denyanswernames));
5355 CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5356 "except-from", named_g_mctx,
5357 &view->answernames_exclude));
5358
5359 /*
5360 * Configure sortlist, if set
5361 */
5362 CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx,
5363 &view->sortlist));
5364
5365 /*
5366 * Configure default allow-update and allow-update-forwarding ACLs,
5367 * so they can be inherited by zones. (XXX: These are not
5368 * read from the options/view level here. However, they may be
5369 * read from there in zoneconf.c:configure_zone_acl() later.)
5370 */
5371 if (view->updateacl == NULL) {
5372 CHECK(configure_view_acl(NULL, NULL, named_g_config,
5373 "allow-update", NULL, actx,
5374 named_g_mctx, &view->updateacl));
5375 }
5376 if (view->upfwdacl == NULL) {
5377 CHECK(configure_view_acl(NULL, NULL, named_g_config,
5378 "allow-update-forwarding", NULL, actx,
5379 named_g_mctx, &view->upfwdacl));
5380 }
5381
5382 /*
5383 * Configure default allow-transfer and allow-notify ACLs so they
5384 * can be inherited by zones.
5385 */
5386 if (view->transferacl == NULL) {
5387 CHECK(configure_view_acl(vconfig, config, named_g_config,
5388 "allow-transfer", NULL, actx,
5389 named_g_mctx, &view->transferacl));
5390 }
5391 if (view->notifyacl == NULL) {
5392 CHECK(configure_view_acl(vconfig, config, named_g_config,
5393 "allow-notify", NULL, actx,
5394 named_g_mctx, &view->notifyacl));
5395 }
5396
5397 obj = NULL;
5398 result = named_config_get(maps, "provide-ixfr", &obj);
5399 INSIST(result == ISC_R_SUCCESS);
5400 view->provideixfr = cfg_obj_asboolean(obj);
5401
5402 obj = NULL;
5403 result = named_config_get(maps, "request-nsid", &obj);
5404 INSIST(result == ISC_R_SUCCESS);
5405 view->requestnsid = cfg_obj_asboolean(obj);
5406
5407 obj = NULL;
5408 result = named_config_get(maps, "send-cookie", &obj);
5409 INSIST(result == ISC_R_SUCCESS);
5410 view->sendcookie = cfg_obj_asboolean(obj);
5411
5412 obj = NULL;
5413 if (view->pad_acl != NULL) {
5414 dns_acl_detach(&view->pad_acl);
5415 }
5416 result = named_config_get(optionmaps, "response-padding", &obj);
5417 if (result == ISC_R_SUCCESS) {
5418 const cfg_obj_t *padobj = cfg_tuple_get(obj, "block-size");
5419 const cfg_obj_t *aclobj = cfg_tuple_get(obj, "acl");
5420 uint32_t padding = cfg_obj_asuint32(padobj);
5421
5422 if (padding > 512U) {
5423 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
5424 "response-padding block-size cannot "
5425 "exceed 512: lowering");
5426 padding = 512U;
5427 }
5428 view->padding = (uint16_t)padding;
5429 CHECK(cfg_acl_fromconfig(aclobj, config, named_g_lctx, actx,
5430 named_g_mctx, 0, &view->pad_acl));
5431 }
5432
5433 obj = NULL;
5434 result = named_config_get(maps, "require-server-cookie", &obj);
5435 INSIST(result == ISC_R_SUCCESS);
5436 view->requireservercookie = cfg_obj_asboolean(obj);
5437
5438 obj = NULL;
5439 result = named_config_get(maps, "v6-bias", &obj);
5440 INSIST(result == ISC_R_SUCCESS);
5441 view->v6bias = cfg_obj_asuint32(obj) * 1000;
5442
5443 obj = NULL;
5444 result = named_config_get(maps, "max-clients-per-query", &obj);
5445 INSIST(result == ISC_R_SUCCESS);
5446 max_clients_per_query = cfg_obj_asuint32(obj);
5447
5448 obj = NULL;
5449 result = named_config_get(maps, "clients-per-query", &obj);
5450 INSIST(result == ISC_R_SUCCESS);
5451 dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj),
5452 max_clients_per_query);
5453
5454 obj = NULL;
5455 result = named_config_get(maps, "max-recursion-depth", &obj);
5456 INSIST(result == ISC_R_SUCCESS);
5457 dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
5458
5459 obj = NULL;
5460 result = named_config_get(maps, "max-recursion-queries", &obj);
5461 INSIST(result == ISC_R_SUCCESS);
5462 dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
5463
5464 obj = NULL;
5465 result = named_config_get(maps, "fetches-per-zone", &obj);
5466 INSIST(result == ISC_R_SUCCESS);
5467 obj2 = cfg_tuple_get(obj, "fetches");
5468 dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
5469 obj2 = cfg_tuple_get(obj, "response");
5470 if (!cfg_obj_isvoid(obj2)) {
5471 const char *resp = cfg_obj_asstring(obj2);
5472 isc_result_t r = DNS_R_SERVFAIL;
5473
5474 if (strcasecmp(resp, "drop") == 0) {
5475 r = DNS_R_DROP;
5476 } else if (strcasecmp(resp, "fail") == 0) {
5477 r = DNS_R_SERVFAIL;
5478 } else {
5479 UNREACHABLE();
5480 }
5481
5482 dns_resolver_setquotaresponse(view->resolver,
5483 dns_quotatype_zone, r);
5484 }
5485
5486 obj = NULL;
5487 result = named_config_get(maps, "prefetch", &obj);
5488 INSIST(result == ISC_R_SUCCESS);
5489 prefetch_trigger = cfg_tuple_get(obj, "trigger");
5490 view->prefetch_trigger = cfg_obj_asuint32(prefetch_trigger);
5491 if (view->prefetch_trigger > 10) {
5492 view->prefetch_trigger = 10;
5493 }
5494 prefetch_eligible = cfg_tuple_get(obj, "eligible");
5495 if (cfg_obj_isvoid(prefetch_eligible)) {
5496 int m;
5497 for (m = 1; maps[m] != NULL; m++) {
5498 obj = NULL;
5499 result = named_config_get(&maps[m], "prefetch", &obj);
5500 INSIST(result == ISC_R_SUCCESS);
5501 prefetch_eligible = cfg_tuple_get(obj, "eligible");
5502 if (cfg_obj_isuint32(prefetch_eligible)) {
5503 break;
5504 }
5505 }
5506 INSIST(cfg_obj_isuint32(prefetch_eligible));
5507 }
5508 view->prefetch_eligible = cfg_obj_asuint32(prefetch_eligible);
5509 if (view->prefetch_eligible < view->prefetch_trigger + 6) {
5510 view->prefetch_eligible = view->prefetch_trigger + 6;
5511 }
5512
5513 /*
5514 * For now, there is only one kind of trusted keys, the
5515 * "security roots".
5516 */
5517 CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
5518 auto_root, mctx));
5519 dns_resolver_resetmustbesecure(view->resolver);
5520 obj = NULL;
5521 result = named_config_get(maps, "dnssec-must-be-secure", &obj);
5522 if (result == ISC_R_SUCCESS) {
5523 CHECK(mustbesecure(obj, view->resolver));
5524 }
5525
5526 obj = NULL;
5527 result = named_config_get(maps, "nta-recheck", &obj);
5528 INSIST(result == ISC_R_SUCCESS);
5529 view->nta_recheck = cfg_obj_asduration(obj);
5530
5531 obj = NULL;
5532 result = named_config_get(maps, "nta-lifetime", &obj);
5533 INSIST(result == ISC_R_SUCCESS);
5534 view->nta_lifetime = cfg_obj_asduration(obj);
5535
5536 obj = NULL;
5537 result = named_config_get(maps, "preferred-glue", &obj);
5538 if (result == ISC_R_SUCCESS) {
5539 str = cfg_obj_asstring(obj);
5540 if (strcasecmp(str, "a") == 0) {
5541 view->preferred_glue = dns_rdatatype_a;
5542 } else if (strcasecmp(str, "aaaa") == 0) {
5543 view->preferred_glue = dns_rdatatype_aaaa;
5544 } else {
5545 view->preferred_glue = 0;
5546 }
5547 } else {
5548 view->preferred_glue = 0;
5549 }
5550
5551 obj = NULL;
5552 result = named_config_get(maps, "root-delegation-only", &obj);
5553 if (result == ISC_R_SUCCESS) {
5554 dns_view_setrootdelonly(view, true);
5555 }
5556 if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
5557 const cfg_obj_t *exclude;
5558 dns_fixedname_t fixed;
5559 dns_name_t *name;
5560
5561 name = dns_fixedname_initname(&fixed);
5562 for (element = cfg_list_first(obj); element != NULL;
5563 element = cfg_list_next(element))
5564 {
5565 exclude = cfg_listelt_value(element);
5566 CHECK(dns_name_fromstring(
5567 name, cfg_obj_asstring(exclude), 0, NULL));
5568 CHECK(dns_view_excludedelegationonly(view, name));
5569 }
5570 } else {
5571 dns_view_setrootdelonly(view, false);
5572 }
5573
5574 /*
5575 * Load DynDB modules.
5576 */
5577 dyndb_list = NULL;
5578 if (voptions != NULL) {
5579 (void)cfg_map_get(voptions, "dyndb", &dyndb_list);
5580 } else {
5581 (void)cfg_map_get(config, "dyndb", &dyndb_list);
5582 }
5583
5584 #ifdef HAVE_DLOPEN
5585 for (element = cfg_list_first(dyndb_list); element != NULL;
5586 element = cfg_list_next(element))
5587 {
5588 const cfg_obj_t *dyndb = cfg_listelt_value(element);
5589
5590 if (dctx == NULL) {
5591 const void *hashinit = isc_hash_get_initializer();
5592 CHECK(dns_dyndb_createctx(mctx, hashinit, named_g_lctx,
5593 view, named_g_server->zonemgr,
5594 named_g_server->task,
5595 named_g_timermgr, &dctx));
5596 }
5597
5598 CHECK(configure_dyndb(dyndb, mctx, dctx));
5599 }
5600 #endif /* ifdef HAVE_DLOPEN */
5601
5602 /*
5603 * Load plugins.
5604 */
5605 plugin_list = NULL;
5606 if (voptions != NULL) {
5607 (void)cfg_map_get(voptions, "plugin", &plugin_list);
5608 } else {
5609 (void)cfg_map_get(config, "plugin", &plugin_list);
5610 }
5611
5612 #ifdef HAVE_DLOPEN
5613 if (plugin_list != NULL) {
5614 INSIST(view->hooktable == NULL);
5615 CHECK(ns_hooktable_create(view->mctx,
5616 (ns_hooktable_t **)&view->hooktable));
5617 view->hooktable_free = ns_hooktable_free;
5618
5619 ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
5620 view->plugins_free = ns_plugins_free;
5621
5622 CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
5623 register_one_plugin, view));
5624 }
5625 #endif /* ifdef HAVE_DLOPEN */
5626
5627 /*
5628 * Setup automatic empty zones. If recursion is off then
5629 * they are disabled by default.
5630 */
5631 obj = NULL;
5632 (void)named_config_get(maps, "empty-zones-enable", &obj);
5633 (void)named_config_get(maps, "disable-empty-zone", &disablelist);
5634 if (obj == NULL && disablelist == NULL &&
5635 view->rdclass == dns_rdataclass_in)
5636 {
5637 empty_zones_enable = view->recursion;
5638 } else if (view->rdclass == dns_rdataclass_in) {
5639 if (obj != NULL) {
5640 empty_zones_enable = cfg_obj_asboolean(obj);
5641 } else {
5642 empty_zones_enable = view->recursion;
5643 }
5644 } else {
5645 empty_zones_enable = false;
5646 }
5647
5648 if (empty_zones_enable) {
5649 const char *empty;
5650 int empty_zone = 0;
5651 dns_fixedname_t fixed;
5652 dns_name_t *name;
5653 isc_buffer_t buffer;
5654 char server[DNS_NAME_FORMATSIZE + 1];
5655 char contact[DNS_NAME_FORMATSIZE + 1];
5656 const char *empty_dbtype[4] = { "_builtin", "empty", NULL,
5657 NULL };
5658 int empty_dbtypec = 4;
5659 dns_zonestat_level_t statlevel = dns_zonestat_none;
5660
5661 name = dns_fixedname_initname(&fixed);
5662
5663 obj = NULL;
5664 result = named_config_get(maps, "empty-server", &obj);
5665 if (result == ISC_R_SUCCESS) {
5666 CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5667 0, NULL));
5668 isc_buffer_init(&buffer, server, sizeof(server) - 1);
5669 CHECK(dns_name_totext(name, false, &buffer));
5670 server[isc_buffer_usedlength(&buffer)] = 0;
5671 empty_dbtype[2] = server;
5672 } else {
5673 empty_dbtype[2] = "@";
5674 }
5675
5676 obj = NULL;
5677 result = named_config_get(maps, "empty-contact", &obj);
5678 if (result == ISC_R_SUCCESS) {
5679 CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5680 0, NULL));
5681 isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
5682 CHECK(dns_name_totext(name, false, &buffer));
5683 contact[isc_buffer_usedlength(&buffer)] = 0;
5684 empty_dbtype[3] = contact;
5685 } else {
5686 empty_dbtype[3] = ".";
5687 }
5688
5689 obj = NULL;
5690 result = named_config_get(maps, "zone-statistics", &obj);
5691 INSIST(result == ISC_R_SUCCESS);
5692 if (cfg_obj_isboolean(obj)) {
5693 if (cfg_obj_asboolean(obj)) {
5694 statlevel = dns_zonestat_full;
5695 } else {
5696 statlevel = dns_zonestat_none;
5697 }
5698 } else {
5699 const char *levelstr = cfg_obj_asstring(obj);
5700 if (strcasecmp(levelstr, "full") == 0) {
5701 statlevel = dns_zonestat_full;
5702 } else if (strcasecmp(levelstr, "terse") == 0) {
5703 statlevel = dns_zonestat_terse;
5704 } else if (strcasecmp(levelstr, "none") == 0) {
5705 statlevel = dns_zonestat_none;
5706 } else {
5707 UNREACHABLE();
5708 }
5709 }
5710
5711 for (empty = empty_zones[empty_zone]; empty != NULL;
5712 empty = empty_zones[++empty_zone])
5713 {
5714 dns_forwarders_t *dnsforwarders = NULL;
5715
5716 /*
5717 * Look for zone on drop list.
5718 */
5719 CHECK(dns_name_fromstring(name, empty, 0, NULL));
5720 if (disablelist != NULL &&
5721 on_disable_list(disablelist, name))
5722 {
5723 continue;
5724 }
5725
5726 /*
5727 * This zone already exists.
5728 */
5729 (void)dns_view_findzone(view, name, &zone);
5730 if (zone != NULL) {
5731 dns_zone_detach(&zone);
5732 continue;
5733 }
5734
5735 /*
5736 * If we would forward this name don't add a
5737 * empty zone for it.
5738 */
5739 result = dns_fwdtable_find(view->fwdtable, name, NULL,
5740 &dnsforwarders);
5741 if (result == ISC_R_SUCCESS &&
5742 dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
5743 {
5744 continue;
5745 }
5746
5747 /*
5748 * See if we can re-use a existing zone.
5749 */
5750 result = dns_viewlist_find(&named_g_server->viewlist,
5751 view->name, view->rdclass,
5752 &pview);
5753 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
5754 {
5755 goto cleanup;
5756 }
5757
5758 if (pview != NULL) {
5759 (void)dns_view_findzone(pview, name, &zone);
5760 dns_view_detach(&pview);
5761 }
5762
5763 CHECK(create_empty_zone(zone, name, view, zonelist,
5764 empty_dbtype, empty_dbtypec,
5765 statlevel));
5766 if (zone != NULL) {
5767 dns_zone_detach(&zone);
5768 }
5769 }
5770 }
5771
5772 obj = NULL;
5773 result = named_config_get(maps, "rate-limit", &obj);
5774 if (result == ISC_R_SUCCESS) {
5775 result = configure_rrl(view, config, obj);
5776 if (result != ISC_R_SUCCESS) {
5777 goto cleanup;
5778 }
5779 }
5780
5781 /*
5782 * Set the servfail-ttl.
5783 */
5784 obj = NULL;
5785 result = named_config_get(maps, "servfail-ttl", &obj);
5786 INSIST(result == ISC_R_SUCCESS);
5787 fail_ttl = cfg_obj_asduration(obj);
5788 if (fail_ttl > 30) {
5789 fail_ttl = 30;
5790 }
5791 dns_view_setfailttl(view, fail_ttl);
5792
5793 /*
5794 * Name space to look up redirect information in.
5795 */
5796 obj = NULL;
5797 result = named_config_get(maps, "nxdomain-redirect", &obj);
5798 if (result == ISC_R_SUCCESS) {
5799 dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
5800 CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0,
5801 NULL));
5802 view->redirectzone = name;
5803 } else {
5804 view->redirectzone = NULL;
5805 }
5806
5807 /*
5808 * Exceptions to DNSSEC validation.
5809 */
5810 obj = NULL;
5811 result = named_config_get(maps, "validate-except", &obj);
5812 if (result == ISC_R_SUCCESS) {
5813 result = dns_view_getntatable(view, &ntatable);
5814 }
5815 if (result == ISC_R_SUCCESS) {
5816 for (element = cfg_list_first(obj); element != NULL;
5817 element = cfg_list_next(element))
5818 {
5819 dns_fixedname_t fntaname;
5820 dns_name_t *ntaname;
5821
5822 ntaname = dns_fixedname_initname(&fntaname);
5823 obj = cfg_listelt_value(element);
5824 CHECK(dns_name_fromstring(
5825 ntaname, cfg_obj_asstring(obj), 0, NULL));
5826 CHECK(dns_ntatable_add(ntatable, ntaname, true, 0,
5827 0xffffffffU));
5828 }
5829 }
5830
5831 #ifdef HAVE_DNSTAP
5832 /*
5833 * Set up the dnstap environment and configure message
5834 * types to log.
5835 */
5836 CHECK(configure_dnstap(maps, view));
5837 #endif /* HAVE_DNSTAP */
5838
5839 result = ISC_R_SUCCESS;
5840
5841 cleanup:
5842 /*
5843 * Revert to the old view if there was an error.
5844 */
5845 if (result != ISC_R_SUCCESS) {
5846 isc_result_t result2;
5847
5848 result2 = dns_viewlist_find(&named_g_server->viewlist,
5849 view->name, view->rdclass, &pview);
5850 if (result2 == ISC_R_SUCCESS) {
5851 dns_view_thaw(pview);
5852
5853 obj = NULL;
5854 if (rpz_configured &&
5855 pview->rdclass == dns_rdataclass_in && need_hints &&
5856 named_config_get(maps, "response-policy", &obj) ==
5857 ISC_R_SUCCESS)
5858 {
5859 /*
5860 * We are swapping the places of the `view` and
5861 * `pview` in the function's parameters list
5862 * because we are reverting the same operation
5863 * done previously in the "correct" order.
5864 */
5865 result2 = configure_rpz(pview, view, maps, obj,
5866 &old_rpz_ok);
5867 if (result2 != ISC_R_SUCCESS) {
5868 isc_log_write(named_g_lctx,
5869 NAMED_LOGCATEGORY_GENERAL,
5870 NAMED_LOGMODULE_SERVER,
5871 ISC_LOG_ERROR,
5872 "rpz configuration "
5873 "revert failed for view "
5874 "'%s'",
5875 pview->name);
5876 }
5877 }
5878
5879 obj = NULL;
5880 if (catz_configured &&
5881 pview->rdclass == dns_rdataclass_in && need_hints &&
5882 named_config_get(maps, "catalog-zones", &obj) ==
5883 ISC_R_SUCCESS)
5884 {
5885 /*
5886 * We are swapping the places of the `view` and
5887 * `pview` in the function's parameters list
5888 * because we are reverting the same operation
5889 * done previously in the "correct" order.
5890 */
5891 result2 = configure_catz(pview, view, config,
5892 obj);
5893 if (result2 != ISC_R_SUCCESS) {
5894 isc_log_write(named_g_lctx,
5895 NAMED_LOGCATEGORY_GENERAL,
5896 NAMED_LOGMODULE_SERVER,
5897 ISC_LOG_ERROR,
5898 "catz configuration "
5899 "revert failed for view "
5900 "'%s'",
5901 pview->name);
5902 }
5903 }
5904
5905 dns_view_freeze(pview);
5906 }
5907
5908 if (pview != NULL) {
5909 dns_view_detach(&pview);
5910 }
5911
5912 if (zone_element_latest != NULL) {
5913 for (element = cfg_list_first(zonelist);
5914 element != NULL; element = cfg_list_next(element))
5915 {
5916 const cfg_obj_t *zconfig =
5917 cfg_listelt_value(element);
5918 configure_zone_setviewcommit(result, zconfig,
5919 view);
5920 if (element == zone_element_latest) {
5921 /*
5922 * This was the latest element that was
5923 * successfully configured earlier.
5924 */
5925 break;
5926 }
5927 }
5928 }
5929 }
5930
5931 if (ntatable != NULL) {
5932 dns_ntatable_detach(&ntatable);
5933 }
5934 if (clients != NULL) {
5935 dns_acl_detach(&clients);
5936 }
5937 if (mapped != NULL) {
5938 dns_acl_detach(&mapped);
5939 }
5940 if (excluded != NULL) {
5941 dns_acl_detach(&excluded);
5942 }
5943 if (ring != NULL) {
5944 dns_tsigkeyring_detach(&ring);
5945 }
5946 if (zone != NULL) {
5947 dns_zone_detach(&zone);
5948 }
5949 if (dispatch4 != NULL) {
5950 dns_dispatch_detach(&dispatch4);
5951 }
5952 if (dispatch6 != NULL) {
5953 dns_dispatch_detach(&dispatch6);
5954 }
5955 if (resstats != NULL) {
5956 isc_stats_detach(&resstats);
5957 }
5958 if (resquerystats != NULL) {
5959 dns_stats_detach(&resquerystats);
5960 }
5961 if (order != NULL) {
5962 dns_order_detach(&order);
5963 }
5964 if (cmctx != NULL) {
5965 isc_mem_detach(&cmctx);
5966 }
5967 if (hmctx != NULL) {
5968 isc_mem_detach(&hmctx);
5969 }
5970 if (cache != NULL) {
5971 dns_cache_detach(&cache);
5972 }
5973 if (dctx != NULL) {
5974 dns_dyndb_destroyctx(&dctx);
5975 }
5976
5977 return (result);
5978 }
5979
5980 static isc_result_t
configure_hints(dns_view_t * view,const char * filename)5981 configure_hints(dns_view_t *view, const char *filename) {
5982 isc_result_t result;
5983 dns_db_t *db;
5984
5985 db = NULL;
5986 result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
5987 if (result == ISC_R_SUCCESS) {
5988 dns_view_sethints(view, db);
5989 dns_db_detach(&db);
5990 }
5991
5992 return (result);
5993 }
5994
5995 static isc_result_t
configure_alternates(const cfg_obj_t * config,dns_view_t * view,const cfg_obj_t * alternates)5996 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
5997 const cfg_obj_t *alternates) {
5998 const cfg_obj_t *portobj;
5999 const cfg_obj_t *addresses;
6000 const cfg_listelt_t *element;
6001 isc_result_t result = ISC_R_SUCCESS;
6002 in_port_t port;
6003
6004 /*
6005 * Determine which port to send requests to.
6006 */
6007 CHECKM(named_config_getport(config, &port), "port");
6008
6009 if (alternates != NULL) {
6010 portobj = cfg_tuple_get(alternates, "port");
6011 if (cfg_obj_isuint32(portobj)) {
6012 uint32_t val = cfg_obj_asuint32(portobj);
6013 if (val > UINT16_MAX) {
6014 cfg_obj_log(portobj, named_g_lctx,
6015 ISC_LOG_ERROR,
6016 "port '%u' out of range", val);
6017 return (ISC_R_RANGE);
6018 }
6019 port = (in_port_t)val;
6020 }
6021 }
6022
6023 addresses = NULL;
6024 if (alternates != NULL) {
6025 addresses = cfg_tuple_get(alternates, "addresses");
6026 }
6027
6028 for (element = cfg_list_first(addresses); element != NULL;
6029 element = cfg_list_next(element))
6030 {
6031 const cfg_obj_t *alternate = cfg_listelt_value(element);
6032 isc_sockaddr_t sa;
6033
6034 if (!cfg_obj_issockaddr(alternate)) {
6035 dns_fixedname_t fixed;
6036 dns_name_t *name;
6037 const char *str = cfg_obj_asstring(
6038 cfg_tuple_get(alternate, "name"));
6039 isc_buffer_t buffer;
6040 in_port_t myport = port;
6041
6042 isc_buffer_constinit(&buffer, str, strlen(str));
6043 isc_buffer_add(&buffer, strlen(str));
6044 name = dns_fixedname_initname(&fixed);
6045 CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
6046 NULL));
6047
6048 portobj = cfg_tuple_get(alternate, "port");
6049 if (cfg_obj_isuint32(portobj)) {
6050 uint32_t val = cfg_obj_asuint32(portobj);
6051 if (val > UINT16_MAX) {
6052 cfg_obj_log(portobj, named_g_lctx,
6053 ISC_LOG_ERROR,
6054 "port '%u' out of range",
6055 val);
6056 return (ISC_R_RANGE);
6057 }
6058 myport = (in_port_t)val;
6059 }
6060 CHECK(dns_resolver_addalternate(view->resolver, NULL,
6061 name, myport));
6062 continue;
6063 }
6064
6065 sa = *cfg_obj_assockaddr(alternate);
6066 if (isc_sockaddr_getport(&sa) == 0) {
6067 isc_sockaddr_setport(&sa, port);
6068 }
6069 CHECK(dns_resolver_addalternate(view->resolver, &sa, NULL, 0));
6070 }
6071
6072 cleanup:
6073 return (result);
6074 }
6075
6076 static isc_result_t
configure_forward(const cfg_obj_t * config,dns_view_t * view,const dns_name_t * origin,const cfg_obj_t * forwarders,const cfg_obj_t * forwardtype)6077 configure_forward(const cfg_obj_t *config, dns_view_t *view,
6078 const dns_name_t *origin, const cfg_obj_t *forwarders,
6079 const cfg_obj_t *forwardtype) {
6080 const cfg_obj_t *portobj, *dscpobj;
6081 const cfg_obj_t *faddresses;
6082 const cfg_listelt_t *element;
6083 dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
6084 dns_forwarderlist_t fwdlist;
6085 dns_forwarder_t *fwd;
6086 isc_result_t result;
6087 in_port_t port;
6088 isc_dscp_t dscp = -1;
6089
6090 ISC_LIST_INIT(fwdlist);
6091
6092 /*
6093 * Determine which port to send forwarded requests to.
6094 */
6095 CHECKM(named_config_getport(config, &port), "port");
6096
6097 if (forwarders != NULL) {
6098 portobj = cfg_tuple_get(forwarders, "port");
6099 if (cfg_obj_isuint32(portobj)) {
6100 uint32_t val = cfg_obj_asuint32(portobj);
6101 if (val > UINT16_MAX) {
6102 cfg_obj_log(portobj, named_g_lctx,
6103 ISC_LOG_ERROR,
6104 "port '%u' out of range", val);
6105 return (ISC_R_RANGE);
6106 }
6107 port = (in_port_t)val;
6108 }
6109 }
6110
6111 /*
6112 * DSCP value for forwarded requests.
6113 */
6114 dscp = named_g_dscp;
6115 if (forwarders != NULL) {
6116 dscpobj = cfg_tuple_get(forwarders, "dscp");
6117 if (cfg_obj_isuint32(dscpobj)) {
6118 if (cfg_obj_asuint32(dscpobj) > 63) {
6119 cfg_obj_log(dscpobj, named_g_lctx,
6120 ISC_LOG_ERROR,
6121 "dscp value '%u' is out of range",
6122 cfg_obj_asuint32(dscpobj));
6123 return (ISC_R_RANGE);
6124 }
6125 dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
6126 }
6127 }
6128
6129 faddresses = NULL;
6130 if (forwarders != NULL) {
6131 faddresses = cfg_tuple_get(forwarders, "addresses");
6132 }
6133
6134 for (element = cfg_list_first(faddresses); element != NULL;
6135 element = cfg_list_next(element))
6136 {
6137 const cfg_obj_t *forwarder = cfg_listelt_value(element);
6138 fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
6139 fwd->addr = *cfg_obj_assockaddr(forwarder);
6140 if (isc_sockaddr_getport(&fwd->addr) == 0) {
6141 isc_sockaddr_setport(&fwd->addr, port);
6142 }
6143 fwd->dscp = cfg_obj_getdscp(forwarder);
6144 if (fwd->dscp == -1) {
6145 fwd->dscp = dscp;
6146 }
6147 ISC_LINK_INIT(fwd, link);
6148 ISC_LIST_APPEND(fwdlist, fwd, link);
6149 }
6150
6151 if (ISC_LIST_EMPTY(fwdlist)) {
6152 if (forwardtype != NULL) {
6153 cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING,
6154 "no forwarders seen; disabling "
6155 "forwarding");
6156 }
6157 fwdpolicy = dns_fwdpolicy_none;
6158 } else {
6159 if (forwardtype == NULL) {
6160 fwdpolicy = dns_fwdpolicy_first;
6161 } else {
6162 const char *forwardstr = cfg_obj_asstring(forwardtype);
6163 if (strcasecmp(forwardstr, "first") == 0) {
6164 fwdpolicy = dns_fwdpolicy_first;
6165 } else if (strcasecmp(forwardstr, "only") == 0) {
6166 fwdpolicy = dns_fwdpolicy_only;
6167 } else {
6168 UNREACHABLE();
6169 }
6170 }
6171 }
6172
6173 result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
6174 fwdpolicy);
6175 if (result != ISC_R_SUCCESS) {
6176 char namebuf[DNS_NAME_FORMATSIZE];
6177 dns_name_format(origin, namebuf, sizeof(namebuf));
6178 cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING,
6179 "could not set up forwarding for domain '%s': %s",
6180 namebuf, isc_result_totext(result));
6181 goto cleanup;
6182 }
6183
6184 result = ISC_R_SUCCESS;
6185
6186 cleanup:
6187
6188 while (!ISC_LIST_EMPTY(fwdlist)) {
6189 fwd = ISC_LIST_HEAD(fwdlist);
6190 ISC_LIST_UNLINK(fwdlist, fwd, link);
6191 isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
6192 }
6193
6194 return (result);
6195 }
6196
6197 static isc_result_t
get_viewinfo(const cfg_obj_t * vconfig,const char ** namep,dns_rdataclass_t * classp)6198 get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
6199 dns_rdataclass_t *classp) {
6200 isc_result_t result = ISC_R_SUCCESS;
6201 const char *viewname;
6202 dns_rdataclass_t viewclass;
6203
6204 REQUIRE(namep != NULL && *namep == NULL);
6205 REQUIRE(classp != NULL);
6206
6207 if (vconfig != NULL) {
6208 const cfg_obj_t *classobj = NULL;
6209
6210 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
6211 classobj = cfg_tuple_get(vconfig, "class");
6212 CHECK(named_config_getclass(classobj, dns_rdataclass_in,
6213 &viewclass));
6214 if (dns_rdataclass_ismeta(viewclass)) {
6215 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6216 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6217 "view '%s': class must not be meta",
6218 viewname);
6219 CHECK(ISC_R_FAILURE);
6220 }
6221 } else {
6222 viewname = "_default";
6223 viewclass = dns_rdataclass_in;
6224 }
6225
6226 *namep = viewname;
6227 *classp = viewclass;
6228
6229 cleanup:
6230 return (result);
6231 }
6232
6233 /*
6234 * Find a view based on its configuration info and attach to it.
6235 *
6236 * If 'vconfig' is NULL, attach to the default view.
6237 */
6238 static isc_result_t
find_view(const cfg_obj_t * vconfig,dns_viewlist_t * viewlist,dns_view_t ** viewp)6239 find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6240 dns_view_t **viewp) {
6241 isc_result_t result;
6242 const char *viewname = NULL;
6243 dns_rdataclass_t viewclass;
6244 dns_view_t *view = NULL;
6245
6246 result = get_viewinfo(vconfig, &viewname, &viewclass);
6247 if (result != ISC_R_SUCCESS) {
6248 return (result);
6249 }
6250
6251 result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6252 if (result != ISC_R_SUCCESS) {
6253 return (result);
6254 }
6255
6256 *viewp = view;
6257 return (ISC_R_SUCCESS);
6258 }
6259
6260 /*
6261 * Create a new view and add it to the list.
6262 *
6263 * If 'vconfig' is NULL, create the default view.
6264 *
6265 * The view created is attached to '*viewp'.
6266 */
6267 static isc_result_t
create_view(const cfg_obj_t * vconfig,dns_viewlist_t * viewlist,dns_view_t ** viewp)6268 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
6269 dns_view_t **viewp) {
6270 isc_result_t result;
6271 const char *viewname = NULL;
6272 dns_rdataclass_t viewclass;
6273 dns_view_t *view = NULL;
6274
6275 result = get_viewinfo(vconfig, &viewname, &viewclass);
6276 if (result != ISC_R_SUCCESS) {
6277 return (result);
6278 }
6279
6280 result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
6281 if (result == ISC_R_SUCCESS) {
6282 return (ISC_R_EXISTS);
6283 }
6284 if (result != ISC_R_NOTFOUND) {
6285 return (result);
6286 }
6287 INSIST(view == NULL);
6288
6289 result = dns_view_create(named_g_mctx, viewclass, viewname, &view);
6290 if (result != ISC_R_SUCCESS) {
6291 return (result);
6292 }
6293
6294 isc_nonce_buf(view->secret, sizeof(view->secret));
6295
6296 ISC_LIST_APPEND(*viewlist, view, link);
6297 dns_view_attach(view, viewp);
6298 return (ISC_R_SUCCESS);
6299 }
6300
6301 /*
6302 * Configure or reconfigure a zone.
6303 */
6304 static isc_result_t
configure_zone(const cfg_obj_t * config,const cfg_obj_t * zconfig,const cfg_obj_t * vconfig,isc_mem_t * mctx,dns_view_t * view,dns_viewlist_t * viewlist,dns_kasplist_t * kasplist,cfg_aclconfctx_t * aclconf,bool added,bool old_rpz_ok,bool modify)6305 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
6306 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
6307 dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
6308 cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
6309 bool modify) {
6310 dns_view_t *pview = NULL; /* Production view */
6311 dns_zone_t *zone = NULL; /* New or reused zone */
6312 dns_zone_t *raw = NULL; /* New or reused raw zone */
6313 dns_zone_t *dupzone = NULL;
6314 const cfg_obj_t *options = NULL;
6315 const cfg_obj_t *zoptions = NULL;
6316 const cfg_obj_t *typeobj = NULL;
6317 const cfg_obj_t *forwarders = NULL;
6318 const cfg_obj_t *forwardtype = NULL;
6319 const cfg_obj_t *ixfrfromdiffs = NULL;
6320 const cfg_obj_t *only = NULL;
6321 const cfg_obj_t *viewobj = NULL;
6322 isc_result_t result;
6323 isc_result_t tresult;
6324 isc_buffer_t buffer;
6325 dns_fixedname_t fixorigin;
6326 dns_name_t *origin;
6327 const char *zname;
6328 dns_rdataclass_t zclass;
6329 const char *ztypestr;
6330 dns_rpz_num_t rpz_num;
6331 bool zone_is_catz = false;
6332 bool zone_maybe_inline = false;
6333 bool inline_signing = false;
6334 bool fullsign = false;
6335
6336 options = NULL;
6337 (void)cfg_map_get(config, "options", &options);
6338
6339 zoptions = cfg_tuple_get(zconfig, "options");
6340
6341 /*
6342 * Get the zone origin as a dns_name_t.
6343 */
6344 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
6345 isc_buffer_constinit(&buffer, zname, strlen(zname));
6346 isc_buffer_add(&buffer, strlen(zname));
6347 dns_fixedname_init(&fixorigin);
6348 CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
6349 dns_rootname, 0, NULL));
6350 origin = dns_fixedname_name(&fixorigin);
6351
6352 CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"),
6353 view->rdclass, &zclass));
6354 if (zclass != view->rdclass) {
6355 const char *vname = NULL;
6356 if (vconfig != NULL) {
6357 vname = cfg_obj_asstring(
6358 cfg_tuple_get(vconfig, "name"));
6359 } else {
6360 vname = "<default view>";
6361 }
6362
6363 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6364 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6365 "zone '%s': wrong class for view '%s'", zname,
6366 vname);
6367 result = ISC_R_FAILURE;
6368 goto cleanup;
6369 }
6370
6371 (void)cfg_map_get(zoptions, "in-view", &viewobj);
6372 if (viewobj != NULL) {
6373 const char *inview = cfg_obj_asstring(viewobj);
6374 dns_view_t *otherview = NULL;
6375
6376 if (viewlist == NULL) {
6377 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6378 "'in-view' option is not permitted in "
6379 "dynamically added zones");
6380 result = ISC_R_FAILURE;
6381 goto cleanup;
6382 }
6383
6384 result = dns_viewlist_find(viewlist, inview, view->rdclass,
6385 &otherview);
6386 if (result != ISC_R_SUCCESS) {
6387 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6388 "view '%s' is not yet defined.", inview);
6389 result = ISC_R_FAILURE;
6390 goto cleanup;
6391 }
6392
6393 result = dns_view_findzone(otherview, origin, &zone);
6394 dns_view_detach(&otherview);
6395 if (result != ISC_R_SUCCESS) {
6396 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6397 "zone '%s' not defined in view '%s'", zname,
6398 inview);
6399 result = ISC_R_FAILURE;
6400 goto cleanup;
6401 }
6402
6403 CHECK(dns_view_addzone(view, zone));
6404 dns_zone_detach(&zone);
6405
6406 /*
6407 * If the zone contains a 'forwarders' statement, configure
6408 * selective forwarding. Note: this is not inherited from the
6409 * other view.
6410 */
6411 forwarders = NULL;
6412 result = cfg_map_get(zoptions, "forwarders", &forwarders);
6413 if (result == ISC_R_SUCCESS) {
6414 forwardtype = NULL;
6415 (void)cfg_map_get(zoptions, "forward", &forwardtype);
6416 CHECK(configure_forward(config, view, origin,
6417 forwarders, forwardtype));
6418 }
6419 result = ISC_R_SUCCESS;
6420 goto cleanup;
6421 }
6422
6423 (void)cfg_map_get(zoptions, "type", &typeobj);
6424 if (typeobj == NULL) {
6425 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6426 "zone '%s' 'type' not specified", zname);
6427 result = ISC_R_FAILURE;
6428 goto cleanup;
6429 }
6430 ztypestr = cfg_obj_asstring(typeobj);
6431
6432 /*
6433 * "hints zones" aren't zones. If we've got one,
6434 * configure it and return.
6435 */
6436 if (strcasecmp(ztypestr, "hint") == 0) {
6437 const cfg_obj_t *fileobj = NULL;
6438 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
6439 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6440 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6441 "zone '%s': 'file' not specified", zname);
6442 result = ISC_R_FAILURE;
6443 goto cleanup;
6444 }
6445 if (dns_name_equal(origin, dns_rootname)) {
6446 const char *hintsfile = cfg_obj_asstring(fileobj);
6447
6448 CHECK(configure_hints(view, hintsfile));
6449
6450 /*
6451 * Hint zones may also refer to delegation only points.
6452 */
6453 only = NULL;
6454 tresult = cfg_map_get(zoptions, "delegation-only",
6455 &only);
6456 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
6457 {
6458 CHECK(dns_view_adddelegationonly(view, origin));
6459 }
6460 } else {
6461 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6462 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
6463 "ignoring non-root hint zone '%s'",
6464 zname);
6465 result = ISC_R_SUCCESS;
6466 }
6467 /* Skip ordinary zone processing. */
6468 goto cleanup;
6469 }
6470
6471 /*
6472 * "forward zones" aren't zones either. Translate this syntax into
6473 * the appropriate selective forwarding configuration and return.
6474 */
6475 if (strcasecmp(ztypestr, "forward") == 0) {
6476 forwardtype = NULL;
6477 forwarders = NULL;
6478
6479 (void)cfg_map_get(zoptions, "forward", &forwardtype);
6480 (void)cfg_map_get(zoptions, "forwarders", &forwarders);
6481 CHECK(configure_forward(config, view, origin, forwarders,
6482 forwardtype));
6483
6484 /*
6485 * Forward zones may also set delegation only.
6486 */
6487 only = NULL;
6488 tresult = cfg_map_get(zoptions, "delegation-only", &only);
6489 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) {
6490 CHECK(dns_view_adddelegationonly(view, origin));
6491 }
6492 goto cleanup;
6493 }
6494
6495 /*
6496 * "delegation-only zones" aren't zones either.
6497 */
6498 if (strcasecmp(ztypestr, "delegation-only") == 0) {
6499 result = dns_view_adddelegationonly(view, origin);
6500 goto cleanup;
6501 }
6502
6503 /*
6504 * Redirect zones only require minimal configuration.
6505 */
6506 if (strcasecmp(ztypestr, "redirect") == 0) {
6507 if (view->redirect != NULL) {
6508 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6509 "redirect zone already exists");
6510 result = ISC_R_EXISTS;
6511 goto cleanup;
6512 }
6513 result = dns_viewlist_find(viewlist, view->name, view->rdclass,
6514 &pview);
6515 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6516 goto cleanup;
6517 }
6518 if (pview != NULL && pview->redirect != NULL) {
6519 dns_zone_attach(pview->redirect, &zone);
6520 dns_zone_setview(zone, view);
6521 } else {
6522 CHECK(dns_zonemgr_createzone(named_g_server->zonemgr,
6523 &zone));
6524 CHECK(dns_zone_setorigin(zone, origin));
6525 dns_zone_setview(zone, view);
6526 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr,
6527 zone));
6528 dns_zone_setstats(zone, named_g_server->zonestats);
6529 }
6530 CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
6531 kasplist, zone, NULL));
6532 dns_zone_attach(zone, &view->redirect);
6533 goto cleanup;
6534 }
6535
6536 if (!modify) {
6537 /*
6538 * Check for duplicates in the new zone table.
6539 */
6540 result = dns_view_findzone(view, origin, &dupzone);
6541 if (result == ISC_R_SUCCESS) {
6542 /*
6543 * We already have this zone!
6544 */
6545 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6546 "zone '%s' already exists", zname);
6547 dns_zone_detach(&dupzone);
6548 result = ISC_R_EXISTS;
6549 goto cleanup;
6550 }
6551 INSIST(dupzone == NULL);
6552 }
6553
6554 /*
6555 * Note whether this is a response policy zone and which one if so,
6556 * unless we are using RPZ service interface. In that case, the
6557 * BIND zone database has nothing to do with rpz and so we don't care.
6558 */
6559 for (rpz_num = 0;; ++rpz_num) {
6560 if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
6561 view->rpzs->p.dnsrps_enabled)
6562 {
6563 rpz_num = DNS_RPZ_INVALID_NUM;
6564 break;
6565 }
6566 if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
6567 {
6568 break;
6569 }
6570 }
6571
6572 if (view->catzs != NULL &&
6573 dns_catz_get_zone(view->catzs, origin) != NULL)
6574 {
6575 zone_is_catz = true;
6576 }
6577
6578 /*
6579 * See if we can reuse an existing zone. This is
6580 * only possible if all of these are true:
6581 * - The zone's view exists
6582 * - A zone with the right name exists in the view
6583 * - The zone is compatible with the config
6584 * options (e.g., an existing master zone cannot
6585 * be reused if the options specify a slave zone)
6586 * - The zone was not and is still not a response policy zone
6587 * or the zone is a policy zone with an unchanged number
6588 * and we are using the old policy zone summary data.
6589 */
6590 result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6591 view->rdclass, &pview);
6592 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6593 goto cleanup;
6594 }
6595 if (pview != NULL) {
6596 result = dns_view_findzone(pview, origin, &zone);
6597 }
6598 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6599 goto cleanup;
6600 }
6601
6602 if (zone != NULL && !named_zone_reusable(zone, zconfig)) {
6603 dns_zone_detach(&zone);
6604 fullsign = true;
6605 }
6606
6607 if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
6608 (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
6609 {
6610 dns_zone_detach(&zone);
6611 }
6612
6613 if (zone != NULL) {
6614 /*
6615 * We found a reusable zone. Make it use the
6616 * new view.
6617 */
6618 dns_zone_setview(zone, view);
6619 } else {
6620 /*
6621 * We cannot reuse an existing zone, we have
6622 * to create a new one.
6623 */
6624 CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6625 CHECK(dns_zone_setorigin(zone, origin));
6626 dns_zone_setview(zone, view);
6627 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6628 dns_zone_setstats(zone, named_g_server->zonestats);
6629 }
6630 if (rpz_num != DNS_RPZ_INVALID_NUM) {
6631 result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
6632 if (result != ISC_R_SUCCESS) {
6633 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6634 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6635 "zone '%s': incompatible"
6636 " masterfile-format or database"
6637 " for a response policy zone",
6638 zname);
6639 goto cleanup;
6640 }
6641 }
6642
6643 if (zone_is_catz) {
6644 dns_zone_catz_enable(zone, view->catzs);
6645 } else if (dns_zone_catz_is_enabled(zone)) {
6646 dns_zone_catz_disable(zone);
6647 }
6648
6649 /*
6650 * If the zone contains a 'forwarders' statement, configure
6651 * selective forwarding.
6652 */
6653 forwarders = NULL;
6654 if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) {
6655 forwardtype = NULL;
6656 (void)cfg_map_get(zoptions, "forward", &forwardtype);
6657 CHECK(configure_forward(config, view, origin, forwarders,
6658 forwardtype));
6659 }
6660
6661 /*
6662 * Stub and forward zones may also refer to delegation only points.
6663 */
6664 only = NULL;
6665 if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) {
6666 if (cfg_obj_asboolean(only)) {
6667 CHECK(dns_view_adddelegationonly(view, origin));
6668 }
6669 }
6670
6671 /*
6672 * Mark whether the zone was originally added at runtime or not
6673 */
6674 dns_zone_setadded(zone, added);
6675
6676 /*
6677 * Determine if we need to set up inline signing.
6678 */
6679 zone_maybe_inline = ((strcasecmp(ztypestr, "primary") == 0 ||
6680 strcasecmp(ztypestr, "master") == 0 ||
6681 strcasecmp(ztypestr, "secondary") == 0 ||
6682 strcasecmp(ztypestr, "slave") == 0));
6683
6684 if (zone_maybe_inline) {
6685 inline_signing = named_zone_inlinesigning(zconfig);
6686 }
6687 if (inline_signing) {
6688 dns_zone_getraw(zone, &raw);
6689 if (raw == NULL) {
6690 CHECK(dns_zone_create(&raw, mctx));
6691 CHECK(dns_zone_setorigin(raw, origin));
6692 dns_zone_setview(raw, view);
6693 dns_zone_setstats(raw, named_g_server->zonestats);
6694 CHECK(dns_zone_link(zone, raw));
6695 }
6696 if (cfg_map_get(zoptions, "ixfr-from-differences",
6697 &ixfrfromdiffs) == ISC_R_SUCCESS)
6698 {
6699 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6700 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6701 "zone '%s': 'ixfr-from-differences' is "
6702 "ignored for inline-signed zones",
6703 zname);
6704 }
6705 }
6706
6707 /*
6708 * Configure the zone.
6709 */
6710 CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
6711 zone, raw));
6712
6713 /*
6714 * Add the zone to its view in the new view list.
6715 */
6716 if (!modify) {
6717 CHECK(dns_view_addzone(view, zone));
6718 }
6719
6720 if (zone_is_catz) {
6721 /*
6722 * force catz reload if the zone is loaded;
6723 * if it's not it'll get reloaded on zone load
6724 */
6725 dns_db_t *db = NULL;
6726
6727 tresult = dns_zone_getdb(zone, &db);
6728 if (tresult == ISC_R_SUCCESS) {
6729 dns_catz_dbupdate_callback(db, view->catzs);
6730 dns_db_detach(&db);
6731 }
6732 }
6733
6734 /*
6735 * Ensure that zone keys are reloaded on reconfig
6736 */
6737 if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) {
6738 dns_zone_rekey(zone, fullsign);
6739 }
6740
6741 cleanup:
6742 if (zone != NULL) {
6743 dns_zone_detach(&zone);
6744 }
6745 if (raw != NULL) {
6746 dns_zone_detach(&raw);
6747 }
6748 if (pview != NULL) {
6749 dns_view_detach(&pview);
6750 }
6751
6752 return (result);
6753 }
6754
6755 /*
6756 * Configure built-in zone for storing managed-key data.
6757 */
6758 static isc_result_t
add_keydata_zone(dns_view_t * view,const char * directory,isc_mem_t * mctx)6759 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
6760 isc_result_t result;
6761 dns_view_t *pview = NULL;
6762 dns_zone_t *zone = NULL;
6763 dns_acl_t *none = NULL;
6764 char filename[PATH_MAX];
6765 bool defaultview;
6766
6767 REQUIRE(view != NULL);
6768
6769 /* See if we can re-use an existing keydata zone. */
6770 result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6771 view->rdclass, &pview);
6772 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6773 return (result);
6774 }
6775
6776 if (pview != NULL) {
6777 if (pview->managed_keys != NULL) {
6778 dns_zone_attach(pview->managed_keys,
6779 &view->managed_keys);
6780 dns_zone_setview(pview->managed_keys, view);
6781 dns_zone_setviewcommit(pview->managed_keys);
6782 dns_view_detach(&pview);
6783 dns_zone_synckeyzone(view->managed_keys);
6784 return (ISC_R_SUCCESS);
6785 }
6786
6787 dns_view_detach(&pview);
6788 }
6789
6790 /* No existing keydata zone was found; create one */
6791 CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6792 CHECK(dns_zone_setorigin(zone, dns_rootname));
6793
6794 defaultview = (strcmp(view->name, "_default") == 0);
6795 CHECK(isc_file_sanitize(
6796 directory, defaultview ? "managed-keys" : view->name,
6797 defaultview ? "bind" : "mkeys", filename, sizeof(filename)));
6798 CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text,
6799 &dns_master_style_default));
6800
6801 dns_zone_setview(zone, view);
6802 dns_zone_settype(zone, dns_zone_key);
6803 dns_zone_setclass(zone, view->rdclass);
6804
6805 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6806
6807 CHECK(dns_acl_none(mctx, &none));
6808 dns_zone_setqueryacl(zone, none);
6809 dns_zone_setqueryonacl(zone, none);
6810 dns_acl_detach(&none);
6811
6812 dns_zone_setdialup(zone, dns_dialuptype_no);
6813 dns_zone_setnotifytype(zone, dns_notifytype_no);
6814 dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
6815 dns_zone_setjournalsize(zone, 0);
6816
6817 dns_zone_setstats(zone, named_g_server->zonestats);
6818 CHECK(setquerystats(zone, mctx, dns_zonestat_none));
6819
6820 if (view->managed_keys != NULL) {
6821 dns_zone_detach(&view->managed_keys);
6822 }
6823 dns_zone_attach(zone, &view->managed_keys);
6824
6825 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6826 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6827 "set up managed keys zone for view %s, file '%s'",
6828 view->name, filename);
6829
6830 cleanup:
6831 if (zone != NULL) {
6832 dns_zone_detach(&zone);
6833 }
6834 if (none != NULL) {
6835 dns_acl_detach(&none);
6836 }
6837
6838 return (result);
6839 }
6840
6841 /*
6842 * Configure a single server quota.
6843 */
6844 static void
configure_server_quota(const cfg_obj_t ** maps,const char * name,isc_quota_t * quota)6845 configure_server_quota(const cfg_obj_t **maps, const char *name,
6846 isc_quota_t *quota) {
6847 const cfg_obj_t *obj = NULL;
6848 isc_result_t result;
6849
6850 result = named_config_get(maps, name, &obj);
6851 INSIST(result == ISC_R_SUCCESS);
6852 isc_quota_max(quota, cfg_obj_asuint32(obj));
6853 }
6854
6855 /*
6856 * This function is called as soon as the 'directory' statement has been
6857 * parsed. This can be extended to support other options if necessary.
6858 */
6859 static isc_result_t
directory_callback(const char * clausename,const cfg_obj_t * obj,void * arg)6860 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
6861 isc_result_t result;
6862 const char *directory;
6863
6864 REQUIRE(strcasecmp("directory", clausename) == 0);
6865
6866 UNUSED(arg);
6867 UNUSED(clausename);
6868
6869 /*
6870 * Change directory.
6871 */
6872 directory = cfg_obj_asstring(obj);
6873
6874 if (!isc_file_ischdiridempotent(directory)) {
6875 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
6876 "option 'directory' contains relative path '%s'",
6877 directory);
6878 }
6879
6880 #if 0
6881 if (!isc_file_isdirwritable(directory)) {
6882 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6883 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6884 "directory '%s' is not writable", directory);
6885 return (ISC_R_NOPERM);
6886 }
6887 #endif
6888
6889 result = isc_dir_chdir(directory);
6890 if (result != ISC_R_SUCCESS) {
6891 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
6892 "change directory to '%s' failed: %s", directory,
6893 isc_result_totext(result));
6894 return (result);
6895 }
6896
6897 return (ISC_R_SUCCESS);
6898 }
6899
6900 /*
6901 * This event callback is invoked to do periodic network interface
6902 * scanning.
6903 */
6904
6905 static void
interface_timer_tick(isc_task_t * task,isc_event_t * event)6906 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
6907 named_server_t *server = (named_server_t *)event->ev_arg;
6908 INSIST(task == server->task);
6909 UNUSED(task);
6910
6911 isc_event_free(&event);
6912 ns_interfacemgr_scan(server->interfacemgr, false);
6913 }
6914
6915 static void
heartbeat_timer_tick(isc_task_t * task,isc_event_t * event)6916 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
6917 named_server_t *server = (named_server_t *)event->ev_arg;
6918 dns_view_t *view;
6919
6920 UNUSED(task);
6921 isc_event_free(&event);
6922 view = ISC_LIST_HEAD(server->viewlist);
6923 while (view != NULL) {
6924 dns_view_dialup(view);
6925 view = ISC_LIST_NEXT(view, link);
6926 }
6927 }
6928
6929 typedef struct {
6930 isc_mem_t *mctx;
6931 isc_task_t *task;
6932 dns_fetch_t *fetch;
6933 dns_view_t *view;
6934 dns_fixedname_t tatname;
6935 dns_fixedname_t keyname;
6936 dns_rdataset_t rdataset;
6937 dns_rdataset_t sigrdataset;
6938 } ns_tat_t;
6939
6940 static int
cid(const void * a,const void * b)6941 cid(const void *a, const void *b) {
6942 const uint16_t ida = *(const uint16_t *)a;
6943 const uint16_t idb = *(const uint16_t *)b;
6944 if (ida < idb) {
6945 return (-1);
6946 } else if (ida > idb) {
6947 return (1);
6948 } else {
6949 return (0);
6950 }
6951 }
6952
6953 static void
tat_done(isc_task_t * task,isc_event_t * event)6954 tat_done(isc_task_t *task, isc_event_t *event) {
6955 dns_fetchevent_t *devent;
6956 ns_tat_t *tat;
6957
6958 INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE);
6959 INSIST(event->ev_arg != NULL);
6960
6961 UNUSED(task);
6962
6963 tat = event->ev_arg;
6964 devent = (dns_fetchevent_t *)event;
6965
6966 /* Free resources which are not of interest */
6967 if (devent->node != NULL) {
6968 dns_db_detachnode(devent->db, &devent->node);
6969 }
6970 if (devent->db != NULL) {
6971 dns_db_detach(&devent->db);
6972 }
6973 isc_event_free(&event);
6974 dns_resolver_destroyfetch(&tat->fetch);
6975 if (dns_rdataset_isassociated(&tat->rdataset)) {
6976 dns_rdataset_disassociate(&tat->rdataset);
6977 }
6978 if (dns_rdataset_isassociated(&tat->sigrdataset)) {
6979 dns_rdataset_disassociate(&tat->sigrdataset);
6980 }
6981 dns_view_detach(&tat->view);
6982 isc_task_detach(&tat->task);
6983 isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
6984 }
6985
6986 struct dotat_arg {
6987 dns_view_t *view;
6988 isc_task_t *task;
6989 };
6990
6991 /*%
6992 * Prepare the QNAME for the TAT query to be sent by processing the trust
6993 * anchors present at 'keynode' of 'keytable'. Store the result in 'dst' and
6994 * the domain name which 'keynode' is associated with in 'origin'.
6995 *
6996 * A maximum of 12 key IDs can be reported in a single TAT query due to the
6997 * 63-octet length limit for any single label in a domain name. If there are
6998 * more than 12 keys configured at 'keynode', only the first 12 will be
6999 * reported in the TAT query.
7000 */
7001 static isc_result_t
get_tat_qname(dns_name_t * target,dns_name_t * keyname,dns_keynode_t * keynode)7002 get_tat_qname(dns_name_t *target, dns_name_t *keyname, dns_keynode_t *keynode) {
7003 dns_rdataset_t dsset;
7004 unsigned int i, n = 0;
7005 uint16_t ids[12];
7006 isc_textregion_t r;
7007 char label[64];
7008 int m;
7009
7010 dns_rdataset_init(&dsset);
7011 if (dns_keynode_dsset(keynode, &dsset)) {
7012 isc_result_t result;
7013
7014 for (result = dns_rdataset_first(&dsset);
7015 result == ISC_R_SUCCESS;
7016 result = dns_rdataset_next(&dsset))
7017 {
7018 dns_rdata_t rdata = DNS_RDATA_INIT;
7019 dns_rdata_ds_t ds;
7020
7021 dns_rdata_reset(&rdata);
7022 dns_rdataset_current(&dsset, &rdata);
7023 result = dns_rdata_tostruct(&rdata, &ds, NULL);
7024 RUNTIME_CHECK(result == ISC_R_SUCCESS);
7025 if (n < (sizeof(ids) / sizeof(ids[0]))) {
7026 ids[n] = ds.key_tag;
7027 n++;
7028 }
7029 }
7030 dns_rdataset_disassociate(&dsset);
7031 }
7032
7033 if (n == 0) {
7034 return (DNS_R_EMPTYNAME);
7035 }
7036
7037 if (n > 1) {
7038 qsort(ids, n, sizeof(ids[0]), cid);
7039 }
7040
7041 /*
7042 * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
7043 * of the keyid.
7044 */
7045 label[0] = 0;
7046 r.base = label;
7047 r.length = sizeof(label);
7048 m = snprintf(r.base, r.length, "_ta");
7049 if (m < 0 || (unsigned)m > r.length) {
7050 return (ISC_R_FAILURE);
7051 }
7052 isc_textregion_consume(&r, m);
7053 for (i = 0; i < n; i++) {
7054 m = snprintf(r.base, r.length, "-%04x", ids[i]);
7055 if (m < 0 || (unsigned)m > r.length) {
7056 return (ISC_R_FAILURE);
7057 }
7058 isc_textregion_consume(&r, m);
7059 }
7060
7061 return (dns_name_fromstring2(target, label, keyname, 0, NULL));
7062 }
7063
7064 static void
tat_send(isc_task_t * task,isc_event_t * event)7065 tat_send(isc_task_t *task, isc_event_t *event) {
7066 ns_tat_t *tat;
7067 char namebuf[DNS_NAME_FORMATSIZE];
7068 dns_fixedname_t fdomain;
7069 dns_name_t *domain;
7070 dns_rdataset_t nameservers;
7071 isc_result_t result;
7072 dns_name_t *keyname;
7073 dns_name_t *tatname;
7074
7075 INSIST(event != NULL && event->ev_type == NAMED_EVENT_TATSEND);
7076 INSIST(event->ev_arg != NULL);
7077
7078 UNUSED(task);
7079
7080 tat = event->ev_arg;
7081
7082 keyname = dns_fixedname_name(&tat->keyname);
7083 tatname = dns_fixedname_name(&tat->tatname);
7084
7085 dns_name_format(tatname, namebuf, sizeof(namebuf));
7086 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7087 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7088 "%s: sending trust-anchor-telemetry query '%s/NULL'",
7089 tat->view->name, namebuf);
7090
7091 /*
7092 * TAT queries should be sent to the authoritative servers for a given
7093 * zone. If this function is called for a keytable node corresponding
7094 * to a locally served zone, calling dns_resolver_createfetch() with
7095 * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be
7096 * resolved locally, without sending any TAT queries upstream.
7097 *
7098 * Work around this issue by calling dns_view_findzonecut() first. If
7099 * the zone is served locally, the NS RRset for the given domain name
7100 * will be retrieved from local data; if it is not, the deepest zone
7101 * cut we have for it will be retrieved from cache. In either case,
7102 * passing the results to dns_resolver_createfetch() will prevent it
7103 * from returning NXDOMAIN for 'tatname' while still allowing it to
7104 * chase down any potential delegations returned by upstream servers in
7105 * order to eventually find the destination host to send the TAT query
7106 * to.
7107 *
7108 * After the dns_view_findzonecut() call, 'domain' will hold the
7109 * deepest zone cut we can find for 'keyname' while 'nameservers' will
7110 * hold the NS RRset at that zone cut.
7111 */
7112 domain = dns_fixedname_initname(&fdomain);
7113 dns_rdataset_init(&nameservers);
7114 result = dns_view_findzonecut(tat->view, keyname, domain, NULL, 0, 0,
7115 true, true, &nameservers, NULL);
7116 if (result == ISC_R_SUCCESS) {
7117 result = dns_resolver_createfetch(
7118 tat->view->resolver, tatname, dns_rdatatype_null,
7119 domain, &nameservers, NULL, NULL, 0, 0, 0, NULL,
7120 tat->task, tat_done, tat, &tat->rdataset,
7121 &tat->sigrdataset, &tat->fetch);
7122 }
7123
7124 /*
7125 * 'domain' holds the dns_name_t pointer inside a dst_key_t structure.
7126 * dns_resolver_createfetch() creates its own copy of 'domain' if it
7127 * succeeds. Thus, 'domain' is not freed here.
7128 *
7129 * Even if dns_view_findzonecut() returned something else than
7130 * ISC_R_SUCCESS, it still could have associated 'nameservers'.
7131 * dns_resolver_createfetch() creates its own copy of 'nameservers' if
7132 * it succeeds. Thus, we need to check whether 'nameservers' is
7133 * associated and release it if it is.
7134 */
7135 if (dns_rdataset_isassociated(&nameservers)) {
7136 dns_rdataset_disassociate(&nameservers);
7137 }
7138
7139 if (result != ISC_R_SUCCESS) {
7140 dns_view_detach(&tat->view);
7141 isc_task_detach(&tat->task);
7142 isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
7143 }
7144 isc_event_free(&event);
7145 }
7146
7147 static void
dotat(dns_keytable_t * keytable,dns_keynode_t * keynode,dns_name_t * keyname,void * arg)7148 dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, dns_name_t *keyname,
7149 void *arg) {
7150 struct dotat_arg *dotat_arg = arg;
7151 isc_result_t result;
7152 dns_view_t *view;
7153 isc_task_t *task;
7154 ns_tat_t *tat;
7155 isc_event_t *event;
7156
7157 REQUIRE(keytable != NULL);
7158 REQUIRE(keynode != NULL);
7159 REQUIRE(dotat_arg != NULL);
7160
7161 view = dotat_arg->view;
7162 task = dotat_arg->task;
7163
7164 tat = isc_mem_get(dotat_arg->view->mctx, sizeof(*tat));
7165
7166 tat->fetch = NULL;
7167 tat->mctx = NULL;
7168 tat->task = NULL;
7169 tat->view = NULL;
7170 dns_rdataset_init(&tat->rdataset);
7171 dns_rdataset_init(&tat->sigrdataset);
7172 dns_name_copynf(keyname, dns_fixedname_initname(&tat->keyname));
7173 result = get_tat_qname(dns_fixedname_initname(&tat->tatname), keyname,
7174 keynode);
7175 if (result != ISC_R_SUCCESS) {
7176 isc_mem_put(dotat_arg->view->mctx, tat, sizeof(*tat));
7177 return;
7178 }
7179 isc_mem_attach(dotat_arg->view->mctx, &tat->mctx);
7180 isc_task_attach(task, &tat->task);
7181 dns_view_attach(view, &tat->view);
7182
7183 /*
7184 * We don't want to be holding the keytable lock when calling
7185 * dns_view_findzonecut() as it creates a lock order loop so
7186 * call dns_view_findzonecut() in a event handler.
7187 *
7188 * zone->lock (dns_zone_setviewcommit) while holding view->lock
7189 * (dns_view_setviewcommit)
7190 *
7191 * keytable->lock (dns_keytable_find) while holding zone->lock
7192 * (zone_asyncload)
7193 *
7194 * view->lock (dns_view_findzonecut) while holding keytable->lock
7195 * (dns_keytable_forall)
7196 */
7197 event = isc_event_allocate(tat->mctx, keytable, NAMED_EVENT_TATSEND,
7198 tat_send, tat, sizeof(isc_event_t));
7199 isc_task_send(task, &event);
7200 }
7201
7202 static void
tat_timer_tick(isc_task_t * task,isc_event_t * event)7203 tat_timer_tick(isc_task_t *task, isc_event_t *event) {
7204 isc_result_t result;
7205 named_server_t *server = (named_server_t *)event->ev_arg;
7206 struct dotat_arg arg;
7207 dns_view_t *view;
7208 dns_keytable_t *secroots = NULL;
7209
7210 isc_event_free(&event);
7211
7212 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
7213 view = ISC_LIST_NEXT(view, link))
7214 {
7215 if (!view->trust_anchor_telemetry || !view->enablevalidation) {
7216 continue;
7217 }
7218
7219 result = dns_view_getsecroots(view, &secroots);
7220 if (result != ISC_R_SUCCESS) {
7221 continue;
7222 }
7223
7224 arg.view = view;
7225 arg.task = task;
7226 (void)dns_keytable_forall(secroots, dotat, &arg);
7227 dns_keytable_detach(&secroots);
7228 }
7229 }
7230
7231 static void
pps_timer_tick(isc_task_t * task,isc_event_t * event)7232 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
7233 static unsigned int oldrequests = 0;
7234 unsigned int requests = atomic_load_relaxed(&ns_client_requests);
7235
7236 UNUSED(task);
7237 isc_event_free(&event);
7238
7239 /*
7240 * Don't worry about wrapping as the overflow result will be right.
7241 */
7242 dns_pps = (requests - oldrequests) / 1200;
7243 oldrequests = requests;
7244 }
7245
7246 /*
7247 * Replace the current value of '*field', a dynamically allocated
7248 * string or NULL, with a dynamically allocated copy of the
7249 * null-terminated string pointed to by 'value', or NULL.
7250 */
7251 static isc_result_t
setstring(named_server_t * server,char ** field,const char * value)7252 setstring(named_server_t *server, char **field, const char *value) {
7253 char *copy;
7254
7255 if (value != NULL) {
7256 copy = isc_mem_strdup(server->mctx, value);
7257 } else {
7258 copy = NULL;
7259 }
7260
7261 if (*field != NULL) {
7262 isc_mem_free(server->mctx, *field);
7263 }
7264
7265 *field = copy;
7266 return (ISC_R_SUCCESS);
7267 }
7268
7269 /*
7270 * Replace the current value of '*field', a dynamically allocated
7271 * string or NULL, with another dynamically allocated string
7272 * or NULL if whether 'obj' is a string or void value, respectively.
7273 */
7274 static isc_result_t
setoptstring(named_server_t * server,char ** field,const cfg_obj_t * obj)7275 setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) {
7276 if (cfg_obj_isvoid(obj)) {
7277 return (setstring(server, field, NULL));
7278 } else {
7279 return (setstring(server, field, cfg_obj_asstring(obj)));
7280 }
7281 }
7282
7283 static void
set_limit(const cfg_obj_t ** maps,const char * configname,const char * description,isc_resource_t resourceid,isc_resourcevalue_t defaultvalue)7284 set_limit(const cfg_obj_t **maps, const char *configname,
7285 const char *description, isc_resource_t resourceid,
7286 isc_resourcevalue_t defaultvalue) {
7287 const cfg_obj_t *obj = NULL;
7288 const char *resource;
7289 isc_resourcevalue_t value;
7290 isc_result_t result;
7291
7292 if (named_config_get(maps, configname, &obj) != ISC_R_SUCCESS) {
7293 return;
7294 }
7295
7296 if (cfg_obj_isstring(obj)) {
7297 resource = cfg_obj_asstring(obj);
7298 if (strcasecmp(resource, "unlimited") == 0) {
7299 value = ISC_RESOURCE_UNLIMITED;
7300 } else {
7301 INSIST(strcasecmp(resource, "default") == 0);
7302 value = defaultvalue;
7303 }
7304 } else {
7305 value = cfg_obj_asuint64(obj);
7306 }
7307
7308 result = isc_resource_setlimit(resourceid, value);
7309 isc_log_write(
7310 named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7311 result == ISC_R_SUCCESS ? ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
7312 "set maximum %s to %" PRIu64 ": %s", description, value,
7313 isc_result_totext(result));
7314 }
7315
7316 #define SETLIMIT(cfgvar, resource, description) \
7317 set_limit(maps, cfgvar, description, isc_resource_##resource, \
7318 named_g_init##resource)
7319
7320 static void
set_limits(const cfg_obj_t ** maps)7321 set_limits(const cfg_obj_t **maps) {
7322 SETLIMIT("stacksize", stacksize, "stack size");
7323 SETLIMIT("datasize", datasize, "data size");
7324 SETLIMIT("coresize", coresize, "core size");
7325 SETLIMIT("files", openfiles, "open files");
7326 }
7327
7328 static void
portset_fromconf(isc_portset_t * portset,const cfg_obj_t * ports,bool positive)7329 portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
7330 bool positive) {
7331 const cfg_listelt_t *element;
7332
7333 for (element = cfg_list_first(ports); element != NULL;
7334 element = cfg_list_next(element))
7335 {
7336 const cfg_obj_t *obj = cfg_listelt_value(element);
7337
7338 if (cfg_obj_isuint32(obj)) {
7339 in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
7340
7341 if (positive) {
7342 isc_portset_add(portset, port);
7343 } else {
7344 isc_portset_remove(portset, port);
7345 }
7346 } else {
7347 const cfg_obj_t *obj_loport, *obj_hiport;
7348 in_port_t loport, hiport;
7349
7350 obj_loport = cfg_tuple_get(obj, "loport");
7351 loport = (in_port_t)cfg_obj_asuint32(obj_loport);
7352 obj_hiport = cfg_tuple_get(obj, "hiport");
7353 hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
7354
7355 if (positive) {
7356 isc_portset_addrange(portset, loport, hiport);
7357 } else {
7358 isc_portset_removerange(portset, loport,
7359 hiport);
7360 }
7361 }
7362 }
7363 }
7364
7365 static isc_result_t
removed(dns_zone_t * zone,void * uap)7366 removed(dns_zone_t *zone, void *uap) {
7367 if (dns_zone_getview(zone) != uap) {
7368 return (ISC_R_SUCCESS);
7369 }
7370
7371 dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed",
7372 dns_zonetype_name(dns_zone_gettype(zone)));
7373 return (ISC_R_SUCCESS);
7374 }
7375
7376 static void
cleanup_session_key(named_server_t * server,isc_mem_t * mctx)7377 cleanup_session_key(named_server_t *server, isc_mem_t *mctx) {
7378 if (server->session_keyfile != NULL) {
7379 isc_file_remove(server->session_keyfile);
7380 isc_mem_free(mctx, server->session_keyfile);
7381 server->session_keyfile = NULL;
7382 }
7383
7384 if (server->session_keyname != NULL) {
7385 if (dns_name_dynamic(server->session_keyname)) {
7386 dns_name_free(server->session_keyname, mctx);
7387 }
7388 isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
7389 server->session_keyname = NULL;
7390 }
7391
7392 if (server->sessionkey != NULL) {
7393 dns_tsigkey_detach(&server->sessionkey);
7394 }
7395
7396 server->session_keyalg = DST_ALG_UNKNOWN;
7397 server->session_keybits = 0;
7398 }
7399
7400 static isc_result_t
generate_session_key(const char * filename,const char * keynamestr,const dns_name_t * keyname,const char * algstr,const dns_name_t * algname,unsigned int algtype,uint16_t bits,isc_mem_t * mctx,bool first_time,dns_tsigkey_t ** tsigkeyp)7401 generate_session_key(const char *filename, const char *keynamestr,
7402 const dns_name_t *keyname, const char *algstr,
7403 const dns_name_t *algname, unsigned int algtype,
7404 uint16_t bits, isc_mem_t *mctx, bool first_time,
7405 dns_tsigkey_t **tsigkeyp) {
7406 isc_result_t result = ISC_R_SUCCESS;
7407 dst_key_t *key = NULL;
7408 isc_buffer_t key_txtbuffer;
7409 isc_buffer_t key_rawbuffer;
7410 char key_txtsecret[256];
7411 char key_rawsecret[64];
7412 isc_region_t key_rawregion;
7413 isc_stdtime_t now;
7414 dns_tsigkey_t *tsigkey = NULL;
7415 FILE *fp = NULL;
7416
7417 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7418 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7419 "generating session key for dynamic DNS");
7420
7421 /* generate key */
7422 result = dst_key_generate(keyname, algtype, bits, 1, 0,
7423 DNS_KEYPROTO_ANY, dns_rdataclass_in, mctx,
7424 &key, NULL);
7425 if (result != ISC_R_SUCCESS) {
7426 return (result);
7427 }
7428
7429 /*
7430 * Dump the key to the buffer for later use. Should be done before
7431 * we transfer the ownership of key to tsigkey.
7432 */
7433 isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
7434 CHECK(dst_key_tobuffer(key, &key_rawbuffer));
7435
7436 isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
7437 isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
7438 CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
7439
7440 /* Store the key in tsigkey. */
7441 isc_stdtime_get(&now);
7442 CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key, false,
7443 NULL, now, now, mctx, NULL, &tsigkey));
7444
7445 /* Dump the key to the key file. */
7446 fp = named_os_openfile(filename, S_IRUSR | S_IWUSR, first_time);
7447 if (fp == NULL) {
7448 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7449 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7450 "could not create %s", filename);
7451 result = ISC_R_NOPERM;
7452 goto cleanup;
7453 }
7454
7455 fprintf(fp,
7456 "key \"%s\" {\n"
7457 "\talgorithm %s;\n"
7458 "\tsecret \"%.*s\";\n};\n",
7459 keynamestr, algstr, (int)isc_buffer_usedlength(&key_txtbuffer),
7460 (char *)isc_buffer_base(&key_txtbuffer));
7461
7462 CHECK(isc_stdio_flush(fp));
7463 result = isc_stdio_close(fp);
7464 fp = NULL;
7465 if (result != ISC_R_SUCCESS) {
7466 goto cleanup;
7467 }
7468
7469 dst_key_free(&key);
7470
7471 *tsigkeyp = tsigkey;
7472
7473 return (ISC_R_SUCCESS);
7474
7475 cleanup:
7476 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7477 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7478 "failed to generate session key "
7479 "for dynamic DNS: %s",
7480 isc_result_totext(result));
7481 if (fp != NULL) {
7482 (void)isc_stdio_close(fp);
7483 (void)isc_file_remove(filename);
7484 }
7485 if (tsigkey != NULL) {
7486 dns_tsigkey_detach(&tsigkey);
7487 }
7488 if (key != NULL) {
7489 dst_key_free(&key);
7490 }
7491
7492 return (result);
7493 }
7494
7495 static isc_result_t
configure_session_key(const cfg_obj_t ** maps,named_server_t * server,isc_mem_t * mctx,bool first_time)7496 configure_session_key(const cfg_obj_t **maps, named_server_t *server,
7497 isc_mem_t *mctx, bool first_time) {
7498 const char *keyfile, *keynamestr, *algstr;
7499 unsigned int algtype;
7500 dns_fixedname_t fname;
7501 dns_name_t *keyname;
7502 const dns_name_t *algname;
7503 isc_buffer_t buffer;
7504 uint16_t bits;
7505 const cfg_obj_t *obj;
7506 bool need_deleteold = false;
7507 bool need_createnew = false;
7508 isc_result_t result;
7509
7510 obj = NULL;
7511 result = named_config_get(maps, "session-keyfile", &obj);
7512 if (result == ISC_R_SUCCESS) {
7513 if (cfg_obj_isvoid(obj)) {
7514 keyfile = NULL; /* disable it */
7515 } else {
7516 keyfile = cfg_obj_asstring(obj);
7517 }
7518 } else {
7519 keyfile = named_g_defaultsessionkeyfile;
7520 }
7521
7522 obj = NULL;
7523 result = named_config_get(maps, "session-keyname", &obj);
7524 INSIST(result == ISC_R_SUCCESS);
7525 keynamestr = cfg_obj_asstring(obj);
7526 isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
7527 isc_buffer_add(&buffer, strlen(keynamestr));
7528 keyname = dns_fixedname_initname(&fname);
7529 result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
7530 if (result != ISC_R_SUCCESS) {
7531 return (result);
7532 }
7533
7534 obj = NULL;
7535 result = named_config_get(maps, "session-keyalg", &obj);
7536 INSIST(result == ISC_R_SUCCESS);
7537 algstr = cfg_obj_asstring(obj);
7538 algname = NULL;
7539 result = named_config_getkeyalgorithm2(algstr, &algname, &algtype,
7540 &bits);
7541 if (result != ISC_R_SUCCESS) {
7542 const char *s = " (keeping current key)";
7543
7544 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7545 "session-keyalg: "
7546 "unsupported or unknown algorithm '%s'%s",
7547 algstr, server->session_keyfile != NULL ? s : "");
7548 return (result);
7549 }
7550
7551 /* See if we need to (re)generate a new key. */
7552 if (keyfile == NULL) {
7553 if (server->session_keyfile != NULL) {
7554 need_deleteold = true;
7555 }
7556 } else if (server->session_keyfile == NULL) {
7557 need_createnew = true;
7558 } else if (strcmp(keyfile, server->session_keyfile) != 0 ||
7559 !dns_name_equal(server->session_keyname, keyname) ||
7560 server->session_keyalg != algtype ||
7561 server->session_keybits != bits)
7562 {
7563 need_deleteold = true;
7564 need_createnew = true;
7565 }
7566
7567 if (need_deleteold) {
7568 INSIST(server->session_keyfile != NULL);
7569 INSIST(server->session_keyname != NULL);
7570 INSIST(server->sessionkey != NULL);
7571
7572 cleanup_session_key(server, mctx);
7573 }
7574
7575 if (need_createnew) {
7576 INSIST(server->sessionkey == NULL);
7577 INSIST(server->session_keyfile == NULL);
7578 INSIST(server->session_keyname == NULL);
7579 INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
7580 INSIST(server->session_keybits == 0);
7581
7582 server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
7583 dns_name_init(server->session_keyname, NULL);
7584 dns_name_dup(keyname, mctx, server->session_keyname);
7585
7586 server->session_keyfile = isc_mem_strdup(mctx, keyfile);
7587
7588 server->session_keyalg = algtype;
7589 server->session_keybits = bits;
7590
7591 CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
7592 algname, algtype, bits, mctx,
7593 first_time, &server->sessionkey));
7594 }
7595
7596 return (result);
7597
7598 cleanup:
7599 cleanup_session_key(server, mctx);
7600 return (result);
7601 }
7602
7603 #ifndef HAVE_LMDB
7604 static isc_result_t
count_newzones(dns_view_t * view,ns_cfgctx_t * nzcfg,int * num_zonesp)7605 count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7606 isc_result_t result;
7607
7608 /* The new zone file may not exist. That is OK. */
7609 if (!isc_file_exists(view->new_zone_file)) {
7610 *num_zonesp = 0;
7611 return (ISC_R_SUCCESS);
7612 }
7613
7614 /*
7615 * In the case of NZF files, we also parse the configuration in
7616 * the file at this stage.
7617 *
7618 * This may be called in multiple views, so we reset
7619 * the parser each time.
7620 */
7621 cfg_parser_reset(named_g_addparser);
7622 result = cfg_parse_file(named_g_addparser, view->new_zone_file,
7623 &cfg_type_addzoneconf, &nzcfg->nzf_config);
7624 if (result == ISC_R_SUCCESS) {
7625 int num_zones;
7626
7627 num_zones = count_zones(nzcfg->nzf_config);
7628 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7629 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7630 "NZF file '%s' contains %d zones",
7631 view->new_zone_file, num_zones);
7632 if (num_zonesp != NULL) {
7633 *num_zonesp = num_zones;
7634 }
7635 } else {
7636 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7637 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7638 "Error parsing NZF file '%s': %s",
7639 view->new_zone_file, isc_result_totext(result));
7640 }
7641
7642 return (result);
7643 }
7644
7645 #else /* HAVE_LMDB */
7646
7647 static isc_result_t
count_newzones(dns_view_t * view,ns_cfgctx_t * nzcfg,int * num_zonesp)7648 count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7649 isc_result_t result;
7650 int n;
7651
7652 UNUSED(nzcfg);
7653
7654 REQUIRE(num_zonesp != NULL);
7655
7656 LOCK(&view->new_zone_lock);
7657
7658 CHECK(migrate_nzf(view));
7659
7660 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7661 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7662 "loading NZD zone count from '%s' "
7663 "for view '%s'",
7664 view->new_zone_db, view->name);
7665
7666 CHECK(nzd_count(view, &n));
7667
7668 *num_zonesp = n;
7669
7670 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7671 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7672 "NZD database '%s' contains %d zones", view->new_zone_db,
7673 n);
7674
7675 cleanup:
7676 if (result != ISC_R_SUCCESS) {
7677 *num_zonesp = 0;
7678 }
7679
7680 UNLOCK(&view->new_zone_lock);
7681
7682 return (ISC_R_SUCCESS);
7683 }
7684
7685 #endif /* HAVE_LMDB */
7686
7687 static isc_result_t
setup_newzones(dns_view_t * view,cfg_obj_t * config,cfg_obj_t * vconfig,cfg_parser_t * conf_parser,cfg_aclconfctx_t * actx,int * num_zones)7688 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7689 cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx,
7690 int *num_zones) {
7691 isc_result_t result = ISC_R_SUCCESS;
7692 bool allow = false;
7693 ns_cfgctx_t *nzcfg = NULL;
7694 const cfg_obj_t *maps[4];
7695 const cfg_obj_t *options = NULL, *voptions = NULL;
7696 const cfg_obj_t *nz = NULL;
7697 const cfg_obj_t *nzdir = NULL;
7698 const char *dir = NULL;
7699 const cfg_obj_t *obj = NULL;
7700 int i = 0;
7701 uint64_t mapsize = 0ULL;
7702
7703 REQUIRE(config != NULL);
7704
7705 if (vconfig != NULL) {
7706 voptions = cfg_tuple_get(vconfig, "options");
7707 }
7708 if (voptions != NULL) {
7709 maps[i++] = voptions;
7710 }
7711 result = cfg_map_get(config, "options", &options);
7712 if (result == ISC_R_SUCCESS) {
7713 maps[i++] = options;
7714 }
7715 maps[i++] = named_g_defaults;
7716 maps[i] = NULL;
7717
7718 result = named_config_get(maps, "allow-new-zones", &nz);
7719 if (result == ISC_R_SUCCESS) {
7720 allow = cfg_obj_asboolean(nz);
7721 }
7722 result = named_config_get(maps, "new-zones-directory", &nzdir);
7723 if (result == ISC_R_SUCCESS) {
7724 dir = cfg_obj_asstring(nzdir);
7725 result = isc_file_isdirectory(dir);
7726 if (result != ISC_R_SUCCESS) {
7727 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
7728 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7729 "invalid new-zones-directory %s: %s", dir,
7730 isc_result_totext(result));
7731 return (result);
7732 }
7733 if (!isc_file_isdirwritable(dir)) {
7734 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7735 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7736 "new-zones-directory '%s' "
7737 "is not writable",
7738 dir);
7739 return (ISC_R_NOPERM);
7740 }
7741
7742 dns_view_setnewzonedir(view, dir);
7743 }
7744
7745 #ifdef HAVE_LMDB
7746 result = named_config_get(maps, "lmdb-mapsize", &obj);
7747 if (result == ISC_R_SUCCESS && obj != NULL) {
7748 mapsize = cfg_obj_asuint64(obj);
7749 if (mapsize < (1ULL << 20)) { /* 1 megabyte */
7750 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7751 "'lmdb-mapsize "
7752 "%" PRId64 "' "
7753 "is too small",
7754 mapsize);
7755 return (ISC_R_FAILURE);
7756 } else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
7757 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
7758 "'lmdb-mapsize "
7759 "%" PRId64 "' "
7760 "is too large",
7761 mapsize);
7762 return (ISC_R_FAILURE);
7763 }
7764 }
7765 #else /* ifdef HAVE_LMDB */
7766 UNUSED(obj);
7767 #endif /* HAVE_LMDB */
7768
7769 /*
7770 * A non-empty catalog-zones statement implies allow-new-zones
7771 */
7772 if (!allow) {
7773 const cfg_obj_t *cz = NULL;
7774 result = named_config_get(maps, "catalog-zones", &cz);
7775 if (result == ISC_R_SUCCESS) {
7776 const cfg_listelt_t *e =
7777 cfg_list_first(cfg_tuple_get(cz, "zone list"));
7778 if (e != NULL) {
7779 allow = true;
7780 }
7781 }
7782 }
7783
7784 if (!allow) {
7785 dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7786 if (num_zones != NULL) {
7787 *num_zones = 0;
7788 }
7789 return (ISC_R_SUCCESS);
7790 }
7791
7792 nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
7793
7794 /*
7795 * We attach the parser that was used for config as well
7796 * as the one that will be used for added zones, to avoid
7797 * a shutdown race later.
7798 */
7799 memset(nzcfg, 0, sizeof(*nzcfg));
7800 cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
7801 cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
7802 isc_mem_attach(view->mctx, &nzcfg->mctx);
7803 cfg_aclconfctx_attach(actx, &nzcfg->actx);
7804
7805 result = dns_view_setnewzones(view, true, nzcfg, newzone_cfgctx_destroy,
7806 mapsize);
7807 if (result != ISC_R_SUCCESS) {
7808 dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7809 return (result);
7810 }
7811
7812 cfg_obj_attach(config, &nzcfg->config);
7813 if (vconfig != NULL) {
7814 cfg_obj_attach(vconfig, &nzcfg->vconfig);
7815 }
7816
7817 result = count_newzones(view, nzcfg, num_zones);
7818 return (result);
7819 }
7820
7821 static void
configure_zone_setviewcommit(isc_result_t result,const cfg_obj_t * zconfig,dns_view_t * view)7822 configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
7823 dns_view_t *view) {
7824 const char *zname;
7825 dns_fixedname_t fixorigin;
7826 dns_name_t *origin;
7827 isc_result_t result2;
7828 dns_view_t *pview = NULL;
7829 dns_zone_t *zone = NULL;
7830
7831 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
7832 origin = dns_fixedname_initname(&fixorigin);
7833
7834 result2 = dns_name_fromstring(origin, zname, 0, NULL);
7835 if (result2 != ISC_R_SUCCESS) {
7836 return;
7837 }
7838
7839 result2 = dns_viewlist_find(&named_g_server->viewlist, view->name,
7840 view->rdclass, &pview);
7841 if (result2 != ISC_R_SUCCESS) {
7842 return;
7843 }
7844
7845 result2 = dns_view_findzone(pview, origin, &zone);
7846 if (result2 != ISC_R_SUCCESS) {
7847 dns_view_detach(&pview);
7848 return;
7849 }
7850
7851 if (result == ISC_R_SUCCESS) {
7852 dns_zone_setviewcommit(zone);
7853 } else {
7854 dns_zone_setviewrevert(zone);
7855 }
7856
7857 dns_zone_detach(&zone);
7858 dns_view_detach(&pview);
7859 }
7860
7861 #ifndef HAVE_LMDB
7862
7863 static isc_result_t
configure_newzones(dns_view_t * view,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,cfg_aclconfctx_t * actx)7864 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7865 isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
7866 isc_result_t result;
7867 ns_cfgctx_t *nzctx;
7868 const cfg_obj_t *zonelist;
7869 const cfg_listelt_t *element;
7870
7871 nzctx = view->new_zone_config;
7872 if (nzctx == NULL || nzctx->nzf_config == NULL) {
7873 return (ISC_R_SUCCESS);
7874 }
7875
7876 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7877 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7878 "loading additional zones for view '%s'", view->name);
7879
7880 zonelist = NULL;
7881 cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
7882
7883 for (element = cfg_list_first(zonelist); element != NULL;
7884 element = cfg_list_next(element))
7885 {
7886 const cfg_obj_t *zconfig = cfg_listelt_value(element);
7887 CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
7888 &named_g_server->viewlist,
7889 &named_g_server->kasplist, actx, true,
7890 false, false));
7891 }
7892
7893 result = ISC_R_SUCCESS;
7894
7895 cleanup:
7896 for (element = cfg_list_first(zonelist); element != NULL;
7897 element = cfg_list_next(element))
7898 {
7899 const cfg_obj_t *zconfig = cfg_listelt_value(element);
7900 configure_zone_setviewcommit(result, zconfig, view);
7901 }
7902
7903 return (result);
7904 }
7905
7906 #else /* HAVE_LMDB */
7907
7908 static isc_result_t
data_to_cfg(dns_view_t * view,MDB_val * key,MDB_val * data,isc_buffer_t ** text,cfg_obj_t ** zoneconfig)7909 data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data, isc_buffer_t **text,
7910 cfg_obj_t **zoneconfig) {
7911 isc_result_t result;
7912 const char *zone_name;
7913 size_t zone_name_len;
7914 const char *zone_config;
7915 size_t zone_config_len;
7916 cfg_obj_t *zoneconf = NULL;
7917 char bufname[DNS_NAME_FORMATSIZE];
7918
7919 REQUIRE(view != NULL);
7920 REQUIRE(key != NULL);
7921 REQUIRE(data != NULL);
7922 REQUIRE(text != NULL);
7923 REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
7924
7925 if (*text == NULL) {
7926 isc_buffer_allocate(view->mctx, text, 256);
7927 } else {
7928 isc_buffer_clear(*text);
7929 }
7930
7931 zone_name = (const char *)key->mv_data;
7932 zone_name_len = key->mv_size;
7933 INSIST(zone_name != NULL && zone_name_len > 0);
7934
7935 zone_config = (const char *)data->mv_data;
7936 zone_config_len = data->mv_size;
7937 INSIST(zone_config != NULL && zone_config_len > 0);
7938
7939 /* zone zonename { config; }; */
7940 result = isc_buffer_reserve(text, 6 + zone_name_len + 2 +
7941 zone_config_len + 2);
7942 if (result != ISC_R_SUCCESS) {
7943 goto cleanup;
7944 }
7945
7946 CHECK(putstr(text, "zone \""));
7947 CHECK(putmem(text, (const void *)zone_name, zone_name_len));
7948 CHECK(putstr(text, "\" "));
7949 CHECK(putmem(text, (const void *)zone_config, zone_config_len));
7950 CHECK(putstr(text, ";\n"));
7951
7952 snprintf(bufname, sizeof(bufname), "%.*s", (int)zone_name_len,
7953 zone_name);
7954
7955 cfg_parser_reset(named_g_addparser);
7956 result = cfg_parse_buffer(named_g_addparser, *text, bufname, 0,
7957 &cfg_type_addzoneconf, 0, &zoneconf);
7958 if (result != ISC_R_SUCCESS) {
7959 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7960 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7961 "parsing config for zone '%.*s' in "
7962 "NZD database '%s' failed",
7963 (int)zone_name_len, zone_name, view->new_zone_db);
7964 goto cleanup;
7965 }
7966
7967 *zoneconfig = zoneconf;
7968 zoneconf = NULL;
7969 result = ISC_R_SUCCESS;
7970
7971 cleanup:
7972 if (zoneconf != NULL) {
7973 cfg_obj_destroy(named_g_addparser, &zoneconf);
7974 }
7975
7976 return (result);
7977 }
7978
7979 /*%
7980 * Prototype for a callback which can be used with for_all_newzone_cfgs().
7981 */
7982 typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
7983 cfg_obj_t *config, cfg_obj_t *vconfig,
7984 isc_mem_t *mctx, dns_view_t *view,
7985 cfg_aclconfctx_t *actx);
7986
7987 /*%
7988 * For each zone found in a NZD opened by the caller, create an object
7989 * representing its configuration and invoke "callback" with the created
7990 * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all
7991 * these are non-global variables required to invoke configure_zone()).
7992 * Immediately interrupt processing if an error is encountered while
7993 * transforming NZD data into a zone configuration object or if "callback"
7994 * returns an error.
7995 *
7996 * Caller must hold 'view->new_zone_lock'.
7997 */
7998 static isc_result_t
for_all_newzone_cfgs(newzone_cfg_cb_t callback,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,dns_view_t * view,cfg_aclconfctx_t * actx,MDB_txn * txn,MDB_dbi dbi)7999 for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
8000 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8001 cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi) {
8002 const cfg_obj_t *zconfig, *zlist;
8003 isc_result_t result = ISC_R_SUCCESS;
8004 cfg_obj_t *zconfigobj = NULL;
8005 isc_buffer_t *text = NULL;
8006 MDB_cursor *cursor = NULL;
8007 MDB_val data, key;
8008 int status;
8009
8010 status = mdb_cursor_open(txn, dbi, &cursor);
8011 if (status != MDB_SUCCESS) {
8012 return (ISC_R_FAILURE);
8013 }
8014
8015 for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
8016 status == MDB_SUCCESS;
8017 status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
8018 {
8019 /*
8020 * Create a configuration object from data fetched from NZD.
8021 */
8022 result = data_to_cfg(view, &key, &data, &text, &zconfigobj);
8023 if (result != ISC_R_SUCCESS) {
8024 break;
8025 }
8026
8027 /*
8028 * Extract zone configuration from configuration object.
8029 */
8030 zlist = NULL;
8031 result = cfg_map_get(zconfigobj, "zone", &zlist);
8032 if (result != ISC_R_SUCCESS) {
8033 break;
8034 } else if (!cfg_obj_islist(zlist)) {
8035 result = ISC_R_FAILURE;
8036 break;
8037 }
8038 zconfig = cfg_listelt_value(cfg_list_first(zlist));
8039
8040 /*
8041 * Invoke callback.
8042 */
8043 result = callback(zconfig, config, vconfig, mctx, view, actx);
8044 if (result != ISC_R_SUCCESS) {
8045 break;
8046 }
8047
8048 /*
8049 * Destroy the configuration object created in this iteration.
8050 */
8051 cfg_obj_destroy(named_g_addparser, &zconfigobj);
8052 }
8053
8054 if (text != NULL) {
8055 isc_buffer_free(&text);
8056 }
8057 if (zconfigobj != NULL) {
8058 cfg_obj_destroy(named_g_addparser, &zconfigobj);
8059 }
8060 mdb_cursor_close(cursor);
8061
8062 return (result);
8063 }
8064
8065 /*%
8066 * Attempt to configure a zone found in NZD and return the result.
8067 */
8068 static isc_result_t
configure_newzone(const cfg_obj_t * zconfig,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,dns_view_t * view,cfg_aclconfctx_t * actx)8069 configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
8070 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8071 cfg_aclconfctx_t *actx) {
8072 return (configure_zone(
8073 config, zconfig, vconfig, mctx, view, &named_g_server->viewlist,
8074 &named_g_server->kasplist, actx, true, false, false));
8075 }
8076
8077 /*%
8078 * Revert new view assignment for a zone found in NZD.
8079 */
8080 static isc_result_t
configure_newzone_revert(const cfg_obj_t * zconfig,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,dns_view_t * view,cfg_aclconfctx_t * actx)8081 configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config,
8082 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
8083 cfg_aclconfctx_t *actx) {
8084 UNUSED(config);
8085 UNUSED(vconfig);
8086 UNUSED(mctx);
8087 UNUSED(actx);
8088
8089 configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view);
8090
8091 return (ISC_R_SUCCESS);
8092 }
8093
8094 static isc_result_t
configure_newzones(dns_view_t * view,cfg_obj_t * config,cfg_obj_t * vconfig,isc_mem_t * mctx,cfg_aclconfctx_t * actx)8095 configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
8096 isc_mem_t *mctx, cfg_aclconfctx_t *actx) {
8097 isc_result_t result;
8098 MDB_txn *txn = NULL;
8099 MDB_dbi dbi;
8100
8101 if (view->new_zone_config == NULL) {
8102 return (ISC_R_SUCCESS);
8103 }
8104
8105 LOCK(&view->new_zone_lock);
8106
8107 result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
8108 if (result != ISC_R_SUCCESS) {
8109 UNLOCK(&view->new_zone_lock);
8110 return (ISC_R_SUCCESS);
8111 }
8112
8113 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8114 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8115 "loading NZD configs from '%s' "
8116 "for view '%s'",
8117 view->new_zone_db, view->name);
8118
8119 result = for_all_newzone_cfgs(configure_newzone, config, vconfig, mctx,
8120 view, actx, txn, dbi);
8121 if (result != ISC_R_SUCCESS) {
8122 /*
8123 * An error was encountered while attempting to configure zones
8124 * found in NZD. As this error may have been caused by a
8125 * configure_zone() failure, try restoring a sane configuration
8126 * by reattaching all zones found in NZD to the old view. If
8127 * this also fails, too bad, there is nothing more we can do in
8128 * terms of trying to make things right.
8129 */
8130 (void)for_all_newzone_cfgs(configure_newzone_revert, config,
8131 vconfig, mctx, view, actx, txn, dbi);
8132 }
8133
8134 (void)nzd_close(&txn, false);
8135
8136 UNLOCK(&view->new_zone_lock);
8137
8138 return (result);
8139 }
8140
8141 static isc_result_t
get_newzone_config(dns_view_t * view,const char * zonename,cfg_obj_t ** zoneconfig)8142 get_newzone_config(dns_view_t *view, const char *zonename,
8143 cfg_obj_t **zoneconfig) {
8144 isc_result_t result;
8145 int status;
8146 cfg_obj_t *zoneconf = NULL;
8147 isc_buffer_t *text = NULL;
8148 MDB_txn *txn = NULL;
8149 MDB_dbi dbi;
8150 MDB_val key, data;
8151 char zname[DNS_NAME_FORMATSIZE];
8152 dns_fixedname_t fname;
8153 dns_name_t *name;
8154 isc_buffer_t b;
8155
8156 INSIST(zoneconfig != NULL && *zoneconfig == NULL);
8157
8158 LOCK(&view->new_zone_lock);
8159
8160 CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
8161
8162 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8163 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8164 "loading NZD config from '%s' "
8165 "for zone '%s'",
8166 view->new_zone_db, zonename);
8167
8168 /* Normalize zone name */
8169 isc_buffer_constinit(&b, zonename, strlen(zonename));
8170 isc_buffer_add(&b, strlen(zonename));
8171 name = dns_fixedname_initname(&fname);
8172 CHECK(dns_name_fromtext(name, &b, dns_rootname, DNS_NAME_DOWNCASE,
8173 NULL));
8174 dns_name_format(name, zname, sizeof(zname));
8175
8176 key.mv_data = zname;
8177 key.mv_size = strlen(zname);
8178
8179 status = mdb_get(txn, dbi, &key, &data);
8180 if (status != MDB_SUCCESS) {
8181 CHECK(ISC_R_FAILURE);
8182 }
8183
8184 CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
8185
8186 *zoneconfig = zoneconf;
8187 zoneconf = NULL;
8188 result = ISC_R_SUCCESS;
8189
8190 cleanup:
8191 (void)nzd_close(&txn, false);
8192
8193 UNLOCK(&view->new_zone_lock);
8194
8195 if (zoneconf != NULL) {
8196 cfg_obj_destroy(named_g_addparser, &zoneconf);
8197 }
8198 if (text != NULL) {
8199 isc_buffer_free(&text);
8200 }
8201
8202 return (result);
8203 }
8204
8205 #endif /* HAVE_LMDB */
8206
8207 static int
count_zones(const cfg_obj_t * conf)8208 count_zones(const cfg_obj_t *conf) {
8209 const cfg_obj_t *zonelist = NULL;
8210 const cfg_listelt_t *element;
8211 int n = 0;
8212
8213 REQUIRE(conf != NULL);
8214
8215 cfg_map_get(conf, "zone", &zonelist);
8216 for (element = cfg_list_first(zonelist); element != NULL;
8217 element = cfg_list_next(element))
8218 {
8219 n++;
8220 }
8221
8222 return (n);
8223 }
8224
8225 static isc_result_t
check_lockfile(named_server_t * server,const cfg_obj_t * config,bool first_time)8226 check_lockfile(named_server_t *server, const cfg_obj_t *config,
8227 bool first_time) {
8228 isc_result_t result;
8229 const char *filename = NULL;
8230 const cfg_obj_t *maps[3];
8231 const cfg_obj_t *options;
8232 const cfg_obj_t *obj;
8233 int i;
8234
8235 i = 0;
8236 options = NULL;
8237 result = cfg_map_get(config, "options", &options);
8238 if (result == ISC_R_SUCCESS) {
8239 maps[i++] = options;
8240 }
8241 maps[i++] = named_g_defaults;
8242 maps[i] = NULL;
8243
8244 obj = NULL;
8245 (void)named_config_get(maps, "lock-file", &obj);
8246
8247 if (!first_time) {
8248 if (obj != NULL && !cfg_obj_isstring(obj) &&
8249 server->lockfile != NULL &&
8250 strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
8251 {
8252 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8253 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8254 "changing 'lock-file' "
8255 "has no effect until the "
8256 "server is restarted");
8257 }
8258
8259 return (ISC_R_SUCCESS);
8260 }
8261
8262 if (obj != NULL) {
8263 if (cfg_obj_isvoid(obj)) {
8264 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8265 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
8266 "skipping lock-file check ");
8267 return (ISC_R_SUCCESS);
8268 } else if (named_g_forcelock) {
8269 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8270 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8271 "'lock-file' has no effect "
8272 "because the server was run with -X");
8273 server->lockfile = isc_mem_strdup(
8274 server->mctx, named_g_defaultlockfile);
8275 } else {
8276 filename = cfg_obj_asstring(obj);
8277 server->lockfile = isc_mem_strdup(server->mctx,
8278 filename);
8279 }
8280
8281 if (server->lockfile == NULL) {
8282 return (ISC_R_NOMEMORY);
8283 }
8284 }
8285
8286 if (named_g_forcelock && named_g_defaultlockfile != NULL) {
8287 INSIST(server->lockfile == NULL);
8288 server->lockfile = isc_mem_strdup(server->mctx,
8289 named_g_defaultlockfile);
8290 }
8291
8292 if (server->lockfile == NULL) {
8293 return (ISC_R_SUCCESS);
8294 }
8295
8296 if (named_os_issingleton(server->lockfile)) {
8297 return (ISC_R_SUCCESS);
8298 }
8299
8300 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8301 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8302 "could not lock %s; another named "
8303 "process may be running",
8304 server->lockfile);
8305 return (ISC_R_FAILURE);
8306 }
8307
8308 static isc_result_t
load_configuration(const char * filename,named_server_t * server,bool first_time)8309 load_configuration(const char *filename, named_server_t *server,
8310 bool first_time) {
8311 cfg_obj_t *config = NULL, *bindkeys = NULL;
8312 cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
8313 const cfg_listelt_t *element;
8314 const cfg_obj_t *builtin_views;
8315 const cfg_obj_t *maps[3];
8316 const cfg_obj_t *obj;
8317 const cfg_obj_t *options;
8318 const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
8319 const cfg_obj_t *kasps;
8320 dns_kasp_t *kasp = NULL;
8321 dns_kasp_t *kasp_next = NULL;
8322 dns_kasplist_t tmpkasplist, kasplist;
8323 const cfg_obj_t *views;
8324 dns_view_t *view = NULL;
8325 dns_view_t *view_next = NULL;
8326 dns_viewlist_t tmpviewlist;
8327 dns_viewlist_t viewlist, builtin_viewlist;
8328 in_port_t listen_port, udpport_low, udpport_high;
8329 int i, backlog;
8330 int num_zones = 0;
8331 bool exclusive = false;
8332 isc_interval_t interval;
8333 isc_logconfig_t *logc = NULL;
8334 isc_portset_t *v4portset = NULL;
8335 isc_portset_t *v6portset = NULL;
8336 isc_resourcevalue_t nfiles;
8337 isc_result_t result, tresult;
8338 uint32_t heartbeat_interval;
8339 uint32_t interface_interval;
8340 uint32_t reserved;
8341 uint32_t udpsize;
8342 uint32_t transfer_message_size;
8343 named_cache_t *nsc;
8344 named_cachelist_t cachelist, tmpcachelist;
8345 ns_altsecret_t *altsecret;
8346 ns_altsecretlist_t altsecrets, tmpaltsecrets;
8347 unsigned int maxsocks;
8348 uint32_t softquota = 0;
8349 uint32_t max;
8350 uint64_t initial, idle, keepalive, advertised;
8351 bool loadbalancesockets;
8352 dns_aclenv_t *env =
8353 ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
8354
8355 ISC_LIST_INIT(kasplist);
8356 ISC_LIST_INIT(viewlist);
8357 ISC_LIST_INIT(builtin_viewlist);
8358 ISC_LIST_INIT(cachelist);
8359 ISC_LIST_INIT(altsecrets);
8360
8361 /* Create the ACL configuration context */
8362 if (named_g_aclconfctx != NULL) {
8363 cfg_aclconfctx_detach(&named_g_aclconfctx);
8364 }
8365 CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx));
8366
8367 /*
8368 * Shut down all dyndb instances.
8369 */
8370 dns_dyndb_cleanup(false);
8371
8372 /*
8373 * Parse the global default pseudo-config file.
8374 */
8375 if (first_time) {
8376 result = named_config_parsedefaults(named_g_parser,
8377 &named_g_config);
8378 if (result != ISC_R_SUCCESS) {
8379 named_main_earlyfatal("unable to load "
8380 "internal defaults: %s",
8381 isc_result_totext(result));
8382 }
8383 RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
8384 &named_g_defaults) == ISC_R_SUCCESS);
8385 }
8386
8387 /*
8388 * Parse the configuration file using the new config code.
8389 */
8390 config = NULL;
8391 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8392 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8393 "loading configuration from '%s'", filename);
8394 CHECK(cfg_parser_create(named_g_mctx, named_g_lctx, &conf_parser));
8395 cfg_parser_setcallback(conf_parser, directory_callback, NULL);
8396 result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf,
8397 &config);
8398
8399 CHECK(result);
8400
8401 /*
8402 * Check the validity of the configuration.
8403 *
8404 * (Ignore plugin parameters for now; they will be
8405 * checked later when the modules are actually loaded and
8406 * registered.)
8407 */
8408 CHECK(bind9_check_namedconf(config, false, named_g_lctx, named_g_mctx));
8409
8410 /*
8411 * Fill in the maps array, used for resolving defaults.
8412 */
8413 i = 0;
8414 options = NULL;
8415 result = cfg_map_get(config, "options", &options);
8416 if (result == ISC_R_SUCCESS) {
8417 maps[i++] = options;
8418 }
8419 maps[i++] = named_g_defaults;
8420 maps[i] = NULL;
8421
8422 /*
8423 * If bind.keys exists, load it. If "dnssec-validation auto"
8424 * is turned on, the root key found there will be used as a
8425 * default trust anchor.
8426 */
8427 obj = NULL;
8428 result = named_config_get(maps, "bindkeys-file", &obj);
8429 INSIST(result == ISC_R_SUCCESS);
8430 CHECKM(setstring(server, &server->bindkeysfile, cfg_obj_asstring(obj)),
8431 "strdup");
8432 INSIST(server->bindkeysfile != NULL);
8433
8434 if (access(server->bindkeysfile, R_OK) == 0) {
8435 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8436 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8437 "reading built-in trust anchors "
8438 "from file '%s'",
8439 server->bindkeysfile);
8440
8441 CHECK(cfg_parser_create(named_g_mctx, named_g_lctx,
8442 &bindkeys_parser));
8443
8444 result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
8445 &cfg_type_bindkeys, &bindkeys);
8446 if (result != ISC_R_SUCCESS) {
8447 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8448 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8449 "unable to parse '%s' error '%s'; using "
8450 "built-in keys instead",
8451 server->bindkeysfile,
8452 isc_result_totext(result));
8453 }
8454 } else {
8455 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8456 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8457 "unable to open '%s'; using built-in keys "
8458 "instead",
8459 server->bindkeysfile);
8460 }
8461
8462 /* Ensure exclusive access to configuration data. */
8463 if (!exclusive) {
8464 result = isc_task_beginexclusive(server->task);
8465 RUNTIME_CHECK(result == ISC_R_SUCCESS);
8466 exclusive = true;
8467 }
8468
8469 /*
8470 * Set process limits, which (usually) needs to be done as root.
8471 */
8472 set_limits(maps);
8473
8474 /*
8475 * Check the process lockfile.
8476 */
8477 CHECK(check_lockfile(server, config, first_time));
8478
8479 /*
8480 * Check if max number of open sockets that the system allows is
8481 * sufficiently large. Failing this condition is not necessarily fatal,
8482 * but may cause subsequent runtime failures for a busy recursive
8483 * server.
8484 */
8485 result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &maxsocks);
8486 if (result != ISC_R_SUCCESS) {
8487 maxsocks = 0;
8488 }
8489 result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
8490 if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
8491 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8492 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8493 "max open files (%" PRIu64 ")"
8494 " is smaller than max sockets (%u)",
8495 nfiles, maxsocks);
8496 }
8497
8498 /*
8499 * Set the number of socket reserved for TCP, stdio etc.
8500 */
8501 obj = NULL;
8502 result = named_config_get(maps, "reserved-sockets", &obj);
8503 INSIST(result == ISC_R_SUCCESS);
8504 reserved = cfg_obj_asuint32(obj);
8505 if (maxsocks != 0) {
8506 if (maxsocks < 128U) { /* Prevent underflow. */
8507 reserved = 0;
8508 } else if (reserved > maxsocks - 128U) { /* Minimum UDP space.
8509 */
8510 reserved = maxsocks - 128;
8511 }
8512 }
8513 /* Minimum TCP/stdio space. */
8514 if (reserved < 128U) {
8515 reserved = 128;
8516 }
8517 if (reserved + 128U > maxsocks && maxsocks != 0) {
8518 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8519 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8520 "less than 128 UDP sockets available after "
8521 "applying 'reserved-sockets' and 'maxsockets'");
8522 }
8523 isc_socketmgr_setreserved(named_g_socketmgr, reserved);
8524
8525 #if defined(HAVE_GEOIP2)
8526 /*
8527 * Release any previously opened GeoIP2 databases.
8528 */
8529 named_geoip_unload();
8530
8531 /*
8532 * Initialize GeoIP databases from the configured location.
8533 * This should happen before configuring any ACLs, so that we
8534 * know what databases are available and can reject any GeoIP
8535 * ACLs that can't work.
8536 */
8537 obj = NULL;
8538 result = named_config_get(maps, "geoip-directory", &obj);
8539 INSIST(result == ISC_R_SUCCESS);
8540 if (cfg_obj_isstring(obj)) {
8541 char *dir;
8542 DE_CONST(cfg_obj_asstring(obj), dir);
8543 named_geoip_load(dir);
8544 }
8545 named_g_aclconfctx->geoip = named_g_geoip;
8546 #endif /* HAVE_GEOIP2 */
8547
8548 /*
8549 * Configure various server options.
8550 */
8551 configure_server_quota(maps, "transfers-out",
8552 &server->sctx->xfroutquota);
8553 configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
8554 configure_server_quota(maps, "recursive-clients",
8555 &server->sctx->recursionquota);
8556 configure_server_quota(maps, "update-quota", &server->sctx->updquota);
8557
8558 max = isc_quota_getmax(&server->sctx->recursionquota);
8559 if (max > 1000) {
8560 unsigned margin = ISC_MAX(100, named_g_cpus + 1);
8561 if (margin + 100 > max) {
8562 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8563 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8564 "'recursive-clients %d' too low when "
8565 "running with %d worker threads",
8566 max, named_g_cpus);
8567 CHECK(ISC_R_RANGE);
8568 }
8569 softquota = max - margin;
8570 } else {
8571 softquota = (max * 90) / 100;
8572 }
8573
8574 isc_quota_soft(&server->sctx->recursionquota, softquota);
8575
8576 /*
8577 * Set "blackhole". Only legal at options level; there is
8578 * no default.
8579 */
8580 CHECK(configure_view_acl(NULL, config, NULL, "blackhole", NULL,
8581 named_g_aclconfctx, named_g_mctx,
8582 &server->sctx->blackholeacl));
8583 if (server->sctx->blackholeacl != NULL) {
8584 dns_dispatchmgr_setblackhole(named_g_dispatchmgr,
8585 server->sctx->blackholeacl);
8586 }
8587
8588 /*
8589 * Set "keep-response-order". Only legal at options or
8590 * global defaults level.
8591 */
8592 CHECK(configure_view_acl(NULL, config, named_g_config,
8593 "keep-response-order", NULL,
8594 named_g_aclconfctx, named_g_mctx,
8595 &server->sctx->keepresporder));
8596
8597 obj = NULL;
8598 result = named_config_get(maps, "match-mapped-addresses", &obj);
8599 INSIST(result == ISC_R_SUCCESS);
8600 env->match_mapped = cfg_obj_asboolean(obj);
8601
8602 CHECKM(named_statschannels_configure(named_g_server, config,
8603 named_g_aclconfctx),
8604 "configuring statistics server(s)");
8605
8606 obj = NULL;
8607 result = named_config_get(maps, "tcp-initial-timeout", &obj);
8608 INSIST(result == ISC_R_SUCCESS);
8609 initial = cfg_obj_asuint32(obj) * 100;
8610 if (initial > MAX_INITIAL_TIMEOUT) {
8611 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8612 "tcp-initial-timeout value is out of range: "
8613 "lowering to %" PRIu32,
8614 MAX_INITIAL_TIMEOUT / 100);
8615 initial = MAX_INITIAL_TIMEOUT;
8616 } else if (initial < MIN_INITIAL_TIMEOUT) {
8617 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8618 "tcp-initial-timeout value is out of range: "
8619 "raising to %" PRIu32,
8620 MIN_INITIAL_TIMEOUT / 100);
8621 initial = MIN_INITIAL_TIMEOUT;
8622 }
8623
8624 obj = NULL;
8625 result = named_config_get(maps, "tcp-idle-timeout", &obj);
8626 INSIST(result == ISC_R_SUCCESS);
8627 idle = cfg_obj_asuint32(obj) * 100;
8628 if (idle > MAX_IDLE_TIMEOUT) {
8629 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8630 "tcp-idle-timeout value is out of range: "
8631 "lowering to %" PRIu32,
8632 MAX_IDLE_TIMEOUT / 100);
8633 idle = MAX_IDLE_TIMEOUT;
8634 } else if (idle < MIN_IDLE_TIMEOUT) {
8635 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8636 "tcp-idle-timeout value is out of range: "
8637 "raising to %" PRIu32,
8638 MIN_IDLE_TIMEOUT / 100);
8639 idle = MIN_IDLE_TIMEOUT;
8640 }
8641
8642 obj = NULL;
8643 result = named_config_get(maps, "tcp-keepalive-timeout", &obj);
8644 INSIST(result == ISC_R_SUCCESS);
8645 keepalive = cfg_obj_asuint32(obj) * 100;
8646 if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
8647 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8648 "tcp-keepalive-timeout value is out of range: "
8649 "lowering to %" PRIu32,
8650 MAX_KEEPALIVE_TIMEOUT / 100);
8651 keepalive = MAX_KEEPALIVE_TIMEOUT;
8652 } else if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
8653 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8654 "tcp-keepalive-timeout value is out of range: "
8655 "raising to %" PRIu32,
8656 MIN_KEEPALIVE_TIMEOUT / 100);
8657 keepalive = MIN_KEEPALIVE_TIMEOUT;
8658 }
8659
8660 obj = NULL;
8661 result = named_config_get(maps, "tcp-advertised-timeout", &obj);
8662 INSIST(result == ISC_R_SUCCESS);
8663 advertised = cfg_obj_asuint32(obj) * 100;
8664 if (advertised > MAX_ADVERTISED_TIMEOUT) {
8665 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8666 "tcp-advertized-timeout value is out of range: "
8667 "lowering to %" PRIu32,
8668 MAX_ADVERTISED_TIMEOUT / 100);
8669 advertised = MAX_ADVERTISED_TIMEOUT;
8670 }
8671
8672 isc_nm_settimeouts(named_g_nm, initial, idle, keepalive, advertised);
8673
8674 /*
8675 * Configure sets of UDP query source ports.
8676 */
8677 CHECKM(isc_portset_create(named_g_mctx, &v4portset), "creating UDP "
8678 "port set");
8679 CHECKM(isc_portset_create(named_g_mctx, &v6portset), "creating UDP "
8680 "port set");
8681
8682 usev4ports = NULL;
8683 usev6ports = NULL;
8684 avoidv4ports = NULL;
8685 avoidv6ports = NULL;
8686
8687 (void)named_config_get(maps, "use-v4-udp-ports", &usev4ports);
8688 if (usev4ports != NULL) {
8689 portset_fromconf(v4portset, usev4ports, true);
8690 } else {
8691 CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
8692 &udpport_high),
8693 "get the default UDP/IPv4 port range");
8694 if (udpport_low == udpport_high) {
8695 isc_portset_add(v4portset, udpport_low);
8696 } else {
8697 isc_portset_addrange(v4portset, udpport_low,
8698 udpport_high);
8699 }
8700 if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) {
8701 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8702 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8703 "using default UDP/IPv4 port range: "
8704 "[%d, %d]",
8705 udpport_low, udpport_high);
8706 }
8707 }
8708 (void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
8709 if (avoidv4ports != NULL) {
8710 portset_fromconf(v4portset, avoidv4ports, false);
8711 }
8712
8713 (void)named_config_get(maps, "use-v6-udp-ports", &usev6ports);
8714 if (usev6ports != NULL) {
8715 portset_fromconf(v6portset, usev6ports, true);
8716 } else {
8717 CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
8718 &udpport_high),
8719 "get the default UDP/IPv6 port range");
8720 if (udpport_low == udpport_high) {
8721 isc_portset_add(v6portset, udpport_low);
8722 } else {
8723 isc_portset_addrange(v6portset, udpport_low,
8724 udpport_high);
8725 }
8726 if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) {
8727 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8728 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8729 "using default UDP/IPv6 port range: "
8730 "[%d, %d]",
8731 udpport_low, udpport_high);
8732 }
8733 }
8734 (void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
8735 if (avoidv6ports != NULL) {
8736 portset_fromconf(v6portset, avoidv6ports, false);
8737 }
8738
8739 dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset,
8740 v6portset);
8741
8742 /*
8743 * Set the EDNS UDP size when we don't match a view.
8744 */
8745 obj = NULL;
8746 result = named_config_get(maps, "edns-udp-size", &obj);
8747 INSIST(result == ISC_R_SUCCESS);
8748 udpsize = cfg_obj_asuint32(obj);
8749 if (udpsize < 512) {
8750 udpsize = 512;
8751 }
8752 if (udpsize > 4096) {
8753 udpsize = 4096;
8754 }
8755 server->sctx->udpsize = (uint16_t)udpsize;
8756
8757 /* Set the transfer message size for TCP */
8758 obj = NULL;
8759 result = named_config_get(maps, "transfer-message-size", &obj);
8760 INSIST(result == ISC_R_SUCCESS);
8761 transfer_message_size = cfg_obj_asuint32(obj);
8762 if (transfer_message_size < 512) {
8763 transfer_message_size = 512;
8764 } else if (transfer_message_size > 65535) {
8765 transfer_message_size = 65535;
8766 }
8767 server->sctx->transfer_tcp_message_size =
8768 (uint16_t)transfer_message_size;
8769
8770 /*
8771 * Configure the zone manager.
8772 */
8773 obj = NULL;
8774 result = named_config_get(maps, "transfers-in", &obj);
8775 INSIST(result == ISC_R_SUCCESS);
8776 dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
8777
8778 obj = NULL;
8779 result = named_config_get(maps, "transfers-per-ns", &obj);
8780 INSIST(result == ISC_R_SUCCESS);
8781 dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
8782
8783 obj = NULL;
8784 result = named_config_get(maps, "notify-rate", &obj);
8785 INSIST(result == ISC_R_SUCCESS);
8786 dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
8787
8788 obj = NULL;
8789 result = named_config_get(maps, "startup-notify-rate", &obj);
8790 INSIST(result == ISC_R_SUCCESS);
8791 dns_zonemgr_setstartupnotifyrate(server->zonemgr,
8792 cfg_obj_asuint32(obj));
8793
8794 obj = NULL;
8795 result = named_config_get(maps, "serial-query-rate", &obj);
8796 INSIST(result == ISC_R_SUCCESS);
8797 dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
8798
8799 /*
8800 * Determine which port to use for listening for incoming connections.
8801 */
8802 if (named_g_port != 0) {
8803 listen_port = named_g_port;
8804 } else {
8805 CHECKM(named_config_getport(config, &listen_port), "port");
8806 }
8807
8808 /*
8809 * Determining the default DSCP code point.
8810 */
8811 CHECKM(named_config_getdscp(config, &named_g_dscp), "dscp");
8812
8813 /*
8814 * Find the listen queue depth.
8815 */
8816 obj = NULL;
8817 result = named_config_get(maps, "tcp-listen-queue", &obj);
8818 INSIST(result == ISC_R_SUCCESS);
8819 backlog = cfg_obj_asuint32(obj);
8820 if ((backlog > 0) && (backlog < 10)) {
8821 backlog = 10;
8822 }
8823 ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
8824
8825 obj = NULL;
8826 result = named_config_get(maps, "reuseport", &obj);
8827 INSIST(result == ISC_R_SUCCESS);
8828 loadbalancesockets = cfg_obj_asboolean(obj);
8829 #if HAVE_SO_REUSEPORT_LB
8830 if (first_time) {
8831 isc_nm_setloadbalancesockets(named_g_nm,
8832 cfg_obj_asboolean(obj));
8833 } else if (loadbalancesockets !=
8834 isc_nm_getloadbalancesockets(named_g_nm))
8835 {
8836 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8837 "changing reuseport value requires server restart");
8838 }
8839 #else
8840 if (loadbalancesockets) {
8841 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8842 "reuseport has no effect on this system");
8843 }
8844 #endif
8845
8846 /*
8847 * Configure the interface manager according to the "listen-on"
8848 * statement.
8849 */
8850 {
8851 const cfg_obj_t *clistenon = NULL;
8852 ns_listenlist_t *listenon = NULL;
8853
8854 clistenon = NULL;
8855 /*
8856 * Even though listen-on is present in the default
8857 * configuration, this way is easier.
8858 */
8859 if (options != NULL) {
8860 (void)cfg_map_get(options, "listen-on", &clistenon);
8861 }
8862 if (clistenon != NULL) {
8863 /* check return code? */
8864 (void)ns_listenlist_fromconfig(
8865 clistenon, config, named_g_aclconfctx,
8866 named_g_mctx, AF_INET, &listenon);
8867 } else {
8868 /*
8869 * Not specified, use default.
8870 */
8871 CHECK(ns_listenlist_default(named_g_mctx, listen_port,
8872 -1, true, &listenon));
8873 }
8874 if (listenon != NULL) {
8875 ns_interfacemgr_setlistenon4(server->interfacemgr,
8876 listenon);
8877 ns_listenlist_detach(&listenon);
8878 }
8879 }
8880 /*
8881 * Ditto for IPv6.
8882 */
8883 {
8884 const cfg_obj_t *clistenon = NULL;
8885 ns_listenlist_t *listenon = NULL;
8886
8887 if (options != NULL) {
8888 (void)cfg_map_get(options, "listen-on-v6", &clistenon);
8889 }
8890 if (clistenon != NULL) {
8891 /* check return code? */
8892 (void)ns_listenlist_fromconfig(
8893 clistenon, config, named_g_aclconfctx,
8894 named_g_mctx, AF_INET6, &listenon);
8895 } else {
8896 /*
8897 * Not specified, use default.
8898 */
8899 CHECK(ns_listenlist_default(named_g_mctx, listen_port,
8900 -1, true, &listenon));
8901 }
8902 if (listenon != NULL) {
8903 ns_interfacemgr_setlistenon6(server->interfacemgr,
8904 listenon);
8905 ns_listenlist_detach(&listenon);
8906 }
8907 }
8908
8909 /*
8910 * Rescan the interface list to pick up changes in the
8911 * listen-on option. It's important that we do this before we try
8912 * to configure the query source, since the dispatcher we use might
8913 * be shared with an interface.
8914 */
8915 result = ns_interfacemgr_scan(server->interfacemgr, true);
8916
8917 /*
8918 * Check that named is able to TCP listen on at least one
8919 * interface. Otherwise, another named process could be running
8920 * and we should fail.
8921 */
8922 if (first_time && (result == ISC_R_ADDRINUSE)) {
8923 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8924 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8925 "unable to listen on any configured interfaces");
8926 result = ISC_R_FAILURE;
8927 goto cleanup;
8928 }
8929
8930 /*
8931 * Arrange for further interface scanning to occur periodically
8932 * as specified by the "interface-interval" option.
8933 */
8934 obj = NULL;
8935 result = named_config_get(maps, "interface-interval", &obj);
8936 INSIST(result == ISC_R_SUCCESS);
8937 interface_interval = cfg_obj_asduration(obj);
8938 if (interface_interval == 0) {
8939 CHECK(isc_timer_reset(server->interface_timer,
8940 isc_timertype_inactive, NULL, NULL,
8941 true));
8942 } else if (server->interface_interval != interface_interval) {
8943 isc_interval_set(&interval, interface_interval, 0);
8944 CHECK(isc_timer_reset(server->interface_timer,
8945 isc_timertype_ticker, NULL, &interval,
8946 false));
8947 }
8948 server->interface_interval = interface_interval;
8949
8950 /*
8951 * Enable automatic interface scans.
8952 */
8953 obj = NULL;
8954 result = named_config_get(maps, "automatic-interface-scan", &obj);
8955 INSIST(result == ISC_R_SUCCESS);
8956 server->sctx->interface_auto = cfg_obj_asboolean(obj);
8957
8958 /*
8959 * Configure the dialup heartbeat timer.
8960 */
8961 obj = NULL;
8962 result = named_config_get(maps, "heartbeat-interval", &obj);
8963 INSIST(result == ISC_R_SUCCESS);
8964 heartbeat_interval = cfg_obj_asuint32(obj) * 60;
8965 if (heartbeat_interval == 0) {
8966 CHECK(isc_timer_reset(server->heartbeat_timer,
8967 isc_timertype_inactive, NULL, NULL,
8968 true));
8969 } else if (server->heartbeat_interval != heartbeat_interval) {
8970 isc_interval_set(&interval, heartbeat_interval, 0);
8971 CHECK(isc_timer_reset(server->heartbeat_timer,
8972 isc_timertype_ticker, NULL, &interval,
8973 false));
8974 }
8975 server->heartbeat_interval = heartbeat_interval;
8976
8977 isc_interval_set(&interval, 1200, 0);
8978 CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
8979 &interval, false));
8980
8981 isc_interval_set(&interval, named_g_tat_interval, 0);
8982 CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker, NULL,
8983 &interval, false));
8984
8985 /*
8986 * Write the PID file.
8987 */
8988 obj = NULL;
8989 if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) {
8990 if (cfg_obj_isvoid(obj)) {
8991 named_os_writepidfile(NULL, first_time);
8992 } else {
8993 named_os_writepidfile(cfg_obj_asstring(obj),
8994 first_time);
8995 }
8996 } else {
8997 named_os_writepidfile(named_g_defaultpidfile, first_time);
8998 }
8999
9000 /*
9001 * Configure the server-wide session key. This must be done before
9002 * configure views because zone configuration may need to know
9003 * session-keyname.
9004 *
9005 * Failure of session key generation isn't fatal at this time; if it
9006 * turns out that a session key is really needed but doesn't exist,
9007 * we'll treat it as a fatal error then.
9008 */
9009 (void)configure_session_key(maps, server, named_g_mctx, first_time);
9010
9011 /*
9012 * Create the DNSSEC key and signing policies (KASP).
9013 */
9014 kasps = NULL;
9015 (void)cfg_map_get(config, "dnssec-policy", &kasps);
9016 for (element = cfg_list_first(kasps); element != NULL;
9017 element = cfg_list_next(element))
9018 {
9019 cfg_obj_t *kconfig = cfg_listelt_value(element);
9020 kasp = NULL;
9021 CHECK(cfg_kasp_fromconfig(kconfig, NULL, named_g_mctx,
9022 named_g_lctx, &kasplist, &kasp));
9023 INSIST(kasp != NULL);
9024 dns_kasp_freeze(kasp);
9025 dns_kasp_detach(&kasp);
9026 }
9027 /*
9028 * Create the built-in kasp policies ("default", "insecure").
9029 */
9030 kasp = NULL;
9031 CHECK(cfg_kasp_fromconfig(NULL, "default", named_g_mctx, named_g_lctx,
9032 &kasplist, &kasp));
9033 INSIST(kasp != NULL);
9034 dns_kasp_freeze(kasp);
9035 dns_kasp_detach(&kasp);
9036
9037 kasp = NULL;
9038 CHECK(cfg_kasp_fromconfig(NULL, "insecure", named_g_mctx, named_g_lctx,
9039 &kasplist, &kasp));
9040 INSIST(kasp != NULL);
9041 dns_kasp_freeze(kasp);
9042 dns_kasp_detach(&kasp);
9043
9044 tmpkasplist = server->kasplist;
9045 server->kasplist = kasplist;
9046 kasplist = tmpkasplist;
9047
9048 /*
9049 * Configure the views.
9050 */
9051 views = NULL;
9052 (void)cfg_map_get(config, "view", &views);
9053
9054 /*
9055 * Create the views and count all the configured zones in
9056 * order to correctly size the zone manager's task table.
9057 * (We only count zones for configured views; the built-in
9058 * "bind" view can be ignored as it only adds a negligible
9059 * number of zones.)
9060 *
9061 * If we're allowing new zones, we need to be able to find the
9062 * new zone file and count those as well. So we setup the new
9063 * zone configuration context, but otherwise view configuration
9064 * waits until after the zone manager's task list has been sized.
9065 */
9066 for (element = cfg_list_first(views); element != NULL;
9067 element = cfg_list_next(element))
9068 {
9069 cfg_obj_t *vconfig = cfg_listelt_value(element);
9070 const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
9071 int nzf_num_zones;
9072
9073 view = NULL;
9074
9075 CHECK(create_view(vconfig, &viewlist, &view));
9076 INSIST(view != NULL);
9077
9078 num_zones += count_zones(voptions);
9079
9080 CHECK(setup_newzones(view, config, vconfig, conf_parser,
9081 named_g_aclconfctx, &nzf_num_zones));
9082 num_zones += nzf_num_zones;
9083
9084 dns_view_detach(&view);
9085 }
9086
9087 /*
9088 * If there were no explicit views then we do the default
9089 * view here.
9090 */
9091 if (views == NULL) {
9092 int nzf_num_zones;
9093
9094 CHECK(create_view(NULL, &viewlist, &view));
9095 INSIST(view != NULL);
9096
9097 num_zones = count_zones(config);
9098
9099 CHECK(setup_newzones(view, config, NULL, conf_parser,
9100 named_g_aclconfctx, &nzf_num_zones));
9101 num_zones += nzf_num_zones;
9102
9103 dns_view_detach(&view);
9104 }
9105
9106 /*
9107 * Zones have been counted; set the zone manager task pool size.
9108 */
9109 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9110 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9111 "sizing zone task pool based on %d zones", num_zones);
9112 CHECK(dns_zonemgr_setsize(named_g_server->zonemgr, num_zones));
9113
9114 /*
9115 * Configure and freeze all explicit views. Explicit
9116 * views that have zones were already created at parsing
9117 * time, but views with no zones must be created here.
9118 */
9119 for (element = cfg_list_first(views); element != NULL;
9120 element = cfg_list_next(element))
9121 {
9122 cfg_obj_t *vconfig = cfg_listelt_value(element);
9123
9124 view = NULL;
9125 CHECK(find_view(vconfig, &viewlist, &view));
9126 CHECK(configure_view(view, &viewlist, config, vconfig,
9127 &cachelist, &server->kasplist, bindkeys,
9128 named_g_mctx, named_g_aclconfctx, true));
9129 dns_view_freeze(view);
9130 dns_view_detach(&view);
9131 }
9132
9133 /*
9134 * Make sure we have a default view if and only if there
9135 * were no explicit views.
9136 */
9137 if (views == NULL) {
9138 view = NULL;
9139 CHECK(find_view(NULL, &viewlist, &view));
9140 CHECK(configure_view(view, &viewlist, config, NULL, &cachelist,
9141 &server->kasplist, bindkeys, named_g_mctx,
9142 named_g_aclconfctx, true));
9143 dns_view_freeze(view);
9144 dns_view_detach(&view);
9145 }
9146
9147 /*
9148 * Create (or recreate) the built-in views.
9149 */
9150 builtin_views = NULL;
9151 RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) ==
9152 ISC_R_SUCCESS);
9153 for (element = cfg_list_first(builtin_views); element != NULL;
9154 element = cfg_list_next(element))
9155 {
9156 cfg_obj_t *vconfig = cfg_listelt_value(element);
9157
9158 CHECK(create_view(vconfig, &builtin_viewlist, &view));
9159 CHECK(configure_view(view, &viewlist, config, vconfig,
9160 &cachelist, &server->kasplist, bindkeys,
9161 named_g_mctx, named_g_aclconfctx, false));
9162 dns_view_freeze(view);
9163 dns_view_detach(&view);
9164 view = NULL;
9165 }
9166
9167 /* Now combine the two viewlists into one */
9168 ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9169
9170 /*
9171 * Commit any dns_zone_setview() calls on all zones in the new
9172 * view.
9173 */
9174 for (view = ISC_LIST_HEAD(viewlist); view != NULL;
9175 view = ISC_LIST_NEXT(view, link))
9176 {
9177 dns_view_setviewcommit(view);
9178 }
9179
9180 /* Swap our new view list with the production one. */
9181 tmpviewlist = server->viewlist;
9182 server->viewlist = viewlist;
9183 viewlist = tmpviewlist;
9184
9185 /* Make the view list available to each of the views */
9186 view = ISC_LIST_HEAD(server->viewlist);
9187 while (view != NULL) {
9188 view->viewlist = &server->viewlist;
9189 view = ISC_LIST_NEXT(view, link);
9190 }
9191
9192 /* Swap our new cache list with the production one. */
9193 tmpcachelist = server->cachelist;
9194 server->cachelist = cachelist;
9195 cachelist = tmpcachelist;
9196
9197 /* Load the TKEY information from the configuration. */
9198 if (options != NULL) {
9199 dns_tkeyctx_t *t = NULL;
9200 CHECKM(named_tkeyctx_fromconfig(options, named_g_mctx, &t),
9201 "configuring TKEY");
9202 if (server->sctx->tkeyctx != NULL) {
9203 dns_tkeyctx_destroy(&server->sctx->tkeyctx);
9204 }
9205 server->sctx->tkeyctx = t;
9206 }
9207
9208 /*
9209 * Bind the control port(s).
9210 */
9211 CHECKM(named_controls_configure(named_g_server->controls, config,
9212 named_g_aclconfctx),
9213 "binding control channel(s)");
9214
9215 #ifdef HAVE_LMDB
9216 /*
9217 * If we're using LMDB, we may have created newzones databases
9218 * as root, making it impossible to reopen them later after
9219 * switching to a new userid. We close them now, and reopen
9220 * after relinquishing privileges them.
9221 */
9222 if (first_time) {
9223 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9224 view = ISC_LIST_NEXT(view, link))
9225 {
9226 nzd_env_close(view);
9227 }
9228 }
9229 #endif /* HAVE_LMDB */
9230
9231 /*
9232 * Relinquish root privileges.
9233 */
9234 if (first_time) {
9235 named_os_changeuser();
9236 }
9237
9238 #if 0
9239 /*
9240 * Check that the working directory is writable.
9241 */
9242 if (!isc_file_isdirwritable(".")) {
9243 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9244 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9245 "the working directory is not writable");
9246 result = ISC_R_NOPERM;
9247 goto cleanup;
9248 }
9249 #endif
9250
9251 #ifdef HAVE_LMDB
9252 /*
9253 * Reopen NZD databases.
9254 */
9255 if (first_time) {
9256 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9257 view = ISC_LIST_NEXT(view, link))
9258 {
9259 nzd_env_reopen(view);
9260 }
9261 }
9262 #endif /* HAVE_LMDB */
9263
9264 /*
9265 * Configure the logging system.
9266 *
9267 * Do this after changing UID to make sure that any log
9268 * files specified in named.conf get created by the
9269 * unprivileged user, not root.
9270 */
9271 if (named_g_logstderr) {
9272 const cfg_obj_t *logobj = NULL;
9273
9274 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9275 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9276 "not using config file logging "
9277 "statement for logging due to "
9278 "-g option");
9279
9280 (void)cfg_map_get(config, "logging", &logobj);
9281 if (logobj != NULL) {
9282 result = named_logconfig(NULL, logobj);
9283 if (result != ISC_R_SUCCESS) {
9284 isc_log_write(
9285 named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9286 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9287 "checking logging configuration "
9288 "failed: %s",
9289 isc_result_totext(result));
9290 goto cleanup;
9291 }
9292 }
9293 } else {
9294 const cfg_obj_t *logobj = NULL;
9295
9296 isc_logconfig_create(named_g_lctx, &logc);
9297
9298 logobj = NULL;
9299 (void)cfg_map_get(config, "logging", &logobj);
9300 if (logobj != NULL) {
9301 CHECKM(named_logconfig(logc, logobj),
9302 "configuring logging");
9303 } else {
9304 named_log_setdefaultchannels(logc);
9305 CHECKM(named_log_setunmatchedcategory(logc),
9306 "setting up default 'category unmatched'");
9307 CHECKM(named_log_setdefaultcategory(logc),
9308 "setting up default 'category default'");
9309 }
9310
9311 isc_logconfig_use(named_g_lctx, logc);
9312 logc = NULL;
9313
9314 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9315 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9316 "now using logging configuration from "
9317 "config file");
9318 }
9319
9320 /*
9321 * Set the default value of the query logging flag depending
9322 * whether a "queries" category has been defined. This is
9323 * a disgusting hack, but we need to do this for BIND 8
9324 * compatibility.
9325 */
9326 if (first_time) {
9327 const cfg_obj_t *logobj = NULL;
9328 const cfg_obj_t *categories = NULL;
9329
9330 obj = NULL;
9331 if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
9332 ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES,
9333 cfg_obj_asboolean(obj));
9334 } else {
9335 (void)cfg_map_get(config, "logging", &logobj);
9336 if (logobj != NULL) {
9337 (void)cfg_map_get(logobj, "category",
9338 &categories);
9339 }
9340 if (categories != NULL) {
9341 for (element = cfg_list_first(categories);
9342 element != NULL;
9343 element = cfg_list_next(element))
9344 {
9345 const cfg_obj_t *catobj;
9346 const char *str;
9347
9348 obj = cfg_listelt_value(element);
9349 catobj = cfg_tuple_get(obj, "name");
9350 str = cfg_obj_asstring(catobj);
9351 if (strcasecmp(str, "queries") == 0) {
9352 ns_server_setoption(
9353 server->sctx,
9354 NS_SERVER_LOGQUERIES,
9355 true);
9356 }
9357 }
9358 }
9359 }
9360 }
9361
9362 obj = NULL;
9363 if (options != NULL &&
9364 cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
9365 {
9366 named_g_memstatistics = cfg_obj_asboolean(obj);
9367 } else {
9368 named_g_memstatistics =
9369 ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
9370 }
9371
9372 obj = NULL;
9373 if (named_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
9374 {
9375 named_main_setmemstats(cfg_obj_asstring(obj));
9376 } else if (named_g_memstatistics) {
9377 named_main_setmemstats("named.memstats");
9378 } else {
9379 named_main_setmemstats(NULL);
9380 }
9381
9382 obj = NULL;
9383 result = named_config_get(maps, "statistics-file", &obj);
9384 INSIST(result == ISC_R_SUCCESS);
9385 CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
9386 "strdup");
9387
9388 obj = NULL;
9389 result = named_config_get(maps, "dump-file", &obj);
9390 INSIST(result == ISC_R_SUCCESS);
9391 CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
9392 "strdup");
9393
9394 obj = NULL;
9395 result = named_config_get(maps, "secroots-file", &obj);
9396 INSIST(result == ISC_R_SUCCESS);
9397 CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
9398 "strdup");
9399
9400 obj = NULL;
9401 result = named_config_get(maps, "recursing-file", &obj);
9402 INSIST(result == ISC_R_SUCCESS);
9403 CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
9404 "strdup");
9405
9406 obj = NULL;
9407 result = named_config_get(maps, "version", &obj);
9408 if (result == ISC_R_SUCCESS) {
9409 CHECKM(setoptstring(server, &server->version, obj), "strdup");
9410 server->version_set = true;
9411 } else {
9412 server->version_set = false;
9413 }
9414
9415 obj = NULL;
9416 result = named_config_get(maps, "hostname", &obj);
9417 if (result == ISC_R_SUCCESS) {
9418 CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
9419 server->hostname_set = true;
9420 } else {
9421 server->hostname_set = false;
9422 }
9423
9424 obj = NULL;
9425 result = named_config_get(maps, "server-id", &obj);
9426 server->sctx->gethostname = NULL;
9427 if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
9428 /* The parser translates "hostname" to true */
9429 server->sctx->gethostname = named_os_gethostname;
9430 result = ns_server_setserverid(server->sctx, NULL);
9431 } else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
9432 /* Found a quoted string */
9433 result = ns_server_setserverid(server->sctx,
9434 cfg_obj_asstring(obj));
9435 } else {
9436 result = ns_server_setserverid(server->sctx, NULL);
9437 }
9438 RUNTIME_CHECK(result == ISC_R_SUCCESS);
9439
9440 obj = NULL;
9441 result = named_config_get(maps, "flush-zones-on-shutdown", &obj);
9442 if (result == ISC_R_SUCCESS) {
9443 server->flushonshutdown = cfg_obj_asboolean(obj);
9444 } else {
9445 server->flushonshutdown = false;
9446 }
9447
9448 obj = NULL;
9449 result = named_config_get(maps, "answer-cookie", &obj);
9450 INSIST(result == ISC_R_SUCCESS);
9451 server->sctx->answercookie = cfg_obj_asboolean(obj);
9452
9453 obj = NULL;
9454 result = named_config_get(maps, "cookie-algorithm", &obj);
9455 INSIST(result == ISC_R_SUCCESS);
9456 if (strcasecmp(cfg_obj_asstring(obj), "siphash24") == 0) {
9457 server->sctx->cookiealg = ns_cookiealg_siphash24;
9458 } else if (strcasecmp(cfg_obj_asstring(obj), "aes") == 0) {
9459 server->sctx->cookiealg = ns_cookiealg_aes;
9460 } else {
9461 UNREACHABLE();
9462 }
9463
9464 obj = NULL;
9465 result = named_config_get(maps, "cookie-secret", &obj);
9466 if (result == ISC_R_SUCCESS) {
9467 const char *str;
9468 bool first = true;
9469 isc_buffer_t b;
9470 unsigned int usedlength;
9471 unsigned int expectedlength;
9472
9473 for (element = cfg_list_first(obj); element != NULL;
9474 element = cfg_list_next(element))
9475 {
9476 obj = cfg_listelt_value(element);
9477 str = cfg_obj_asstring(obj);
9478
9479 if (first) {
9480 memset(server->sctx->secret, 0,
9481 sizeof(server->sctx->secret));
9482 isc_buffer_init(&b, server->sctx->secret,
9483 sizeof(server->sctx->secret));
9484 result = isc_hex_decodestring(str, &b);
9485 if (result != ISC_R_SUCCESS &&
9486 result != ISC_R_NOSPACE)
9487 {
9488 goto cleanup;
9489 }
9490 first = false;
9491 } else {
9492 altsecret = isc_mem_get(server->sctx->mctx,
9493 sizeof(*altsecret));
9494 isc_buffer_init(&b, altsecret->secret,
9495 sizeof(altsecret->secret));
9496 result = isc_hex_decodestring(str, &b);
9497 if (result != ISC_R_SUCCESS &&
9498 result != ISC_R_NOSPACE)
9499 {
9500 isc_mem_put(server->sctx->mctx,
9501 altsecret,
9502 sizeof(*altsecret));
9503 goto cleanup;
9504 }
9505 ISC_LIST_INITANDAPPEND(altsecrets, altsecret,
9506 link);
9507 }
9508
9509 usedlength = isc_buffer_usedlength(&b);
9510 switch (server->sctx->cookiealg) {
9511 case ns_cookiealg_siphash24:
9512 expectedlength = ISC_SIPHASH24_KEY_LENGTH;
9513 if (usedlength != expectedlength) {
9514 CHECKM(ISC_R_RANGE, "SipHash-2-4 "
9515 "cookie-secret "
9516 "must be 128 bits");
9517 }
9518 break;
9519 case ns_cookiealg_aes:
9520 expectedlength = ISC_AES128_KEYLENGTH;
9521 if (usedlength != expectedlength) {
9522 CHECKM(ISC_R_RANGE, "AES cookie-secret "
9523 "must be 128 bits");
9524 }
9525 break;
9526 }
9527 }
9528 } else {
9529 isc_nonce_buf(server->sctx->secret,
9530 sizeof(server->sctx->secret));
9531 }
9532
9533 /*
9534 * Swap altsecrets lists.
9535 */
9536 tmpaltsecrets = server->sctx->altsecrets;
9537 server->sctx->altsecrets = altsecrets;
9538 altsecrets = tmpaltsecrets;
9539
9540 (void)named_server_loadnta(server);
9541
9542 #ifdef USE_DNSRPS
9543 /*
9544 * Start and connect to the DNS Response Policy Service
9545 * daemon, dnsrpzd, for each view that uses DNSRPS.
9546 */
9547 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9548 view = ISC_LIST_NEXT(view, link))
9549 {
9550 result = dns_dnsrps_connect(view->rpzs);
9551 if (result != ISC_R_SUCCESS) {
9552 view = NULL;
9553 goto cleanup;
9554 }
9555 }
9556 #endif /* ifdef USE_DNSRPS */
9557
9558 result = ISC_R_SUCCESS;
9559
9560 cleanup:
9561 if (logc != NULL) {
9562 isc_logconfig_destroy(&logc);
9563 }
9564
9565 if (v4portset != NULL) {
9566 isc_portset_destroy(named_g_mctx, &v4portset);
9567 }
9568
9569 if (v6portset != NULL) {
9570 isc_portset_destroy(named_g_mctx, &v6portset);
9571 }
9572
9573 if (conf_parser != NULL) {
9574 if (config != NULL) {
9575 cfg_obj_destroy(conf_parser, &config);
9576 }
9577 cfg_parser_destroy(&conf_parser);
9578 }
9579
9580 if (bindkeys_parser != NULL) {
9581 if (bindkeys != NULL) {
9582 cfg_obj_destroy(bindkeys_parser, &bindkeys);
9583 }
9584 cfg_parser_destroy(&bindkeys_parser);
9585 }
9586
9587 if (view != NULL) {
9588 dns_view_detach(&view);
9589 }
9590
9591 if (kasp != NULL) {
9592 dns_kasp_detach(&kasp);
9593 }
9594
9595 ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9596
9597 /*
9598 * This cleans up either the old production view list
9599 * or our temporary list depending on whether they
9600 * were swapped above or not.
9601 */
9602 for (view = ISC_LIST_HEAD(viewlist); view != NULL; view = view_next) {
9603 view_next = ISC_LIST_NEXT(view, link);
9604 ISC_LIST_UNLINK(viewlist, view, link);
9605 if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
9606 {
9607 dns_view_setviewrevert(view);
9608 (void)dns_zt_apply(view->zonetable, isc_rwlocktype_read,
9609 false, NULL, removed, view);
9610 }
9611 dns_view_detach(&view);
9612 }
9613
9614 /*
9615 * Same cleanup for kasp list.
9616 */
9617 for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
9618 kasp_next = ISC_LIST_NEXT(kasp, link);
9619 ISC_LIST_UNLINK(kasplist, kasp, link);
9620 dns_kasp_detach(&kasp);
9621 }
9622
9623 /* Same cleanup for cache list. */
9624 while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
9625 ISC_LIST_UNLINK(cachelist, nsc, link);
9626 dns_cache_detach(&nsc->cache);
9627 isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9628 }
9629
9630 /* Cleanup for altsecrets list. */
9631 while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) {
9632 ISC_LIST_UNLINK(altsecrets, altsecret, link);
9633 isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret));
9634 }
9635
9636 /*
9637 * Record the time of most recent configuration
9638 */
9639 tresult = isc_time_now(&named_g_configtime);
9640 if (tresult != ISC_R_SUCCESS) {
9641 named_main_earlyfatal("isc_time_now() failed: %s",
9642 isc_result_totext(result));
9643 }
9644
9645 /* Relinquish exclusive access to configuration data. */
9646 if (exclusive) {
9647 isc_task_endexclusive(server->task);
9648 }
9649
9650 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9651 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9652 "load_configuration: %s", isc_result_totext(result));
9653
9654 return (result);
9655 }
9656
9657 static isc_result_t
view_loaded(void * arg)9658 view_loaded(void *arg) {
9659 isc_result_t result;
9660 ns_zoneload_t *zl = (ns_zoneload_t *)arg;
9661
9662 /*
9663 * Force zone maintenance. Do this after loading
9664 * so that we know when we need to force AXFR of
9665 * slave zones whose master files are missing.
9666 *
9667 * We use the zoneload reference counter to let us
9668 * know when all views are finished.
9669 */
9670 if (isc_refcount_decrement(&zl->refs) == 1) {
9671 named_server_t *server = zl->server;
9672 bool reconfig = zl->reconfig;
9673 dns_view_t *view = NULL;
9674
9675 isc_refcount_destroy(&zl->refs);
9676 isc_mem_put(server->mctx, zl, sizeof(*zl));
9677
9678 /*
9679 * To maintain compatibility with log parsing tools that might
9680 * be looking for this string after "rndc reconfig", we keep it
9681 * as it is
9682 */
9683 if (reconfig) {
9684 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9685 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9686 "any newly configured zones are now "
9687 "loaded");
9688 } else {
9689 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9690 NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9691 "all zones loaded");
9692 }
9693
9694 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9695 view = ISC_LIST_NEXT(view, link))
9696 {
9697 if (view->managed_keys != NULL) {
9698 result = dns_zone_synckeyzone(
9699 view->managed_keys);
9700 if (result != ISC_R_SUCCESS) {
9701 isc_log_write(
9702 named_g_lctx,
9703 DNS_LOGCATEGORY_DNSSEC,
9704 DNS_LOGMODULE_DNSSEC,
9705 ISC_LOG_ERROR,
9706 "failed to initialize "
9707 "managed-keys for view %s "
9708 "(%s): DNSSEC validation is "
9709 "at risk",
9710 view->name,
9711 isc_result_totext(result));
9712 }
9713 }
9714 }
9715
9716 CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
9717 "forcing zone maintenance");
9718
9719 named_os_started();
9720
9721 #ifdef HAVE_FIPS_MODE
9722 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9723 NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9724 "FIPS mode is %s",
9725 FIPS_mode() ? "enabled" : "disabled");
9726 #endif /* ifdef HAVE_FIPS_MODE */
9727 atomic_store(&server->reload_status, NAMED_RELOAD_DONE);
9728
9729 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9730 NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9731 "running");
9732 }
9733
9734 return (ISC_R_SUCCESS);
9735 }
9736
9737 static isc_result_t
load_zones(named_server_t * server,bool init,bool reconfig)9738 load_zones(named_server_t *server, bool init, bool reconfig) {
9739 isc_result_t result;
9740 isc_taskmgr_t *taskmgr = dns_zonemgr_gettaskmgr(server->zonemgr);
9741 dns_view_t *view = NULL;
9742 ns_zoneload_t *zl = NULL;
9743
9744 zl = isc_mem_get(server->mctx, sizeof(*zl));
9745 zl->server = server;
9746 zl->reconfig = reconfig;
9747
9748 result = isc_task_beginexclusive(server->task);
9749 RUNTIME_CHECK(result == ISC_R_SUCCESS);
9750
9751 isc_refcount_init(&zl->refs, 1);
9752
9753 /*
9754 * Schedule zones to be loaded from disk.
9755 */
9756 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9757 view = ISC_LIST_NEXT(view, link))
9758 {
9759 if (view->managed_keys != NULL) {
9760 result = dns_zone_load(view->managed_keys, false);
9761 if (result != ISC_R_SUCCESS &&
9762 result != DNS_R_UPTODATE &&
9763 result != DNS_R_CONTINUE)
9764 {
9765 goto cleanup;
9766 }
9767 }
9768 if (view->redirect != NULL) {
9769 result = dns_zone_load(view->redirect, false);
9770 if (result != ISC_R_SUCCESS &&
9771 result != DNS_R_UPTODATE &&
9772 result != DNS_R_CONTINUE)
9773 {
9774 goto cleanup;
9775 }
9776 }
9777
9778 /*
9779 * 'dns_view_asyncload' calls view_loaded if there are no
9780 * zones.
9781 */
9782 isc_refcount_increment(&zl->refs);
9783 result = dns_view_asyncload(view, reconfig, view_loaded, zl);
9784 if (result != ISC_R_SUCCESS) {
9785 isc_refcount_decrement1(&zl->refs);
9786 goto cleanup;
9787 }
9788 }
9789
9790 cleanup:
9791 if (isc_refcount_decrement(&zl->refs) == 1) {
9792 isc_refcount_destroy(&zl->refs);
9793 isc_mem_put(server->mctx, zl, sizeof(*zl));
9794 }
9795
9796 if (init) {
9797 /*
9798 * If we're setting up the server for the first time, set
9799 * the task manager into privileged mode; this ensures
9800 * that no other tasks will begin to run until after zone
9801 * loading is complete. We won't return from exclusive mode
9802 * until the loading is finished; we can then drop out of
9803 * privileged mode.
9804 *
9805 * We do *not* want to do this in the case of reload or
9806 * reconfig, as loading a large zone could cause the server
9807 * to be inactive for too long a time.
9808 */
9809 isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
9810 isc_task_endexclusive(server->task);
9811 isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal);
9812 } else {
9813 isc_task_endexclusive(server->task);
9814 }
9815
9816 return (result);
9817 }
9818
9819 static void
run_server(isc_task_t * task,isc_event_t * event)9820 run_server(isc_task_t *task, isc_event_t *event) {
9821 isc_result_t result;
9822 named_server_t *server = (named_server_t *)event->ev_arg;
9823 dns_geoip_databases_t *geoip;
9824
9825 INSIST(task == server->task);
9826
9827 isc_event_free(&event);
9828
9829 CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, &named_g_dispatchmgr),
9830 "creating dispatch manager");
9831
9832 dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
9833
9834 #if defined(HAVE_GEOIP2)
9835 geoip = named_g_geoip;
9836 #else /* if defined(HAVE_GEOIP2) */
9837 geoip = NULL;
9838 #endif /* if defined(HAVE_GEOIP2) */
9839
9840 CHECKFATAL(ns_interfacemgr_create(
9841 named_g_mctx, server->sctx, named_g_taskmgr,
9842 named_g_timermgr, named_g_socketmgr, named_g_nm,
9843 named_g_dispatchmgr, server->task, named_g_udpdisp,
9844 geoip, named_g_cpus, &server->interfacemgr),
9845 "creating interface manager");
9846
9847 CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9848 NULL, NULL, server->task,
9849 interface_timer_tick, server,
9850 &server->interface_timer),
9851 "creating interface timer");
9852
9853 CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9854 NULL, NULL, server->task,
9855 heartbeat_timer_tick, server,
9856 &server->heartbeat_timer),
9857 "creating heartbeat timer");
9858
9859 CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9860 NULL, NULL, server->task, tat_timer_tick,
9861 server, &server->tat_timer),
9862 "creating trust anchor telemetry timer");
9863
9864 CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9865 NULL, NULL, server->task, pps_timer_tick,
9866 server, &server->pps_timer),
9867 "creating pps timer");
9868
9869 CHECKFATAL(
9870 cfg_parser_create(named_g_mctx, named_g_lctx, &named_g_parser),
9871 "creating default configuration parser");
9872
9873 CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx,
9874 &named_g_addparser),
9875 "creating additional configuration parser");
9876
9877 CHECKFATAL(load_configuration(named_g_conffile, server, true),
9878 "loading configuration");
9879
9880 CHECKFATAL(load_zones(server, true, false), "loading zones");
9881 #ifdef ENABLE_AFL
9882 named_g_run_done = true;
9883 #endif /* ifdef ENABLE_AFL */
9884 }
9885
9886 void
named_server_flushonshutdown(named_server_t * server,bool flush)9887 named_server_flushonshutdown(named_server_t *server, bool flush) {
9888 REQUIRE(NAMED_SERVER_VALID(server));
9889
9890 server->flushonshutdown = flush;
9891 }
9892
9893 static void
shutdown_server(isc_task_t * task,isc_event_t * event)9894 shutdown_server(isc_task_t *task, isc_event_t *event) {
9895 isc_result_t result;
9896 dns_view_t *view, *view_next = NULL;
9897 dns_kasp_t *kasp, *kasp_next = NULL;
9898 named_server_t *server = (named_server_t *)event->ev_arg;
9899 bool flush = server->flushonshutdown;
9900 named_cache_t *nsc;
9901
9902 UNUSED(task);
9903 INSIST(task == server->task);
9904
9905 /*
9906 * We need to shutdown the interface before going
9907 * exclusive (which would pause the netmgr).
9908 */
9909 ns_interfacemgr_shutdown(server->interfacemgr);
9910
9911 result = isc_task_beginexclusive(server->task);
9912 RUNTIME_CHECK(result == ISC_R_SUCCESS);
9913
9914 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9915 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, "shutting down%s",
9916 flush ? ": flushing changes" : "");
9917
9918 named_statschannels_shutdown(server);
9919 named_controls_shutdown(server->controls);
9920 end_reserved_dispatches(server, true);
9921 cleanup_session_key(server, server->mctx);
9922
9923 if (named_g_aclconfctx != NULL) {
9924 cfg_aclconfctx_detach(&named_g_aclconfctx);
9925 }
9926
9927 cfg_obj_destroy(named_g_parser, &named_g_config);
9928 cfg_parser_destroy(&named_g_parser);
9929 cfg_parser_destroy(&named_g_addparser);
9930
9931 (void)named_server_saventa(server);
9932
9933 for (kasp = ISC_LIST_HEAD(server->kasplist); kasp != NULL;
9934 kasp = kasp_next)
9935 {
9936 kasp_next = ISC_LIST_NEXT(kasp, link);
9937 ISC_LIST_UNLINK(server->kasplist, kasp, link);
9938 dns_kasp_detach(&kasp);
9939 }
9940
9941 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
9942 view = view_next)
9943 {
9944 view_next = ISC_LIST_NEXT(view, link);
9945 ISC_LIST_UNLINK(server->viewlist, view, link);
9946 if (flush) {
9947 dns_view_flushanddetach(&view);
9948 } else {
9949 dns_view_detach(&view);
9950 }
9951 }
9952
9953 /*
9954 * Shut down all dyndb instances.
9955 */
9956 dns_dyndb_cleanup(true);
9957
9958 while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
9959 ISC_LIST_UNLINK(server->cachelist, nsc, link);
9960 dns_cache_detach(&nsc->cache);
9961 isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9962 }
9963
9964 isc_timer_destroy(&server->interface_timer);
9965 isc_timer_destroy(&server->heartbeat_timer);
9966 isc_timer_destroy(&server->pps_timer);
9967 isc_timer_destroy(&server->tat_timer);
9968
9969 ns_interfacemgr_detach(&server->interfacemgr);
9970
9971 dns_dispatchmgr_destroy(&named_g_dispatchmgr);
9972
9973 dns_zonemgr_shutdown(server->zonemgr);
9974
9975 if (named_g_sessionkey != NULL) {
9976 dns_tsigkey_detach(&named_g_sessionkey);
9977 dns_name_free(&named_g_sessionkeyname, server->mctx);
9978 }
9979 #if defined(HAVE_GEOIP2)
9980 named_geoip_shutdown();
9981 #endif /* HAVE_GEOIP2 */
9982
9983 dns_db_detach(&server->in_roothints);
9984
9985 isc_task_endexclusive(server->task);
9986
9987 isc_task_detach(&server->task);
9988
9989 isc_event_free(&event);
9990 }
9991
9992 /*%
9993 * Find a view that matches the source and destination addresses of a query.
9994 */
9995 static isc_result_t
get_matching_view(isc_netaddr_t * srcaddr,isc_netaddr_t * destaddr,dns_message_t * message,dns_aclenv_t * env,isc_result_t * sigresult,dns_view_t ** viewp)9996 get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
9997 dns_message_t *message, dns_aclenv_t *env,
9998 isc_result_t *sigresult, dns_view_t **viewp) {
9999 dns_view_t *view;
10000
10001 REQUIRE(message != NULL);
10002 REQUIRE(sigresult != NULL);
10003 REQUIRE(viewp != NULL && *viewp == NULL);
10004
10005 for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
10006 view = ISC_LIST_NEXT(view, link))
10007 {
10008 if (message->rdclass == view->rdclass ||
10009 message->rdclass == dns_rdataclass_any)
10010 {
10011 const dns_name_t *tsig = NULL;
10012
10013 *sigresult = dns_message_rechecksig(message, view);
10014 if (*sigresult == ISC_R_SUCCESS) {
10015 dns_tsigkey_t *tsigkey;
10016
10017 tsigkey = message->tsigkey;
10018 tsig = dns_tsigkey_identity(tsigkey);
10019 }
10020
10021 if (dns_acl_allowed(srcaddr, tsig, view->matchclients,
10022 env) &&
10023 dns_acl_allowed(destaddr, tsig,
10024 view->matchdestinations, env) &&
10025 !(view->matchrecursiveonly &&
10026 (message->flags & DNS_MESSAGEFLAG_RD) == 0))
10027 {
10028 dns_view_attach(view, viewp);
10029 return (ISC_R_SUCCESS);
10030 }
10031 }
10032 }
10033
10034 return (ISC_R_NOTFOUND);
10035 }
10036
10037 void
named_server_create(isc_mem_t * mctx,named_server_t ** serverp)10038 named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
10039 isc_result_t result;
10040 named_server_t *server = isc_mem_get(mctx, sizeof(*server));
10041
10042 *server = (named_server_t){
10043 .mctx = mctx,
10044 .statsfile = isc_mem_strdup(mctx, "named.stats"),
10045 .bindkeysfile = isc_mem_strdup(mctx, named_g_defaultbindkeys),
10046 .dumpfile = isc_mem_strdup(mctx, "named_dump.db"),
10047 .secrootsfile = isc_mem_strdup(mctx, "named.secroots"),
10048 .recfile = isc_mem_strdup(mctx, "named.recursing"),
10049 };
10050
10051 #ifdef USE_DNSRPS
10052 CHECKFATAL(dns_dnsrps_server_create(), "initializing RPZ service "
10053 "interface");
10054 #endif /* ifdef USE_DNSRPS */
10055
10056 /* Initialize server data structures. */
10057 ISC_LIST_INIT(server->kasplist);
10058 ISC_LIST_INIT(server->viewlist);
10059
10060 /* Must be first. */
10061 CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine), "initializing "
10062 "DST");
10063
10064 CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
10065 &server->in_roothints),
10066 "setting up root hints");
10067
10068 isc_mutex_init(&server->reload_event_lock);
10069
10070 server->reload_event = isc_event_allocate(
10071 named_g_mctx, server, NAMED_EVENT_RELOAD, named_server_reload,
10072 server, sizeof(isc_event_t));
10073 CHECKFATAL(server->reload_event == NULL ? ISC_R_NOMEMORY
10074 : ISC_R_SUCCESS,
10075 "allocating reload event");
10076 atomic_init(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10077
10078 /*
10079 * Setup the server task, which is responsible for coordinating
10080 * startup and shutdown of the server, as well as all exclusive
10081 * tasks.
10082 */
10083 CHECKFATAL(isc_task_create_bound(named_g_taskmgr, 0, &server->task, 0),
10084 "creating server task");
10085 isc_task_setname(server->task, "server", server);
10086 isc_taskmgr_setexcltask(named_g_taskmgr, server->task);
10087
10088 CHECKFATAL(ns_server_create(mctx, get_matching_view, &server->sctx),
10089 "creating server context");
10090
10091 #if defined(HAVE_GEOIP2)
10092 /*
10093 * GeoIP must be initialized before the interface
10094 * manager (which includes the ACL environment)
10095 * is created.
10096 */
10097 named_geoip_init();
10098 #endif /* HAVE_GEOIP2 */
10099
10100 #ifdef ENABLE_AFL
10101 server->sctx->fuzztype = named_g_fuzz_type;
10102 server->sctx->fuzznotify = named_fuzz_notify;
10103 #endif /* ifdef ENABLE_AFL */
10104
10105 CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
10106 "isc_task_onshutdown");
10107 CHECKFATAL(
10108 isc_app_onrun(named_g_mctx, server->task, run_server, server),
10109 "isc_app_onrun");
10110
10111 CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr,
10112 named_g_timermgr, named_g_socketmgr,
10113 &server->zonemgr),
10114 "dns_zonemgr_create");
10115 CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_"
10116 "setsize");
10117
10118 CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
10119 isc_sockstatscounter_max),
10120 "isc_stats_create");
10121 isc_socketmgr_setstats(named_g_socketmgr, server->sockstats);
10122 isc_nm_setstats(named_g_nm, server->sockstats);
10123
10124 CHECKFATAL(isc_stats_create(named_g_mctx, &server->zonestats,
10125 dns_zonestatscounter_max),
10126 "dns_stats_create (zone)");
10127
10128 CHECKFATAL(isc_stats_create(named_g_mctx, &server->resolverstats,
10129 dns_resstatscounter_max),
10130 "dns_stats_create (resolver)");
10131
10132 CHECKFATAL(named_controls_create(server, &server->controls),
10133 "named_controls_create");
10134
10135 ISC_LIST_INIT(server->dispatches);
10136
10137 ISC_LIST_INIT(server->statschannels);
10138
10139 ISC_LIST_INIT(server->cachelist);
10140
10141 server->magic = NAMED_SERVER_MAGIC;
10142 *serverp = server;
10143 }
10144
10145 void
named_server_destroy(named_server_t ** serverp)10146 named_server_destroy(named_server_t **serverp) {
10147 named_server_t *server = *serverp;
10148 REQUIRE(NAMED_SERVER_VALID(server));
10149
10150 #ifdef HAVE_DNSTAP
10151 if (server->dtenv != NULL) {
10152 dns_dt_detach(&server->dtenv);
10153 }
10154 #endif /* HAVE_DNSTAP */
10155
10156 #ifdef USE_DNSRPS
10157 dns_dnsrps_server_destroy();
10158 #endif /* ifdef USE_DNSRPS */
10159
10160 named_controls_destroy(&server->controls);
10161
10162 isc_stats_detach(&server->zonestats);
10163 isc_stats_detach(&server->sockstats);
10164 isc_stats_detach(&server->resolverstats);
10165
10166 if (server->sctx != NULL) {
10167 ns_server_detach(&server->sctx);
10168 }
10169
10170 isc_mem_free(server->mctx, server->statsfile);
10171 isc_mem_free(server->mctx, server->bindkeysfile);
10172 isc_mem_free(server->mctx, server->dumpfile);
10173 isc_mem_free(server->mctx, server->secrootsfile);
10174 isc_mem_free(server->mctx, server->recfile);
10175
10176 if (server->version != NULL) {
10177 isc_mem_free(server->mctx, server->version);
10178 }
10179 if (server->hostname != NULL) {
10180 isc_mem_free(server->mctx, server->hostname);
10181 }
10182 if (server->lockfile != NULL) {
10183 isc_mem_free(server->mctx, server->lockfile);
10184 }
10185
10186 if (server->zonemgr != NULL) {
10187 dns_zonemgr_detach(&server->zonemgr);
10188 }
10189
10190 dst_lib_destroy();
10191
10192 isc_event_free(&server->reload_event);
10193 isc_mutex_destroy(&server->reload_event_lock);
10194
10195 INSIST(ISC_LIST_EMPTY(server->kasplist));
10196 INSIST(ISC_LIST_EMPTY(server->viewlist));
10197 INSIST(ISC_LIST_EMPTY(server->cachelist));
10198
10199 server->magic = 0;
10200 isc_mem_put(server->mctx, server, sizeof(*server));
10201 *serverp = NULL;
10202 }
10203
10204 static void
fatal(named_server_t * server,const char * msg,isc_result_t result)10205 fatal(named_server_t *server, const char *msg, isc_result_t result) {
10206 if (server != NULL && server->task != NULL) {
10207 /*
10208 * Prevent races between the OpenSSL on_exit registered
10209 * function and any other OpenSSL calls from other tasks
10210 * by requesting exclusive access to the task manager.
10211 */
10212 (void)isc_task_beginexclusive(server->task);
10213 }
10214 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10215 NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL, "%s: %s", msg,
10216 isc_result_totext(result));
10217 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10218 NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
10219 "exiting (due to fatal error)");
10220 named_os_shutdown();
10221 exit(1);
10222 }
10223
10224 static void
start_reserved_dispatches(named_server_t * server)10225 start_reserved_dispatches(named_server_t *server) {
10226 REQUIRE(NAMED_SERVER_VALID(server));
10227
10228 server->dispatchgen++;
10229 }
10230
10231 static void
end_reserved_dispatches(named_server_t * server,bool all)10232 end_reserved_dispatches(named_server_t *server, bool all) {
10233 named_dispatch_t *dispatch, *nextdispatch;
10234
10235 REQUIRE(NAMED_SERVER_VALID(server));
10236
10237 for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10238 dispatch = nextdispatch)
10239 {
10240 nextdispatch = ISC_LIST_NEXT(dispatch, link);
10241 if (!all && server->dispatchgen == dispatch->dispatchgen) {
10242 continue;
10243 }
10244 ISC_LIST_UNLINK(server->dispatches, dispatch, link);
10245 dns_dispatch_detach(&dispatch->dispatch);
10246 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10247 }
10248 }
10249
10250 void
named_add_reserved_dispatch(named_server_t * server,const isc_sockaddr_t * addr)10251 named_add_reserved_dispatch(named_server_t *server,
10252 const isc_sockaddr_t *addr) {
10253 named_dispatch_t *dispatch;
10254 in_port_t port;
10255 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
10256 isc_result_t result;
10257 unsigned int attrs, attrmask;
10258
10259 REQUIRE(NAMED_SERVER_VALID(server));
10260
10261 port = isc_sockaddr_getport(addr);
10262 if (port == 0 || port >= 1024) {
10263 return;
10264 }
10265
10266 for (dispatch = ISC_LIST_HEAD(server->dispatches); dispatch != NULL;
10267 dispatch = ISC_LIST_NEXT(dispatch, link))
10268 {
10269 if (isc_sockaddr_equal(&dispatch->addr, addr)) {
10270 break;
10271 }
10272 }
10273 if (dispatch != NULL) {
10274 dispatch->dispatchgen = server->dispatchgen;
10275 return;
10276 }
10277
10278 dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
10279
10280 dispatch->addr = *addr;
10281 dispatch->dispatchgen = server->dispatchgen;
10282 dispatch->dispatch = NULL;
10283
10284 attrs = 0;
10285 attrs |= DNS_DISPATCHATTR_UDP;
10286 switch (isc_sockaddr_pf(addr)) {
10287 case AF_INET:
10288 attrs |= DNS_DISPATCHATTR_IPV4;
10289 break;
10290 case AF_INET6:
10291 attrs |= DNS_DISPATCHATTR_IPV6;
10292 break;
10293 default:
10294 result = ISC_R_NOTIMPLEMENTED;
10295 goto cleanup;
10296 }
10297 attrmask = 0;
10298 attrmask |= DNS_DISPATCHATTR_UDP;
10299 attrmask |= DNS_DISPATCHATTR_TCP;
10300 attrmask |= DNS_DISPATCHATTR_IPV4;
10301 attrmask |= DNS_DISPATCHATTR_IPV6;
10302
10303 result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr,
10304 named_g_taskmgr, &dispatch->addr, 4096,
10305 UDPBUFFERS, 32768, 16411, 16433, attrs,
10306 attrmask, &dispatch->dispatch);
10307 if (result != ISC_R_SUCCESS) {
10308 goto cleanup;
10309 }
10310
10311 ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
10312
10313 return;
10314
10315 cleanup:
10316 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
10317 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
10318 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10319 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
10320 "unable to create dispatch for reserved port %s: %s",
10321 addrbuf, isc_result_totext(result));
10322 }
10323
10324 static isc_result_t
loadconfig(named_server_t * server)10325 loadconfig(named_server_t *server) {
10326 isc_result_t result;
10327 start_reserved_dispatches(server);
10328 result = load_configuration(named_g_conffile, server, false);
10329 if (result == ISC_R_SUCCESS) {
10330 end_reserved_dispatches(server, false);
10331 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10332 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10333 "reloading configuration succeeded");
10334 } else {
10335 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10336 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10337 "reloading configuration failed: %s",
10338 isc_result_totext(result));
10339 atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10340 }
10341
10342 return (result);
10343 }
10344
10345 static isc_result_t
reload(named_server_t * server)10346 reload(named_server_t *server) {
10347 isc_result_t result;
10348
10349 atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10350
10351 CHECK(loadconfig(server));
10352
10353 result = load_zones(server, false, false);
10354 if (result == ISC_R_SUCCESS) {
10355 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10356 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10357 "reloading zones succeeded");
10358 } else {
10359 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10360 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10361 "reloading zones failed: %s",
10362 isc_result_totext(result));
10363 atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10364 }
10365 cleanup:
10366 return (result);
10367 }
10368
10369 /*
10370 * Handle a reload event (from SIGHUP).
10371 */
10372 static void
named_server_reload(isc_task_t * task,isc_event_t * event)10373 named_server_reload(isc_task_t *task, isc_event_t *event) {
10374 named_server_t *server = (named_server_t *)event->ev_arg;
10375
10376 INSIST(task == server->task);
10377 UNUSED(task);
10378
10379 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10380 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10381 "received SIGHUP signal to reload zones");
10382 (void)reload(server);
10383
10384 LOCK(&server->reload_event_lock);
10385 INSIST(server->reload_event == NULL);
10386 server->reload_event = event;
10387 UNLOCK(&server->reload_event_lock);
10388 }
10389
10390 void
named_server_reloadwanted(named_server_t * server)10391 named_server_reloadwanted(named_server_t *server) {
10392 LOCK(&server->reload_event_lock);
10393 if (server->reload_event != NULL) {
10394 isc_task_send(server->task, &server->reload_event);
10395 }
10396 UNLOCK(&server->reload_event_lock);
10397 }
10398
10399 void
named_server_scan_interfaces(named_server_t * server)10400 named_server_scan_interfaces(named_server_t *server) {
10401 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10402 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
10403 "automatic interface rescan");
10404
10405 ns_interfacemgr_scan(server->interfacemgr, true);
10406 }
10407
10408 /*
10409 * Get the next token from lexer 'lex'.
10410 *
10411 * NOTE: the token value for string tokens always uses the same pointer
10412 * value. Multiple calls to this function on the same lexer will always
10413 * return either that value (lex->data) or NULL. It is necessary to copy
10414 * the token into local storage if it needs to be referenced after the next
10415 * call to next_token().
10416 */
10417 static char *
next_token(isc_lex_t * lex,isc_buffer_t ** text)10418 next_token(isc_lex_t *lex, isc_buffer_t **text) {
10419 isc_result_t result;
10420 isc_token_t token;
10421
10422 token.type = isc_tokentype_unknown;
10423 result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING,
10424 &token);
10425
10426 switch (result) {
10427 case ISC_R_NOMORE:
10428 (void)isc_lex_close(lex);
10429 break;
10430 case ISC_R_SUCCESS:
10431 if (token.type == isc_tokentype_eof) {
10432 (void)isc_lex_close(lex);
10433 }
10434 break;
10435 case ISC_R_NOSPACE:
10436 if (text != NULL) {
10437 (void)putstr(text, "token too large");
10438 (void)putnull(text);
10439 }
10440 return (NULL);
10441 default:
10442 if (text != NULL) {
10443 (void)putstr(text, isc_result_totext(result));
10444 (void)putnull(text);
10445 }
10446 return (NULL);
10447 }
10448
10449 if (token.type == isc_tokentype_string ||
10450 token.type == isc_tokentype_qstring)
10451 {
10452 return (token.value.as_textregion.base);
10453 }
10454
10455 return (NULL);
10456 }
10457
10458 /*
10459 * Find the zone specified in the control channel command, if any.
10460 * If a zone is specified, point '*zonep' at it, otherwise
10461 * set '*zonep' to NULL, and f 'zonename' is not NULL, copy
10462 * the zone name into it (N.B. 'zonename' must have space to hold
10463 * a full DNS name).
10464 *
10465 * If 'zonetxt' is set, the caller has already pulled a token
10466 * off the command line that is to be used as the zone name. (This
10467 * is sometimes done when it's necessary to check for an optional
10468 * argument before the zone name, as in "rndc sync [-clean] zone".)
10469 */
10470 static isc_result_t
zone_from_args(named_server_t * server,isc_lex_t * lex,const char * zonetxt,dns_zone_t ** zonep,char * zonename,isc_buffer_t ** text,bool skip)10471 zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
10472 dns_zone_t **zonep, char *zonename, isc_buffer_t **text,
10473 bool skip) {
10474 char *ptr;
10475 char *classtxt;
10476 const char *viewtxt = NULL;
10477 dns_fixedname_t fname;
10478 dns_name_t *name;
10479 isc_result_t result;
10480 dns_view_t *view = NULL;
10481 dns_rdataclass_t rdclass;
10482 char problem[DNS_NAME_FORMATSIZE + 500] = "";
10483 char zonebuf[DNS_NAME_FORMATSIZE];
10484 bool redirect = false;
10485
10486 REQUIRE(zonep != NULL && *zonep == NULL);
10487
10488 if (skip) {
10489 /* Skip the command name. */
10490 ptr = next_token(lex, text);
10491 if (ptr == NULL) {
10492 return (ISC_R_UNEXPECTEDEND);
10493 }
10494 }
10495
10496 /* Look for the zone name. */
10497 if (zonetxt == NULL) {
10498 zonetxt = next_token(lex, text);
10499 }
10500 if (zonetxt == NULL) {
10501 return (ISC_R_SUCCESS);
10502 }
10503
10504 /* Copy zonetxt because it'll be overwritten by next_token() */
10505 /* To locate a zone named "-redirect" use "-redirect." */
10506 if (strcmp(zonetxt, "-redirect") == 0) {
10507 redirect = true;
10508 strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE);
10509 } else {
10510 strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE);
10511 }
10512 if (zonename != NULL) {
10513 strlcpy(zonename, redirect ? "." : zonetxt,
10514 DNS_NAME_FORMATSIZE);
10515 }
10516
10517 name = dns_fixedname_initname(&fname);
10518 CHECK(dns_name_fromstring(name, zonebuf, 0, NULL));
10519
10520 /* Look for the optional class name. */
10521 classtxt = next_token(lex, text);
10522 if (classtxt != NULL) {
10523 isc_textregion_t r;
10524 r.base = classtxt;
10525 r.length = strlen(classtxt);
10526 CHECK(dns_rdataclass_fromtext(&rdclass, &r));
10527
10528 /* Look for the optional view name. */
10529 viewtxt = next_token(lex, text);
10530 } else {
10531 rdclass = dns_rdataclass_in;
10532 }
10533
10534 if (viewtxt == NULL) {
10535 if (redirect) {
10536 result = dns_viewlist_find(&server->viewlist,
10537 "_default",
10538 dns_rdataclass_in, &view);
10539 if (result != ISC_R_SUCCESS || view->redirect == NULL) {
10540 result = ISC_R_NOTFOUND;
10541 snprintf(problem, sizeof(problem),
10542 "redirect zone not found in "
10543 "_default view");
10544 } else {
10545 dns_zone_attach(view->redirect, zonep);
10546 result = ISC_R_SUCCESS;
10547 }
10548 } else {
10549 result = dns_viewlist_findzone(&server->viewlist, name,
10550 (classtxt == NULL),
10551 rdclass, zonep);
10552 if (result == ISC_R_NOTFOUND) {
10553 snprintf(problem, sizeof(problem),
10554 "no matching zone '%s' in any view",
10555 zonebuf);
10556 } else if (result == ISC_R_MULTIPLE) {
10557 snprintf(problem, sizeof(problem),
10558 "zone '%s' was found in multiple "
10559 "views",
10560 zonebuf);
10561 }
10562 }
10563 } else {
10564 result = dns_viewlist_find(&server->viewlist, viewtxt, rdclass,
10565 &view);
10566 if (result != ISC_R_SUCCESS) {
10567 snprintf(problem, sizeof(problem),
10568 "no matching view '%s'", viewtxt);
10569 goto report;
10570 }
10571
10572 if (redirect) {
10573 if (view->redirect != NULL) {
10574 dns_zone_attach(view->redirect, zonep);
10575 result = ISC_R_SUCCESS;
10576 } else {
10577 result = ISC_R_NOTFOUND;
10578 }
10579 } else {
10580 result = dns_zt_find(view->zonetable, name, 0, NULL,
10581 zonep);
10582 }
10583 if (result != ISC_R_SUCCESS) {
10584 snprintf(problem, sizeof(problem),
10585 "no matching zone '%s' in view '%s'", zonebuf,
10586 viewtxt);
10587 }
10588 }
10589
10590 /* Partial match? */
10591 if (result != ISC_R_SUCCESS && *zonep != NULL) {
10592 dns_zone_detach(zonep);
10593 }
10594 if (result == DNS_R_PARTIALMATCH) {
10595 result = ISC_R_NOTFOUND;
10596 }
10597 report:
10598 if (result != ISC_R_SUCCESS) {
10599 isc_result_t tresult;
10600
10601 tresult = putstr(text, problem);
10602 if (tresult == ISC_R_SUCCESS) {
10603 (void)putnull(text);
10604 }
10605 }
10606
10607 cleanup:
10608 if (view != NULL) {
10609 dns_view_detach(&view);
10610 }
10611
10612 return (result);
10613 }
10614
10615 /*
10616 * Act on a "retransfer" command from the command channel.
10617 */
10618 isc_result_t
named_server_retransfercommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10619 named_server_retransfercommand(named_server_t *server, isc_lex_t *lex,
10620 isc_buffer_t **text) {
10621 isc_result_t result;
10622 dns_zone_t *zone = NULL;
10623 dns_zone_t *raw = NULL;
10624 dns_zonetype_t type;
10625
10626 REQUIRE(text != NULL);
10627
10628 result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10629 if (result != ISC_R_SUCCESS) {
10630 return (result);
10631 }
10632 if (zone == NULL) {
10633 return (ISC_R_UNEXPECTEDEND);
10634 }
10635 dns_zone_getraw(zone, &raw);
10636 if (raw != NULL) {
10637 dns_zone_detach(&zone);
10638 dns_zone_attach(raw, &zone);
10639 dns_zone_detach(&raw);
10640 }
10641 type = dns_zone_gettype(zone);
10642 if (type == dns_zone_secondary || type == dns_zone_mirror ||
10643 type == dns_zone_stub ||
10644 (type == dns_zone_redirect &&
10645 dns_zone_getredirecttype(zone) == dns_zone_secondary))
10646 {
10647 dns_zone_forcereload(zone);
10648 } else {
10649 (void)putstr(text, "retransfer: inappropriate zone type: ");
10650 (void)putstr(text, dns_zonetype_name(type));
10651 if (type == dns_zone_redirect) {
10652 type = dns_zone_getredirecttype(zone);
10653 (void)putstr(text, "(");
10654 (void)putstr(text, dns_zonetype_name(type));
10655 (void)putstr(text, ")");
10656 }
10657 (void)putnull(text);
10658 result = ISC_R_FAILURE;
10659 }
10660 dns_zone_detach(&zone);
10661 return (result);
10662 }
10663
10664 /*
10665 * Act on a "reload" command from the command channel.
10666 */
10667 isc_result_t
named_server_reloadcommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10668 named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
10669 isc_buffer_t **text) {
10670 isc_result_t result;
10671 dns_zone_t *zone = NULL;
10672 dns_zonetype_t type;
10673 const char *msg = NULL;
10674
10675 REQUIRE(text != NULL);
10676
10677 result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10678 if (result != ISC_R_SUCCESS) {
10679 return (result);
10680 }
10681 if (zone == NULL) {
10682 result = reload(server);
10683 if (result == ISC_R_SUCCESS) {
10684 msg = "server reload successful";
10685 }
10686 } else {
10687 type = dns_zone_gettype(zone);
10688 if (type == dns_zone_secondary || type == dns_zone_mirror ||
10689 type == dns_zone_stub)
10690 {
10691 dns_zone_refresh(zone);
10692 dns_zone_detach(&zone);
10693 msg = "zone refresh queued";
10694 } else {
10695 result = dns_zone_load(zone, false);
10696 dns_zone_detach(&zone);
10697 switch (result) {
10698 case ISC_R_SUCCESS:
10699 msg = "zone reload successful";
10700 break;
10701 case DNS_R_CONTINUE:
10702 msg = "zone reload queued";
10703 result = ISC_R_SUCCESS;
10704 break;
10705 case DNS_R_UPTODATE:
10706 msg = "zone reload up-to-date";
10707 result = ISC_R_SUCCESS;
10708 break;
10709 default:
10710 /* failure message will be generated by rndc */
10711 break;
10712 }
10713 }
10714 }
10715 if (msg != NULL) {
10716 (void)putstr(text, msg);
10717 (void)putnull(text);
10718 }
10719 return (result);
10720 }
10721
10722 /*
10723 * Act on a "reconfig" command from the command channel.
10724 */
10725 isc_result_t
named_server_reconfigcommand(named_server_t * server)10726 named_server_reconfigcommand(named_server_t *server) {
10727 isc_result_t result;
10728 atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
10729
10730 CHECK(loadconfig(server));
10731
10732 result = load_zones(server, false, true);
10733 if (result == ISC_R_SUCCESS) {
10734 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10735 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10736 "scheduled loading new zones");
10737 } else {
10738 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10739 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10740 "loading new zones failed: %s",
10741 isc_result_totext(result));
10742 atomic_store(&server->reload_status, NAMED_RELOAD_FAILED);
10743 }
10744 cleanup:
10745 return (result);
10746 }
10747
10748 /*
10749 * Act on a "notify" command from the command channel.
10750 */
10751 isc_result_t
named_server_notifycommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10752 named_server_notifycommand(named_server_t *server, isc_lex_t *lex,
10753 isc_buffer_t **text) {
10754 isc_result_t result;
10755 dns_zone_t *zone = NULL;
10756 const char msg[] = "zone notify queued";
10757
10758 REQUIRE(text != NULL);
10759
10760 result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10761 if (result != ISC_R_SUCCESS) {
10762 return (result);
10763 }
10764 if (zone == NULL) {
10765 return (ISC_R_UNEXPECTEDEND);
10766 }
10767
10768 dns_zone_notify(zone);
10769 dns_zone_detach(&zone);
10770 (void)putstr(text, msg);
10771 (void)putnull(text);
10772
10773 return (ISC_R_SUCCESS);
10774 }
10775
10776 /*
10777 * Act on a "refresh" command from the command channel.
10778 */
10779 isc_result_t
named_server_refreshcommand(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)10780 named_server_refreshcommand(named_server_t *server, isc_lex_t *lex,
10781 isc_buffer_t **text) {
10782 isc_result_t result;
10783 dns_zone_t *zone = NULL, *raw = NULL;
10784 const char msg1[] = "zone refresh queued";
10785 const char msg2[] = "not a slave, mirror, or stub zone";
10786 dns_zonetype_t type;
10787
10788 REQUIRE(text != NULL);
10789
10790 result = zone_from_args(server, lex, NULL, &zone, NULL, text, true);
10791 if (result != ISC_R_SUCCESS) {
10792 return (result);
10793 }
10794 if (zone == NULL) {
10795 return (ISC_R_UNEXPECTEDEND);
10796 }
10797
10798 dns_zone_getraw(zone, &raw);
10799 if (raw != NULL) {
10800 dns_zone_detach(&zone);
10801 dns_zone_attach(raw, &zone);
10802 dns_zone_detach(&raw);
10803 }
10804
10805 type = dns_zone_gettype(zone);
10806 if (type == dns_zone_secondary || type == dns_zone_mirror ||
10807 type == dns_zone_stub)
10808 {
10809 dns_zone_refresh(zone);
10810 dns_zone_detach(&zone);
10811 (void)putstr(text, msg1);
10812 (void)putnull(text);
10813 return (ISC_R_SUCCESS);
10814 }
10815
10816 dns_zone_detach(&zone);
10817 (void)putstr(text, msg2);
10818 (void)putnull(text);
10819 return (ISC_R_FAILURE);
10820 }
10821
10822 isc_result_t
named_server_togglequerylog(named_server_t * server,isc_lex_t * lex)10823 named_server_togglequerylog(named_server_t *server, isc_lex_t *lex) {
10824 bool prev, value;
10825 char *ptr;
10826
10827 /* Skip the command name. */
10828 ptr = next_token(lex, NULL);
10829 if (ptr == NULL) {
10830 return (ISC_R_UNEXPECTEDEND);
10831 }
10832
10833 prev = ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES);
10834
10835 ptr = next_token(lex, NULL);
10836 if (ptr == NULL) {
10837 value = !prev;
10838 } else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
10839 !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
10840 {
10841 value = true;
10842 } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
10843 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
10844 {
10845 value = false;
10846 } else {
10847 return (DNS_R_SYNTAX);
10848 }
10849
10850 if (value == prev) {
10851 return (ISC_R_SUCCESS);
10852 }
10853
10854 ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES, value);
10855
10856 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10857 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10858 "query logging is now %s", value ? "on" : "off");
10859 return (ISC_R_SUCCESS);
10860 }
10861
10862 static isc_result_t
ns_listenlist_fromconfig(const cfg_obj_t * listenlist,const cfg_obj_t * config,cfg_aclconfctx_t * actx,isc_mem_t * mctx,uint16_t family,ns_listenlist_t ** target)10863 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
10864 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
10865 uint16_t family, ns_listenlist_t **target) {
10866 isc_result_t result;
10867 const cfg_listelt_t *element;
10868 ns_listenlist_t *dlist = NULL;
10869
10870 REQUIRE(target != NULL && *target == NULL);
10871
10872 result = ns_listenlist_create(mctx, &dlist);
10873 if (result != ISC_R_SUCCESS) {
10874 return (result);
10875 }
10876
10877 for (element = cfg_list_first(listenlist); element != NULL;
10878 element = cfg_list_next(element))
10879 {
10880 ns_listenelt_t *delt = NULL;
10881 const cfg_obj_t *listener = cfg_listelt_value(element);
10882 result = ns_listenelt_fromconfig(listener, config, actx, mctx,
10883 family, &delt);
10884 if (result != ISC_R_SUCCESS) {
10885 goto cleanup;
10886 }
10887 ISC_LIST_APPEND(dlist->elts, delt, link);
10888 }
10889 *target = dlist;
10890 return (ISC_R_SUCCESS);
10891
10892 cleanup:
10893 ns_listenlist_detach(&dlist);
10894 return (result);
10895 }
10896
10897 /*
10898 * Create a listen list from the corresponding configuration
10899 * data structure.
10900 */
10901 static isc_result_t
ns_listenelt_fromconfig(const cfg_obj_t * listener,const cfg_obj_t * config,cfg_aclconfctx_t * actx,isc_mem_t * mctx,uint16_t family,ns_listenelt_t ** target)10902 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
10903 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
10904 uint16_t family, ns_listenelt_t **target) {
10905 isc_result_t result;
10906 const cfg_obj_t *portobj, *dscpobj;
10907 in_port_t port;
10908 isc_dscp_t dscp = -1;
10909 ns_listenelt_t *delt = NULL;
10910 REQUIRE(target != NULL && *target == NULL);
10911
10912 portobj = cfg_tuple_get(listener, "port");
10913 if (!cfg_obj_isuint32(portobj)) {
10914 if (named_g_port != 0) {
10915 port = named_g_port;
10916 } else {
10917 result = named_config_getport(config, &port);
10918 if (result != ISC_R_SUCCESS) {
10919 return (result);
10920 }
10921 }
10922 } else {
10923 if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
10924 cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR,
10925 "port value '%u' is out of range",
10926 cfg_obj_asuint32(portobj));
10927 return (ISC_R_RANGE);
10928 }
10929 port = (in_port_t)cfg_obj_asuint32(portobj);
10930 }
10931
10932 dscpobj = cfg_tuple_get(listener, "dscp");
10933 if (!cfg_obj_isuint32(dscpobj)) {
10934 dscp = named_g_dscp;
10935 } else {
10936 if (cfg_obj_asuint32(dscpobj) > 63) {
10937 cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR,
10938 "dscp value '%u' is out of range",
10939 cfg_obj_asuint32(dscpobj));
10940 return (ISC_R_RANGE);
10941 }
10942 dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
10943 }
10944
10945 result = ns_listenelt_create(mctx, port, dscp, NULL, &delt);
10946 if (result != ISC_R_SUCCESS) {
10947 return (result);
10948 }
10949
10950 result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"), config,
10951 named_g_lctx, actx, mctx, 0, family,
10952 &delt->acl);
10953 if (result != ISC_R_SUCCESS) {
10954 ns_listenelt_destroy(delt);
10955 return (result);
10956 }
10957 *target = delt;
10958 return (ISC_R_SUCCESS);
10959 }
10960
10961 isc_result_t
named_server_dumpstats(named_server_t * server)10962 named_server_dumpstats(named_server_t *server) {
10963 isc_result_t result;
10964 FILE *fp = NULL;
10965
10966 CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
10967 "could not open statistics dump file", server->statsfile);
10968
10969 result = named_stats_dump(server, fp);
10970
10971 cleanup:
10972 if (fp != NULL) {
10973 (void)isc_stdio_close(fp);
10974 }
10975 if (result == ISC_R_SUCCESS) {
10976 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10977 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10978 "dumpstats complete");
10979 } else {
10980 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10981 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10982 "dumpstats failed: %s",
10983 dns_result_totext(result));
10984 }
10985 return (result);
10986 }
10987
10988 static isc_result_t
add_zone_tolist(dns_zone_t * zone,void * uap)10989 add_zone_tolist(dns_zone_t *zone, void *uap) {
10990 struct dumpcontext *dctx = uap;
10991 struct zonelistentry *zle;
10992
10993 zle = isc_mem_get(dctx->mctx, sizeof *zle);
10994 zle->zone = NULL;
10995 dns_zone_attach(zone, &zle->zone);
10996 ISC_LINK_INIT(zle, link);
10997 ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
10998 return (ISC_R_SUCCESS);
10999 }
11000
11001 static isc_result_t
add_view_tolist(struct dumpcontext * dctx,dns_view_t * view)11002 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
11003 struct viewlistentry *vle;
11004 isc_result_t result = ISC_R_SUCCESS;
11005
11006 /*
11007 * Prevent duplicate views.
11008 */
11009 for (vle = ISC_LIST_HEAD(dctx->viewlist); vle != NULL;
11010 vle = ISC_LIST_NEXT(vle, link))
11011 {
11012 if (vle->view == view) {
11013 return (ISC_R_SUCCESS);
11014 }
11015 }
11016
11017 vle = isc_mem_get(dctx->mctx, sizeof *vle);
11018 vle->view = NULL;
11019 dns_view_attach(view, &vle->view);
11020 ISC_LINK_INIT(vle, link);
11021 ISC_LIST_INIT(vle->zonelist);
11022 ISC_LIST_APPEND(dctx->viewlist, vle, link);
11023 if (dctx->dumpzones) {
11024 result = dns_zt_apply(view->zonetable, isc_rwlocktype_read,
11025 true, NULL, add_zone_tolist, dctx);
11026 }
11027 return (result);
11028 }
11029
11030 static void
dumpcontext_destroy(struct dumpcontext * dctx)11031 dumpcontext_destroy(struct dumpcontext *dctx) {
11032 struct viewlistentry *vle;
11033 struct zonelistentry *zle;
11034
11035 vle = ISC_LIST_HEAD(dctx->viewlist);
11036 while (vle != NULL) {
11037 ISC_LIST_UNLINK(dctx->viewlist, vle, link);
11038 zle = ISC_LIST_HEAD(vle->zonelist);
11039 while (zle != NULL) {
11040 ISC_LIST_UNLINK(vle->zonelist, zle, link);
11041 dns_zone_detach(&zle->zone);
11042 isc_mem_put(dctx->mctx, zle, sizeof *zle);
11043 zle = ISC_LIST_HEAD(vle->zonelist);
11044 }
11045 dns_view_detach(&vle->view);
11046 isc_mem_put(dctx->mctx, vle, sizeof *vle);
11047 vle = ISC_LIST_HEAD(dctx->viewlist);
11048 }
11049 if (dctx->version != NULL) {
11050 dns_db_closeversion(dctx->db, &dctx->version, false);
11051 }
11052 if (dctx->db != NULL) {
11053 dns_db_detach(&dctx->db);
11054 }
11055 if (dctx->cache != NULL) {
11056 dns_db_detach(&dctx->cache);
11057 }
11058 if (dctx->task != NULL) {
11059 isc_task_detach(&dctx->task);
11060 }
11061 if (dctx->fp != NULL) {
11062 (void)isc_stdio_close(dctx->fp);
11063 }
11064 if (dctx->mdctx != NULL) {
11065 dns_dumpctx_detach(&dctx->mdctx);
11066 }
11067 isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
11068 }
11069
11070 static void
dumpdone(void * arg,isc_result_t result)11071 dumpdone(void *arg, isc_result_t result) {
11072 struct dumpcontext *dctx = arg;
11073 char buf[1024 + 32];
11074 const dns_master_style_t *style;
11075
11076 if (result != ISC_R_SUCCESS) {
11077 goto cleanup;
11078 }
11079 if (dctx->mdctx != NULL) {
11080 dns_dumpctx_detach(&dctx->mdctx);
11081 }
11082 if (dctx->view == NULL) {
11083 dctx->view = ISC_LIST_HEAD(dctx->viewlist);
11084 if (dctx->view == NULL) {
11085 goto done;
11086 }
11087 INSIST(dctx->zone == NULL);
11088 } else {
11089 goto resume;
11090 }
11091 nextview:
11092 fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
11093 resume:
11094 if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
11095 fprintf(dctx->fp, ";\n; Cache of view '%s' is shared as '%s'\n",
11096 dctx->view->view->name,
11097 dns_cache_getname(dctx->view->view->cache));
11098 } else if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache)
11099 {
11100 if (dctx->dumpexpired) {
11101 style = &dns_master_style_cache_with_expired;
11102 } else {
11103 style = &dns_master_style_cache;
11104 }
11105 /* start cache dump */
11106 if (dctx->view->view->cachedb != NULL) {
11107 dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11108 }
11109 if (dctx->cache != NULL) {
11110 fprintf(dctx->fp,
11111 ";\n; Cache dump of view '%s' (cache %s)\n;\n",
11112 dctx->view->view->name,
11113 dns_cache_getname(dctx->view->view->cache));
11114 result = dns_master_dumptostreamasync(
11115 dctx->mctx, dctx->cache, NULL, style, dctx->fp,
11116 dctx->task, dumpdone, dctx, &dctx->mdctx);
11117 if (result == DNS_R_CONTINUE) {
11118 return;
11119 }
11120 if (result == ISC_R_NOTIMPLEMENTED) {
11121 fprintf(dctx->fp, "; %s\n",
11122 dns_result_totext(result));
11123 } else if (result != ISC_R_SUCCESS) {
11124 goto cleanup;
11125 }
11126 }
11127 }
11128
11129 if ((dctx->dumpadb || dctx->dumpbad || dctx->dumpfail) &&
11130 dctx->cache == NULL && dctx->view->view->cachedb != NULL)
11131 {
11132 dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
11133 }
11134
11135 if (dctx->cache != NULL) {
11136 if (dctx->dumpadb) {
11137 dns_adb_dump(dctx->view->view->adb, dctx->fp);
11138 }
11139 if (dctx->dumpbad) {
11140 dns_resolver_printbadcache(dctx->view->view->resolver,
11141 dctx->fp);
11142 }
11143 if (dctx->dumpfail) {
11144 dns_badcache_print(dctx->view->view->failcache,
11145 "SERVFAIL cache", dctx->fp);
11146 }
11147 dns_db_detach(&dctx->cache);
11148 }
11149 if (dctx->dumpzones) {
11150 style = &dns_master_style_full;
11151 nextzone:
11152 if (dctx->version != NULL) {
11153 dns_db_closeversion(dctx->db, &dctx->version, false);
11154 }
11155 if (dctx->db != NULL) {
11156 dns_db_detach(&dctx->db);
11157 }
11158 if (dctx->zone == NULL) {
11159 dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
11160 } else {
11161 dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
11162 }
11163 if (dctx->zone != NULL) {
11164 /* start zone dump */
11165 dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
11166 fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
11167 result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
11168 if (result != ISC_R_SUCCESS) {
11169 fprintf(dctx->fp, "; %s\n",
11170 dns_result_totext(result));
11171 goto nextzone;
11172 }
11173 dns_db_currentversion(dctx->db, &dctx->version);
11174 result = dns_master_dumptostreamasync(
11175 dctx->mctx, dctx->db, dctx->version, style,
11176 dctx->fp, dctx->task, dumpdone, dctx,
11177 &dctx->mdctx);
11178 if (result == DNS_R_CONTINUE) {
11179 return;
11180 }
11181 if (result == ISC_R_NOTIMPLEMENTED) {
11182 fprintf(dctx->fp, "; %s\n",
11183 dns_result_totext(result));
11184 result = ISC_R_SUCCESS;
11185 POST(result);
11186 goto nextzone;
11187 }
11188 if (result != ISC_R_SUCCESS) {
11189 goto cleanup;
11190 }
11191 }
11192 }
11193 if (dctx->view != NULL) {
11194 dctx->view = ISC_LIST_NEXT(dctx->view, link);
11195 if (dctx->view != NULL) {
11196 goto nextview;
11197 }
11198 }
11199 done:
11200 fprintf(dctx->fp, "; Dump complete\n");
11201 result = isc_stdio_flush(dctx->fp);
11202 if (result == ISC_R_SUCCESS) {
11203 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11204 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11205 "dumpdb complete");
11206 }
11207 cleanup:
11208 if (result != ISC_R_SUCCESS) {
11209 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11210 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11211 "dumpdb failed: %s", dns_result_totext(result));
11212 }
11213 dumpcontext_destroy(dctx);
11214 }
11215
11216 isc_result_t
named_server_dumpdb(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)11217 named_server_dumpdb(named_server_t *server, isc_lex_t *lex,
11218 isc_buffer_t **text) {
11219 struct dumpcontext *dctx = NULL;
11220 dns_view_t *view;
11221 isc_result_t result;
11222 char *ptr;
11223 const char *sep;
11224 bool found;
11225
11226 REQUIRE(text != NULL);
11227
11228 /* Skip the command name. */
11229 ptr = next_token(lex, NULL);
11230 if (ptr == NULL) {
11231 return (ISC_R_UNEXPECTEDEND);
11232 }
11233
11234 dctx = isc_mem_get(server->mctx, sizeof(*dctx));
11235
11236 dctx->mctx = server->mctx;
11237 dctx->dumpcache = true;
11238 dctx->dumpadb = true;
11239 dctx->dumpbad = true;
11240 dctx->dumpexpired = false;
11241 dctx->dumpfail = true;
11242 dctx->dumpzones = false;
11243 dctx->fp = NULL;
11244 ISC_LIST_INIT(dctx->viewlist);
11245 dctx->view = NULL;
11246 dctx->zone = NULL;
11247 dctx->cache = NULL;
11248 dctx->mdctx = NULL;
11249 dctx->db = NULL;
11250 dctx->cache = NULL;
11251 dctx->task = NULL;
11252 dctx->version = NULL;
11253 isc_task_attach(server->task, &dctx->task);
11254
11255 CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
11256 "could not open dump file", server->dumpfile);
11257
11258 ptr = next_token(lex, NULL);
11259 sep = (ptr == NULL) ? "" : ": ";
11260 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11261 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11262 "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : "");
11263
11264 if (ptr != NULL && strcmp(ptr, "-all") == 0) {
11265 /* also dump zones */
11266 dctx->dumpzones = true;
11267 ptr = next_token(lex, NULL);
11268 } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
11269 /* this is the default */
11270 ptr = next_token(lex, NULL);
11271 } else if (ptr != NULL && strcmp(ptr, "-expired") == 0) {
11272 /* this is the same as -cache but includes expired data */
11273 dctx->dumpexpired = true;
11274 ptr = next_token(lex, NULL);
11275 } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
11276 /* only dump zones, suppress caches */
11277 dctx->dumpadb = false;
11278 dctx->dumpbad = false;
11279 dctx->dumpcache = false;
11280 dctx->dumpfail = false;
11281 dctx->dumpzones = true;
11282 ptr = next_token(lex, NULL);
11283 } else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
11284 /* only dump adb, suppress other caches */
11285 dctx->dumpbad = false;
11286 dctx->dumpcache = false;
11287 dctx->dumpfail = false;
11288 ptr = next_token(lex, NULL);
11289 } else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
11290 /* only dump badcache, suppress other caches */
11291 dctx->dumpadb = false;
11292 dctx->dumpcache = false;
11293 dctx->dumpfail = false;
11294 ptr = next_token(lex, NULL);
11295 } else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
11296 /* only dump servfail cache, suppress other caches */
11297 dctx->dumpadb = false;
11298 dctx->dumpbad = false;
11299 dctx->dumpcache = false;
11300 ptr = next_token(lex, NULL);
11301 }
11302
11303 nextview:
11304 found = false;
11305 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11306 view = ISC_LIST_NEXT(view, link))
11307 {
11308 if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11309 continue;
11310 }
11311 found = true;
11312 CHECK(add_view_tolist(dctx, view));
11313 }
11314 if (ptr != NULL) {
11315 if (!found) {
11316 CHECK(putstr(text, "view '"));
11317 CHECK(putstr(text, ptr));
11318 CHECK(putstr(text, "' not found"));
11319 CHECK(putnull(text));
11320 result = ISC_R_NOTFOUND;
11321 dumpdone(dctx, result);
11322 return (result);
11323 }
11324 ptr = next_token(lex, NULL);
11325 if (ptr != NULL) {
11326 goto nextview;
11327 }
11328 }
11329 dumpdone(dctx, ISC_R_SUCCESS);
11330 return (ISC_R_SUCCESS);
11331
11332 cleanup:
11333 dumpcontext_destroy(dctx);
11334 return (result);
11335 }
11336
11337 isc_result_t
named_server_dumpsecroots(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)11338 named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex,
11339 isc_buffer_t **text) {
11340 dns_view_t *view;
11341 dns_keytable_t *secroots = NULL;
11342 dns_ntatable_t *ntatable = NULL;
11343 isc_result_t result;
11344 char *ptr;
11345 FILE *fp = NULL;
11346 isc_time_t now;
11347 char tbuf[64];
11348 unsigned int used = isc_buffer_usedlength(*text);
11349 bool first = true;
11350
11351 REQUIRE(text != NULL);
11352
11353 /* Skip the command name. */
11354 ptr = next_token(lex, text);
11355 if (ptr == NULL) {
11356 return (ISC_R_UNEXPECTEDEND);
11357 }
11358
11359 /* "-" here means print the output instead of dumping to file */
11360 ptr = next_token(lex, text);
11361 if (ptr != NULL && strcmp(ptr, "-") == 0) {
11362 ptr = next_token(lex, text);
11363 } else {
11364 result = isc_stdio_open(server->secrootsfile, "w", &fp);
11365 if (result != ISC_R_SUCCESS) {
11366 (void)putstr(text, "could not open ");
11367 (void)putstr(text, server->secrootsfile);
11368 CHECKMF(result, "could not open secroots dump file",
11369 server->secrootsfile);
11370 }
11371 }
11372
11373 TIME_NOW(&now);
11374 isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
11375 CHECK(putstr(text, "secure roots as of "));
11376 CHECK(putstr(text, tbuf));
11377 CHECK(putstr(text, ":\n"));
11378 used = isc_buffer_usedlength(*text);
11379
11380 do {
11381 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11382 view = ISC_LIST_NEXT(view, link))
11383 {
11384 if (ptr != NULL && strcmp(view->name, ptr) != 0) {
11385 continue;
11386 }
11387 if (secroots != NULL) {
11388 dns_keytable_detach(&secroots);
11389 }
11390 result = dns_view_getsecroots(view, &secroots);
11391 if (result == ISC_R_NOTFOUND) {
11392 result = ISC_R_SUCCESS;
11393 continue;
11394 }
11395 if (first || used != isc_buffer_usedlength(*text)) {
11396 CHECK(putstr(text, "\n"));
11397 first = false;
11398 }
11399 CHECK(putstr(text, " Start view "));
11400 CHECK(putstr(text, view->name));
11401 CHECK(putstr(text, "\n Secure roots:\n\n"));
11402 used = isc_buffer_usedlength(*text);
11403 CHECK(dns_keytable_totext(secroots, text));
11404
11405 if (ntatable != NULL) {
11406 dns_ntatable_detach(&ntatable);
11407 }
11408 result = dns_view_getntatable(view, &ntatable);
11409 if (result == ISC_R_NOTFOUND) {
11410 result = ISC_R_SUCCESS;
11411 continue;
11412 }
11413 if (used != isc_buffer_usedlength(*text)) {
11414 CHECK(putstr(text, "\n"));
11415 }
11416 CHECK(putstr(text, " Negative trust anchors:\n\n"));
11417 used = isc_buffer_usedlength(*text);
11418 CHECK(dns_ntatable_totext(ntatable, NULL, text));
11419 }
11420
11421 if (ptr != NULL) {
11422 ptr = next_token(lex, text);
11423 }
11424 } while (ptr != NULL);
11425
11426 cleanup:
11427 if (secroots != NULL) {
11428 dns_keytable_detach(&secroots);
11429 }
11430 if (ntatable != NULL) {
11431 dns_ntatable_detach(&ntatable);
11432 }
11433
11434 if (fp != NULL) {
11435 if (used != isc_buffer_usedlength(*text)) {
11436 (void)putstr(text, "\n");
11437 }
11438 fprintf(fp, "%.*s", (int)isc_buffer_usedlength(*text),
11439 (char *)isc_buffer_base(*text));
11440 isc_buffer_clear(*text);
11441 (void)isc_stdio_close(fp);
11442 } else if (isc_buffer_usedlength(*text) > 0) {
11443 (void)putnull(text);
11444 }
11445
11446 if (result == ISC_R_SUCCESS) {
11447 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11448 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11449 "dumpsecroots complete");
11450 } else {
11451 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11452 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11453 "dumpsecroots failed: %s",
11454 dns_result_totext(result));
11455 }
11456 return (result);
11457 }
11458
11459 isc_result_t
named_server_dumprecursing(named_server_t * server)11460 named_server_dumprecursing(named_server_t *server) {
11461 FILE *fp = NULL;
11462 dns_view_t *view;
11463 isc_result_t result;
11464
11465 CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
11466 "could not open dump file", server->recfile);
11467 fprintf(fp, ";\n; Recursing Queries\n;\n");
11468 ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
11469
11470 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11471 view = ISC_LIST_NEXT(view, link))
11472 {
11473 fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
11474 view->name);
11475 dns_resolver_dumpfetches(view->resolver, isc_statsformat_file,
11476 fp);
11477 }
11478
11479 fprintf(fp, "; Dump complete\n");
11480
11481 cleanup:
11482 if (fp != NULL) {
11483 result = isc_stdio_close(fp);
11484 }
11485 if (result == ISC_R_SUCCESS) {
11486 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11487 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11488 "dumprecursing complete");
11489 } else {
11490 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11491 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11492 "dumprecursing failed: %s",
11493 dns_result_totext(result));
11494 }
11495 return (result);
11496 }
11497
11498 isc_result_t
named_server_setdebuglevel(named_server_t * server,isc_lex_t * lex)11499 named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
11500 char *ptr;
11501 char *endp;
11502 long newlevel;
11503
11504 UNUSED(server);
11505
11506 /* Skip the command name. */
11507 ptr = next_token(lex, NULL);
11508 if (ptr == NULL) {
11509 return (ISC_R_UNEXPECTEDEND);
11510 }
11511
11512 /* Look for the new level name. */
11513 ptr = next_token(lex, NULL);
11514 if (ptr == NULL) {
11515 if (named_g_debuglevel < 99) {
11516 named_g_debuglevel++;
11517 }
11518 } else {
11519 newlevel = strtol(ptr, &endp, 10);
11520 if (*endp != '\0' || newlevel < 0 || newlevel > 99) {
11521 return (ISC_R_RANGE);
11522 }
11523 named_g_debuglevel = (unsigned int)newlevel;
11524 }
11525 isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel);
11526 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11527 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11528 "debug level is now %u", named_g_debuglevel);
11529 return (ISC_R_SUCCESS);
11530 }
11531
11532 isc_result_t
named_server_validation(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)11533 named_server_validation(named_server_t *server, isc_lex_t *lex,
11534 isc_buffer_t **text) {
11535 char *ptr;
11536 dns_view_t *view;
11537 bool changed = false;
11538 isc_result_t result;
11539 bool enable = true, set = true, first = true;
11540
11541 REQUIRE(text != NULL);
11542
11543 /* Skip the command name. */
11544 ptr = next_token(lex, text);
11545 if (ptr == NULL) {
11546 return (ISC_R_UNEXPECTEDEND);
11547 }
11548
11549 /* Find out what we are to do. */
11550 ptr = next_token(lex, text);
11551 if (ptr == NULL) {
11552 return (ISC_R_UNEXPECTEDEND);
11553 }
11554
11555 if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
11556 !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
11557 {
11558 enable = true;
11559 } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
11560 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
11561 {
11562 enable = false;
11563 } else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
11564 set = false;
11565 } else {
11566 return (DNS_R_SYNTAX);
11567 }
11568
11569 /* Look for the view name. */
11570 ptr = next_token(lex, text);
11571
11572 result = isc_task_beginexclusive(server->task);
11573 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11574 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11575 view = ISC_LIST_NEXT(view, link))
11576 {
11577 if ((ptr != NULL && strcasecmp(ptr, view->name) != 0) ||
11578 strcasecmp("_bind", view->name) == 0)
11579 {
11580 continue;
11581 }
11582
11583 if (set) {
11584 CHECK(dns_view_flushcache(view, false));
11585 view->enablevalidation = enable;
11586 changed = true;
11587 } else {
11588 if (!first) {
11589 CHECK(putstr(text, "\n"));
11590 }
11591 CHECK(putstr(text, "DNSSEC validation is "));
11592 CHECK(putstr(text, view->enablevalidation
11593 ? "enabled"
11594 : "disabled"));
11595 CHECK(putstr(text, " (view "));
11596 CHECK(putstr(text, view->name));
11597 CHECK(putstr(text, ")"));
11598 first = false;
11599 }
11600 }
11601 CHECK(putnull(text));
11602
11603 if (!set) {
11604 result = ISC_R_SUCCESS;
11605 } else if (changed) {
11606 result = ISC_R_SUCCESS;
11607 } else {
11608 result = ISC_R_FAILURE;
11609 }
11610 cleanup:
11611 isc_task_endexclusive(server->task);
11612 return (result);
11613 }
11614
11615 isc_result_t
named_server_flushcache(named_server_t * server,isc_lex_t * lex)11616 named_server_flushcache(named_server_t *server, isc_lex_t *lex) {
11617 char *ptr;
11618 dns_view_t *view;
11619 bool flushed;
11620 bool found;
11621 isc_result_t result;
11622 named_cache_t *nsc;
11623
11624 /* Skip the command name. */
11625 ptr = next_token(lex, NULL);
11626 if (ptr == NULL) {
11627 return (ISC_R_UNEXPECTEDEND);
11628 }
11629
11630 /* Look for the view name. */
11631 ptr = next_token(lex, NULL);
11632
11633 result = isc_task_beginexclusive(server->task);
11634 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11635 flushed = true;
11636 found = false;
11637
11638 /*
11639 * Flushing a cache is tricky when caches are shared by multiple views.
11640 * We first identify which caches should be flushed in the local cache
11641 * list, flush these caches, and then update other views that refer to
11642 * the flushed cache DB.
11643 */
11644 if (ptr != NULL) {
11645 /*
11646 * Mark caches that need to be flushed. This is an O(#view^2)
11647 * operation in the very worst case, but should be normally
11648 * much more lightweight because only a few (most typically just
11649 * one) views will match.
11650 */
11651 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11652 view = ISC_LIST_NEXT(view, link))
11653 {
11654 if (strcasecmp(ptr, view->name) != 0) {
11655 continue;
11656 }
11657 found = true;
11658 for (nsc = ISC_LIST_HEAD(server->cachelist);
11659 nsc != NULL; nsc = ISC_LIST_NEXT(nsc, link))
11660 {
11661 if (nsc->cache == view->cache) {
11662 break;
11663 }
11664 }
11665 INSIST(nsc != NULL);
11666 nsc->needflush = true;
11667 }
11668 } else {
11669 found = true;
11670 }
11671
11672 /* Perform flush */
11673 for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
11674 nsc = ISC_LIST_NEXT(nsc, link))
11675 {
11676 if (ptr != NULL && !nsc->needflush) {
11677 continue;
11678 }
11679 nsc->needflush = true;
11680 result = dns_view_flushcache(nsc->primaryview, false);
11681 if (result != ISC_R_SUCCESS) {
11682 flushed = false;
11683 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11684 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11685 "flushing cache in view '%s' failed: %s",
11686 nsc->primaryview->name,
11687 isc_result_totext(result));
11688 }
11689 }
11690
11691 /*
11692 * Fix up views that share a flushed cache: let the views update the
11693 * cache DB they're referring to. This could also be an expensive
11694 * operation, but should typically be marginal: the inner loop is only
11695 * necessary for views that share a cache, and if there are many such
11696 * views the number of shared cache should normally be small.
11697 * A worst case is that we have n views and n/2 caches, each shared by
11698 * two views. Then this will be a O(n^2/4) operation.
11699 */
11700 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11701 view = ISC_LIST_NEXT(view, link))
11702 {
11703 if (!dns_view_iscacheshared(view)) {
11704 continue;
11705 }
11706 for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
11707 nsc = ISC_LIST_NEXT(nsc, link))
11708 {
11709 if (!nsc->needflush || nsc->cache != view->cache) {
11710 continue;
11711 }
11712 result = dns_view_flushcache(view, true);
11713 if (result != ISC_R_SUCCESS) {
11714 flushed = false;
11715 isc_log_write(
11716 named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11717 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11718 "fixing cache in view '%s' "
11719 "failed: %s",
11720 view->name, isc_result_totext(result));
11721 }
11722 }
11723 }
11724
11725 /* Cleanup the cache list. */
11726 for (nsc = ISC_LIST_HEAD(server->cachelist); nsc != NULL;
11727 nsc = ISC_LIST_NEXT(nsc, link))
11728 {
11729 nsc->needflush = false;
11730 }
11731
11732 if (flushed && found) {
11733 if (ptr != NULL) {
11734 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11735 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11736 "flushing cache in view '%s' succeeded",
11737 ptr);
11738 } else {
11739 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11740 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11741 "flushing caches in all views succeeded");
11742 }
11743 result = ISC_R_SUCCESS;
11744 } else {
11745 if (!found) {
11746 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11747 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11748 "flushing cache in view '%s' failed: "
11749 "view not found",
11750 ptr);
11751 result = ISC_R_NOTFOUND;
11752 } else {
11753 result = ISC_R_FAILURE;
11754 }
11755 }
11756 isc_task_endexclusive(server->task);
11757 return (result);
11758 }
11759
11760 isc_result_t
named_server_flushnode(named_server_t * server,isc_lex_t * lex,bool tree)11761 named_server_flushnode(named_server_t *server, isc_lex_t *lex, bool tree) {
11762 char *ptr, *viewname;
11763 char target[DNS_NAME_FORMATSIZE];
11764 dns_view_t *view;
11765 bool flushed;
11766 bool found;
11767 isc_result_t result;
11768 isc_buffer_t b;
11769 dns_fixedname_t fixed;
11770 dns_name_t *name;
11771
11772 /* Skip the command name. */
11773 ptr = next_token(lex, NULL);
11774 if (ptr == NULL) {
11775 return (ISC_R_UNEXPECTEDEND);
11776 }
11777
11778 /* Find the domain name to flush. */
11779 ptr = next_token(lex, NULL);
11780 if (ptr == NULL) {
11781 return (ISC_R_UNEXPECTEDEND);
11782 }
11783
11784 strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
11785 isc_buffer_constinit(&b, target, strlen(target));
11786 isc_buffer_add(&b, strlen(target));
11787 name = dns_fixedname_initname(&fixed);
11788 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
11789 if (result != ISC_R_SUCCESS) {
11790 return (result);
11791 }
11792
11793 /* Look for the view name. */
11794 viewname = next_token(lex, NULL);
11795
11796 result = isc_task_beginexclusive(server->task);
11797 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11798 flushed = true;
11799 found = false;
11800 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
11801 view = ISC_LIST_NEXT(view, link))
11802 {
11803 if (viewname != NULL && strcasecmp(viewname, view->name) != 0) {
11804 continue;
11805 }
11806 found = true;
11807 /*
11808 * It's a little inefficient to try flushing name for all views
11809 * if some of the views share a single cache. But since the
11810 * operation is lightweight we prefer simplicity here.
11811 */
11812 result = dns_view_flushnode(view, name, tree);
11813 if (result != ISC_R_SUCCESS) {
11814 flushed = false;
11815 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11816 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11817 "flushing %s '%s' in cache view '%s' "
11818 "failed: %s",
11819 tree ? "tree" : "name", target,
11820 view->name, isc_result_totext(result));
11821 }
11822 }
11823 if (flushed && found) {
11824 if (viewname != NULL) {
11825 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11826 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11827 "flushing %s '%s' in cache view '%s' "
11828 "succeeded",
11829 tree ? "tree" : "name", target, viewname);
11830 } else {
11831 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11832 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11833 "flushing %s '%s' in all cache views "
11834 "succeeded",
11835 tree ? "tree" : "name", target);
11836 }
11837 result = ISC_R_SUCCESS;
11838 } else {
11839 if (!found) {
11840 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11841 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11842 "flushing %s '%s' in cache view '%s' "
11843 "failed: view not found",
11844 tree ? "tree" : "name", target, viewname);
11845 }
11846 result = ISC_R_FAILURE;
11847 }
11848 isc_task_endexclusive(server->task);
11849 return (result);
11850 }
11851
11852 isc_result_t
named_server_status(named_server_t * server,isc_buffer_t ** text)11853 named_server_status(named_server_t *server, isc_buffer_t **text) {
11854 isc_result_t result;
11855 unsigned int zonecount, xferrunning, xferdeferred, soaqueries;
11856 unsigned int automatic;
11857 const char *ob = "", *cb = "", *alt = "";
11858 char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
11859 char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
11860 char line[1024], hostname[256];
11861 named_reload_t reload_status;
11862
11863 REQUIRE(text != NULL);
11864
11865 if (named_g_server->version_set) {
11866 ob = " (";
11867 cb = ")";
11868 if (named_g_server->version == NULL) {
11869 alt = "version.bind/txt/ch disabled";
11870 } else {
11871 alt = named_g_server->version;
11872 }
11873 }
11874 zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
11875 xferrunning = dns_zonemgr_getcount(server->zonemgr,
11876 DNS_ZONESTATE_XFERRUNNING);
11877 xferdeferred = dns_zonemgr_getcount(server->zonemgr,
11878 DNS_ZONESTATE_XFERDEFERRED);
11879 soaqueries = dns_zonemgr_getcount(server->zonemgr,
11880 DNS_ZONESTATE_SOAQUERY);
11881 automatic = dns_zonemgr_getcount(server->zonemgr,
11882 DNS_ZONESTATE_AUTOMATIC);
11883
11884 isc_time_formathttptimestamp(&named_g_boottime, boottime,
11885 sizeof(boottime));
11886 isc_time_formathttptimestamp(&named_g_configtime, configtime,
11887 sizeof(configtime));
11888
11889 snprintf(line, sizeof(line), "version: %s %s%s%s <id:%s>%s%s%s\n",
11890 named_g_product, named_g_version,
11891 (*named_g_description != '\0') ? " " : "", named_g_description,
11892 named_g_srcid, ob, alt, cb);
11893 CHECK(putstr(text, line));
11894
11895 result = named_os_gethostname(hostname, sizeof(hostname));
11896 if (result != ISC_R_SUCCESS) {
11897 strlcpy(hostname, "localhost", sizeof(hostname));
11898 }
11899 snprintf(line, sizeof(line), "running on %s: %s\n", hostname,
11900 named_os_uname());
11901 CHECK(putstr(text, line));
11902
11903 snprintf(line, sizeof(line), "boot time: %s\n", boottime);
11904 CHECK(putstr(text, line));
11905
11906 snprintf(line, sizeof(line), "last configured: %s\n", configtime);
11907 CHECK(putstr(text, line));
11908
11909 if (named_g_chrootdir != NULL) {
11910 snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n",
11911 named_g_conffile, named_g_chrootdir, named_g_conffile);
11912 } else {
11913 snprintf(line, sizeof(line), "configuration file: %s\n",
11914 named_g_conffile);
11915 }
11916 CHECK(putstr(text, line));
11917
11918 snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected);
11919 CHECK(putstr(text, line));
11920
11921 snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
11922 CHECK(putstr(text, line));
11923
11924 snprintf(line, sizeof(line), "UDP listeners per interface: %u\n",
11925 named_g_udpdisp);
11926 CHECK(putstr(text, line));
11927
11928 snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
11929 zonecount, automatic);
11930 CHECK(putstr(text, line));
11931
11932 snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel);
11933 CHECK(putstr(text, line));
11934
11935 snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
11936 CHECK(putstr(text, line));
11937
11938 snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
11939 CHECK(putstr(text, line));
11940
11941 snprintf(line, sizeof(line), "soa queries in progress: %u\n",
11942 soaqueries);
11943 CHECK(putstr(text, line));
11944
11945 snprintf(line, sizeof(line), "query logging is %s\n",
11946 ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES)
11947 ? "ON"
11948 : "OFF");
11949 CHECK(putstr(text, line));
11950
11951 snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
11952 isc_quota_getused(&server->sctx->recursionquota),
11953 isc_quota_getsoft(&server->sctx->recursionquota),
11954 isc_quota_getmax(&server->sctx->recursionquota));
11955 CHECK(putstr(text, line));
11956
11957 snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
11958 isc_quota_getused(&server->sctx->tcpquota),
11959 isc_quota_getmax(&server->sctx->tcpquota));
11960 CHECK(putstr(text, line));
11961
11962 snprintf(line, sizeof(line), "TCP high-water: %u\n",
11963 (unsigned)ns_stats_get_counter(server->sctx->nsstats,
11964 ns_statscounter_tcphighwater));
11965 CHECK(putstr(text, line));
11966
11967 reload_status = atomic_load(&server->reload_status);
11968 if (reload_status != NAMED_RELOAD_DONE) {
11969 snprintf(line, sizeof(line), "reload/reconfig %s\n",
11970 (reload_status == NAMED_RELOAD_FAILED
11971 ? "failed"
11972 : "in progress"));
11973 CHECK(putstr(text, line));
11974 }
11975
11976 CHECK(putstr(text, "server is up and running"));
11977 CHECK(putnull(text));
11978
11979 return (ISC_R_SUCCESS);
11980 cleanup:
11981 return (result);
11982 }
11983
11984 isc_result_t
named_server_testgen(isc_lex_t * lex,isc_buffer_t ** text)11985 named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) {
11986 isc_result_t result;
11987 char *ptr;
11988 unsigned long count;
11989 unsigned long i;
11990 const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
11991
11992 REQUIRE(text != NULL);
11993
11994 /* Skip the command name. */
11995 ptr = next_token(lex, text);
11996 if (ptr == NULL) {
11997 return (ISC_R_UNEXPECTEDEND);
11998 }
11999
12000 ptr = next_token(lex, text);
12001 if (ptr == NULL) {
12002 count = 26;
12003 } else {
12004 count = strtoul(ptr, NULL, 10);
12005 }
12006
12007 CHECK(isc_buffer_reserve(text, count));
12008 for (i = 0; i < count; i++) {
12009 CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
12010 }
12011
12012 CHECK(putnull(text));
12013
12014 cleanup:
12015 return (result);
12016 }
12017
12018 static isc_result_t
delete_keynames(dns_tsig_keyring_t * ring,char * target,unsigned int * foundkeys)12019 delete_keynames(dns_tsig_keyring_t *ring, char *target,
12020 unsigned int *foundkeys) {
12021 char namestr[DNS_NAME_FORMATSIZE];
12022 isc_result_t result;
12023 dns_rbtnodechain_t chain;
12024 dns_name_t foundname;
12025 dns_fixedname_t fixedorigin;
12026 dns_name_t *origin;
12027 dns_rbtnode_t *node;
12028 dns_tsigkey_t *tkey;
12029
12030 dns_name_init(&foundname, NULL);
12031 origin = dns_fixedname_initname(&fixedorigin);
12032
12033 again:
12034 dns_rbtnodechain_init(&chain);
12035 result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12036 if (result == ISC_R_NOTFOUND) {
12037 dns_rbtnodechain_invalidate(&chain);
12038 return (ISC_R_SUCCESS);
12039 }
12040 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12041 dns_rbtnodechain_invalidate(&chain);
12042 return (result);
12043 }
12044
12045 for (;;) {
12046 node = NULL;
12047 dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12048 tkey = node->data;
12049
12050 if (tkey != NULL) {
12051 if (!tkey->generated) {
12052 goto nextkey;
12053 }
12054
12055 dns_name_format(&tkey->name, namestr, sizeof(namestr));
12056 if (strcmp(namestr, target) == 0) {
12057 (*foundkeys)++;
12058 dns_rbtnodechain_invalidate(&chain);
12059 (void)dns_rbt_deletename(ring->keys,
12060 &tkey->name, false);
12061 goto again;
12062 }
12063 }
12064
12065 nextkey:
12066 result = dns_rbtnodechain_next(&chain, &foundname, origin);
12067 if (result == ISC_R_NOMORE) {
12068 break;
12069 }
12070 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12071 dns_rbtnodechain_invalidate(&chain);
12072 return (result);
12073 }
12074 }
12075
12076 return (ISC_R_SUCCESS);
12077 }
12078
12079 isc_result_t
named_server_tsigdelete(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)12080 named_server_tsigdelete(named_server_t *server, isc_lex_t *lex,
12081 isc_buffer_t **text) {
12082 isc_result_t result;
12083 dns_view_t *view;
12084 unsigned int foundkeys = 0;
12085 char *ptr, *viewname;
12086 char target[DNS_NAME_FORMATSIZE];
12087 char fbuf[16];
12088
12089 REQUIRE(text != NULL);
12090
12091 (void)next_token(lex, text); /* skip command name */
12092
12093 ptr = next_token(lex, text);
12094 if (ptr == NULL) {
12095 return (ISC_R_UNEXPECTEDEND);
12096 }
12097 strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
12098
12099 viewname = next_token(lex, text);
12100
12101 result = isc_task_beginexclusive(server->task);
12102 RUNTIME_CHECK(result == ISC_R_SUCCESS);
12103 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12104 view = ISC_LIST_NEXT(view, link))
12105 {
12106 if (viewname == NULL || strcmp(view->name, viewname) == 0) {
12107 RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
12108 result = delete_keynames(view->dynamickeys, target,
12109 &foundkeys);
12110 RWUNLOCK(&view->dynamickeys->lock,
12111 isc_rwlocktype_write);
12112 if (result != ISC_R_SUCCESS) {
12113 isc_task_endexclusive(server->task);
12114 return (result);
12115 }
12116 }
12117 }
12118 isc_task_endexclusive(server->task);
12119
12120 snprintf(fbuf, sizeof(fbuf), "%u", foundkeys);
12121
12122 CHECK(putstr(text, fbuf));
12123 CHECK(putstr(text, " tsig keys deleted."));
12124 CHECK(putnull(text));
12125
12126 cleanup:
12127 return (result);
12128 }
12129
12130 static isc_result_t
list_keynames(dns_view_t * view,dns_tsig_keyring_t * ring,isc_buffer_t ** text,unsigned int * foundkeys)12131 list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t **text,
12132 unsigned int *foundkeys) {
12133 char namestr[DNS_NAME_FORMATSIZE];
12134 char creatorstr[DNS_NAME_FORMATSIZE];
12135 isc_result_t result;
12136 dns_rbtnodechain_t chain;
12137 dns_name_t foundname;
12138 dns_fixedname_t fixedorigin;
12139 dns_name_t *origin;
12140 dns_rbtnode_t *node;
12141 dns_tsigkey_t *tkey;
12142 const char *viewname;
12143
12144 if (view != NULL) {
12145 viewname = view->name;
12146 } else {
12147 viewname = "(global)";
12148 }
12149
12150 dns_name_init(&foundname, NULL);
12151 origin = dns_fixedname_initname(&fixedorigin);
12152 dns_rbtnodechain_init(&chain);
12153 result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
12154 if (result == ISC_R_NOTFOUND) {
12155 dns_rbtnodechain_invalidate(&chain);
12156 return (ISC_R_SUCCESS);
12157 }
12158 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
12159 dns_rbtnodechain_invalidate(&chain);
12160 return (result);
12161 }
12162
12163 for (;;) {
12164 node = NULL;
12165 dns_rbtnodechain_current(&chain, &foundname, origin, &node);
12166 tkey = node->data;
12167
12168 if (tkey != NULL) {
12169 dns_name_format(&tkey->name, namestr, sizeof(namestr));
12170 if (tkey->generated) {
12171 dns_name_format(tkey->creator, creatorstr,
12172 sizeof(creatorstr));
12173 if (*foundkeys != 0) {
12174 CHECK(putstr(text, "\n"));
12175 }
12176 CHECK(putstr(text, "view \""));
12177 CHECK(putstr(text, viewname));
12178 CHECK(putstr(text, "\"; type \"dynamic\"; key "
12179 "\""));
12180 CHECK(putstr(text, namestr));
12181 CHECK(putstr(text, "\"; creator \""));
12182 CHECK(putstr(text, creatorstr));
12183 CHECK(putstr(text, "\";"));
12184 } else {
12185 if (*foundkeys != 0) {
12186 CHECK(putstr(text, "\n"));
12187 }
12188 CHECK(putstr(text, "view \""));
12189 CHECK(putstr(text, viewname));
12190 CHECK(putstr(text, "\"; type \"static\"; key "
12191 "\""));
12192 CHECK(putstr(text, namestr));
12193 CHECK(putstr(text, "\";"));
12194 }
12195 (*foundkeys)++;
12196 }
12197 result = dns_rbtnodechain_next(&chain, &foundname, origin);
12198 if (result == ISC_R_NOMORE || result == DNS_R_NEWORIGIN) {
12199 break;
12200 }
12201 }
12202
12203 return (ISC_R_SUCCESS);
12204 cleanup:
12205 dns_rbtnodechain_invalidate(&chain);
12206 return (result);
12207 }
12208
12209 isc_result_t
named_server_tsiglist(named_server_t * server,isc_buffer_t ** text)12210 named_server_tsiglist(named_server_t *server, isc_buffer_t **text) {
12211 isc_result_t result = ISC_R_SUCCESS;
12212 dns_view_t *view;
12213 unsigned int foundkeys = 0;
12214
12215 REQUIRE(text != NULL);
12216
12217 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12218 view = ISC_LIST_NEXT(view, link))
12219 {
12220 RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12221 result = list_keynames(view, view->statickeys, text,
12222 &foundkeys);
12223 RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
12224 if (result != ISC_R_SUCCESS) {
12225 return (result);
12226 }
12227 RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12228 result = list_keynames(view, view->dynamickeys, text,
12229 &foundkeys);
12230 RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
12231 if (result != ISC_R_SUCCESS) {
12232 return (result);
12233 }
12234 }
12235
12236 if (foundkeys == 0) {
12237 CHECK(putstr(text, "no tsig keys found."));
12238 }
12239
12240 if (isc_buffer_usedlength(*text) > 0) {
12241 CHECK(putnull(text));
12242 }
12243
12244 cleanup:
12245 return (result);
12246 }
12247
12248 /*
12249 * Act on a "sign" or "loadkeys" command from the command channel.
12250 */
12251 isc_result_t
named_server_rekey(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)12252 named_server_rekey(named_server_t *server, isc_lex_t *lex,
12253 isc_buffer_t **text) {
12254 isc_result_t result;
12255 dns_zone_t *zone = NULL;
12256 dns_zonetype_t type;
12257 uint16_t keyopts;
12258 bool fullsign = false;
12259 char *ptr;
12260
12261 REQUIRE(text != NULL);
12262
12263 ptr = next_token(lex, text);
12264 if (ptr == NULL) {
12265 return (ISC_R_UNEXPECTEDEND);
12266 }
12267
12268 if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0) {
12269 fullsign = true;
12270 }
12271
12272 REQUIRE(text != NULL);
12273
12274 result = zone_from_args(server, lex, NULL, &zone, NULL, text, false);
12275 if (result != ISC_R_SUCCESS) {
12276 return (result);
12277 }
12278 if (zone == NULL) {
12279 return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */
12280 }
12281
12282 type = dns_zone_gettype(zone);
12283 if (type != dns_zone_primary) {
12284 dns_zone_detach(&zone);
12285 return (DNS_R_NOTMASTER);
12286 }
12287
12288 keyopts = dns_zone_getkeyopts(zone);
12289
12290 /*
12291 * "rndc loadkeys" requires "auto-dnssec maintain"
12292 * or a "dnssec-policy".
12293 */
12294 if ((keyopts & DNS_ZONEKEY_ALLOW) == 0) {
12295 result = ISC_R_NOPERM;
12296 } else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) {
12297 result = ISC_R_NOPERM;
12298 } else {
12299 dns_zone_rekey(zone, fullsign);
12300 }
12301
12302 dns_zone_detach(&zone);
12303 return (result);
12304 }
12305
12306 /*
12307 * Act on a "sync" command from the command channel.
12308 */
12309 static isc_result_t
synczone(dns_zone_t * zone,void * uap)12310 synczone(dns_zone_t *zone, void *uap) {
12311 bool cleanup = *(bool *)uap;
12312 isc_result_t result;
12313 dns_zone_t *raw = NULL;
12314 char *journal;
12315
12316 dns_zone_getraw(zone, &raw);
12317 if (raw != NULL) {
12318 synczone(raw, uap);
12319 dns_zone_detach(&raw);
12320 }
12321
12322 result = dns_zone_flush(zone);
12323 if (result != ISC_R_SUCCESS) {
12324 cleanup = false;
12325 }
12326 if (cleanup) {
12327 journal = dns_zone_getjournal(zone);
12328 if (journal != NULL) {
12329 (void)isc_file_remove(journal);
12330 }
12331 }
12332
12333 return (result);
12334 }
12335
12336 isc_result_t
named_server_sync(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)12337 named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
12338 isc_result_t result, tresult;
12339 dns_view_t *view;
12340 dns_zone_t *zone = NULL;
12341 char classstr[DNS_RDATACLASS_FORMATSIZE];
12342 char zonename[DNS_NAME_FORMATSIZE];
12343 const char *vname, *sep, *arg;
12344 bool cleanup = false;
12345
12346 REQUIRE(text != NULL);
12347
12348 (void)next_token(lex, text);
12349
12350 arg = next_token(lex, text);
12351 if (arg != NULL &&
12352 (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0))
12353 {
12354 cleanup = true;
12355 arg = next_token(lex, text);
12356 }
12357
12358 REQUIRE(text != NULL);
12359
12360 result = zone_from_args(server, lex, arg, &zone, NULL, text, false);
12361 if (result != ISC_R_SUCCESS) {
12362 return (result);
12363 }
12364
12365 if (zone == NULL) {
12366 result = isc_task_beginexclusive(server->task);
12367 RUNTIME_CHECK(result == ISC_R_SUCCESS);
12368 tresult = ISC_R_SUCCESS;
12369 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12370 view = ISC_LIST_NEXT(view, link))
12371 {
12372 result = dns_zt_apply(view->zonetable,
12373 isc_rwlocktype_none, false, NULL,
12374 synczone, &cleanup);
12375 if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12376 {
12377 tresult = result;
12378 }
12379 }
12380 isc_task_endexclusive(server->task);
12381 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12382 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12383 "dumping all zones%s: %s",
12384 cleanup ? ", removing journal files" : "",
12385 isc_result_totext(result));
12386 return (tresult);
12387 }
12388
12389 result = isc_task_beginexclusive(server->task);
12390 RUNTIME_CHECK(result == ISC_R_SUCCESS);
12391 result = synczone(zone, &cleanup);
12392 isc_task_endexclusive(server->task);
12393
12394 view = dns_zone_getview(zone);
12395 if (strcmp(view->name, "_default") == 0 ||
12396 strcmp(view->name, "_bind") == 0)
12397 {
12398 vname = "";
12399 sep = "";
12400 } else {
12401 vname = view->name;
12402 sep = " ";
12403 }
12404 dns_rdataclass_format(dns_zone_getclass(zone), classstr,
12405 sizeof(classstr));
12406 dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
12407 isc_log_write(
12408 named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12409 ISC_LOG_INFO, "sync: dumping zone '%s/%s'%s%s%s: %s", zonename,
12410 classstr, sep, vname, cleanup ? ", removing journal file" : "",
12411 isc_result_totext(result));
12412 dns_zone_detach(&zone);
12413 return (result);
12414 }
12415
12416 /*
12417 * Act on a "freeze" or "thaw" command from the command channel.
12418 */
12419 isc_result_t
named_server_freeze(named_server_t * server,bool freeze,isc_lex_t * lex,isc_buffer_t ** text)12420 named_server_freeze(named_server_t *server, bool freeze, isc_lex_t *lex,
12421 isc_buffer_t **text) {
12422 isc_result_t result, tresult;
12423 dns_zone_t *mayberaw = NULL, *raw = NULL;
12424 dns_zonetype_t type;
12425 char classstr[DNS_RDATACLASS_FORMATSIZE];
12426 char zonename[DNS_NAME_FORMATSIZE];
12427 dns_view_t *view;
12428 const char *vname, *sep;
12429 bool frozen;
12430 const char *msg = NULL;
12431
12432 REQUIRE(text != NULL);
12433
12434 result = zone_from_args(server, lex, NULL, &mayberaw, NULL, text, true);
12435 if (result != ISC_R_SUCCESS) {
12436 return (result);
12437 }
12438 if (mayberaw == NULL) {
12439 result = isc_task_beginexclusive(server->task);
12440 RUNTIME_CHECK(result == ISC_R_SUCCESS);
12441 tresult = ISC_R_SUCCESS;
12442 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
12443 view = ISC_LIST_NEXT(view, link))
12444 {
12445 result = dns_view_freezezones(view, freeze);
12446 if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
12447 {
12448 tresult = result;
12449 }
12450 }
12451 isc_task_endexclusive(server->task);
12452 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12453 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12454 "%s all zones: %s",
12455 freeze ? "freezing" : "thawing",
12456 isc_result_totext(tresult));
12457 return (tresult);
12458 }
12459 dns_zone_getraw(mayberaw, &raw);
12460 if (raw != NULL) {
12461 dns_zone_detach(&mayberaw);
12462 dns_zone_attach(raw, &mayberaw);
12463 dns_zone_detach(&raw);
12464 }
12465 type = dns_zone_gettype(mayberaw);
12466 if (type != dns_zone_primary) {
12467 dns_zone_detach(&mayberaw);
12468 return (DNS_R_NOTMASTER);
12469 }
12470
12471 if (freeze && !dns_zone_isdynamic(mayberaw, true)) {
12472 dns_zone_detach(&mayberaw);
12473 return (DNS_R_NOTDYNAMIC);
12474 }
12475
12476 result = isc_task_beginexclusive(server->task);
12477 RUNTIME_CHECK(result == ISC_R_SUCCESS);
12478 frozen = dns_zone_getupdatedisabled(mayberaw);
12479 if (freeze) {
12480 if (frozen) {
12481 msg = "WARNING: The zone was already frozen.\n"
12482 "Someone else may be editing it or "
12483 "it may still be re-loading.";
12484 result = DNS_R_FROZEN;
12485 }
12486 if (result == ISC_R_SUCCESS) {
12487 result = dns_zone_flush(mayberaw);
12488 if (result != ISC_R_SUCCESS) {
12489 msg = "Flushing the zone updates to "
12490 "disk failed.";
12491 }
12492 }
12493 if (result == ISC_R_SUCCESS) {
12494 dns_zone_setupdatedisabled(mayberaw, freeze);
12495 }
12496 } else {
12497 if (frozen) {
12498 result = dns_zone_loadandthaw(mayberaw);
12499 switch (result) {
12500 case ISC_R_SUCCESS:
12501 case DNS_R_UPTODATE:
12502 msg = "The zone reload and thaw was "
12503 "successful.";
12504 result = ISC_R_SUCCESS;
12505 break;
12506 case DNS_R_CONTINUE:
12507 msg = "A zone reload and thaw was started.\n"
12508 "Check the logs to see the result.";
12509 result = ISC_R_SUCCESS;
12510 break;
12511 }
12512 }
12513 }
12514 isc_task_endexclusive(server->task);
12515
12516 if (msg != NULL) {
12517 (void)putstr(text, msg);
12518 (void)putnull(text);
12519 }
12520
12521 view = dns_zone_getview(mayberaw);
12522 if (strcmp(view->name, "_default") == 0 ||
12523 strcmp(view->name, "_bind") == 0)
12524 {
12525 vname = "";
12526 sep = "";
12527 } else {
12528 vname = view->name;
12529 sep = " ";
12530 }
12531 dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr,
12532 sizeof(classstr));
12533 dns_name_format(dns_zone_getorigin(mayberaw), zonename,
12534 sizeof(zonename));
12535 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12536 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12537 "%s zone '%s/%s'%s%s: %s",
12538 freeze ? "freezing" : "thawing", zonename, classstr, sep,
12539 vname, isc_result_totext(result));
12540 dns_zone_detach(&mayberaw);
12541 return (result);
12542 }
12543
12544 #ifdef HAVE_LIBSCF
12545 /*
12546 * This function adds a message for rndc to echo if named
12547 * is managed by smf and is also running chroot.
12548 */
12549 isc_result_t
named_smf_add_message(isc_buffer_t ** text)12550 named_smf_add_message(isc_buffer_t **text) {
12551 REQUIRE(text != NULL);
12552
12553 return (putstr(text, "use svcadm(1M) to manage named"));
12554 }
12555 #endif /* HAVE_LIBSCF */
12556
12557 #ifndef HAVE_LMDB
12558
12559 /*
12560 * Emit a comment at the top of the nzf file containing the viewname
12561 * Expects the fp to already be open for writing
12562 */
12563 #define HEADER1 "# New zone file for view: "
12564 #define HEADER2 \
12565 "\n# This file contains configuration for zones added by\n" \
12566 "# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
12567 static isc_result_t
add_comment(FILE * fp,const char * viewname)12568 add_comment(FILE *fp, const char *viewname) {
12569 isc_result_t result;
12570 CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
12571 CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
12572 CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
12573 cleanup:
12574 return (result);
12575 }
12576
12577 static void
dumpzone(void * arg,const char * buf,int len)12578 dumpzone(void *arg, const char *buf, int len) {
12579 FILE *fp = arg;
12580
12581 (void)isc_stdio_write(buf, len, 1, fp, NULL);
12582 }
12583
12584 static isc_result_t
nzf_append(dns_view_t * view,const cfg_obj_t * zconfig)12585 nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
12586 isc_result_t result;
12587 off_t offset;
12588 FILE *fp = NULL;
12589 bool offsetok = false;
12590
12591 LOCK(&view->new_zone_lock);
12592
12593 CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
12594 CHECK(isc_stdio_seek(fp, 0, SEEK_END));
12595
12596 CHECK(isc_stdio_tell(fp, &offset));
12597 offsetok = true;
12598 if (offset == 0) {
12599 CHECK(add_comment(fp, view->name));
12600 }
12601
12602 CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
12603 cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
12604 CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
12605 CHECK(isc_stdio_flush(fp));
12606 result = isc_stdio_close(fp);
12607 fp = NULL;
12608
12609 cleanup:
12610 if (fp != NULL) {
12611 (void)isc_stdio_close(fp);
12612 if (offsetok) {
12613 isc_result_t result2;
12614
12615 result2 = isc_file_truncate(view->new_zone_file,
12616 offset);
12617 if (result2 != ISC_R_SUCCESS) {
12618 isc_log_write(
12619 named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12620 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12621 "Error truncating NZF file '%s' "
12622 "during rollback from append: "
12623 "%s",
12624 view->new_zone_file,
12625 isc_result_totext(result2));
12626 }
12627 }
12628 }
12629 UNLOCK(&view->new_zone_lock);
12630 return (result);
12631 }
12632
12633 static isc_result_t
nzf_writeconf(const cfg_obj_t * config,dns_view_t * view)12634 nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
12635 const cfg_obj_t *zl = NULL;
12636 cfg_list_t *list;
12637 const cfg_listelt_t *elt;
12638
12639 FILE *fp = NULL;
12640 char tmp[1024];
12641 isc_result_t result;
12642
12643 result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX", tmp,
12644 sizeof(tmp));
12645 if (result == ISC_R_SUCCESS) {
12646 result = isc_file_openunique(tmp, &fp);
12647 }
12648 if (result != ISC_R_SUCCESS) {
12649 return (result);
12650 }
12651
12652 cfg_map_get(config, "zone", &zl);
12653 if (!cfg_obj_islist(zl)) {
12654 CHECK(ISC_R_FAILURE);
12655 }
12656
12657 DE_CONST(&zl->value.list, list);
12658
12659 CHECK(add_comment(fp, view->name)); /* force a comment */
12660
12661 for (elt = ISC_LIST_HEAD(*list); elt != NULL;
12662 elt = ISC_LIST_NEXT(elt, link))
12663 {
12664 const cfg_obj_t *zconfig = cfg_listelt_value(elt);
12665
12666 CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
12667 cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
12668 CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
12669 }
12670
12671 CHECK(isc_stdio_flush(fp));
12672 result = isc_stdio_close(fp);
12673 fp = NULL;
12674 if (result != ISC_R_SUCCESS) {
12675 goto cleanup;
12676 }
12677 CHECK(isc_file_rename(tmp, view->new_zone_file));
12678 return (result);
12679
12680 cleanup:
12681 if (fp != NULL) {
12682 (void)isc_stdio_close(fp);
12683 }
12684 (void)isc_file_remove(tmp);
12685 return (result);
12686 }
12687
12688 #else /* HAVE_LMDB */
12689
12690 static void
nzd_setkey(MDB_val * key,dns_name_t * name,char * namebuf,size_t buflen)12691 nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
12692 dns_fixedname_t fixed;
12693
12694 dns_fixedname_init(&fixed);
12695 dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
12696 dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
12697
12698 key->mv_data = namebuf;
12699 key->mv_size = strlen(namebuf);
12700 }
12701
12702 static void
dumpzone(void * arg,const char * buf,int len)12703 dumpzone(void *arg, const char *buf, int len) {
12704 ns_dzarg_t *dzarg = arg;
12705 isc_result_t result;
12706
12707 REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
12708
12709 result = putmem(dzarg->text, buf, len);
12710 if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
12711 dzarg->result = result;
12712 }
12713 }
12714
12715 static isc_result_t
nzd_save(MDB_txn ** txnp,MDB_dbi dbi,dns_zone_t * zone,const cfg_obj_t * zconfig)12716 nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
12717 const cfg_obj_t *zconfig) {
12718 isc_result_t result;
12719 int status;
12720 dns_view_t *view;
12721 bool commit = false;
12722 isc_buffer_t *text = NULL;
12723 char namebuf[1024];
12724 MDB_val key, data;
12725 ns_dzarg_t dzarg;
12726
12727 view = dns_zone_getview(zone);
12728
12729 nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
12730
12731 if (zconfig == NULL) {
12732 /* We're deleting the zone from the database */
12733 status = mdb_del(*txnp, dbi, &key, NULL);
12734 if (status != MDB_SUCCESS && status != MDB_NOTFOUND) {
12735 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12736 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12737 "Error deleting zone %s "
12738 "from NZD database: %s",
12739 namebuf, mdb_strerror(status));
12740 result = ISC_R_FAILURE;
12741 goto cleanup;
12742 } else if (status != MDB_NOTFOUND) {
12743 commit = true;
12744 }
12745 } else {
12746 /* We're creating or overwriting the zone */
12747 const cfg_obj_t *zoptions;
12748
12749 isc_buffer_allocate(view->mctx, &text, 256);
12750
12751 zoptions = cfg_tuple_get(zconfig, "options");
12752 if (zoptions == NULL) {
12753 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12754 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12755 "Unable to get options from config in "
12756 "nzd_save()");
12757 result = ISC_R_FAILURE;
12758 goto cleanup;
12759 }
12760
12761 dzarg.magic = DZARG_MAGIC;
12762 dzarg.text = &text;
12763 dzarg.result = ISC_R_SUCCESS;
12764 cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
12765 if (dzarg.result != ISC_R_SUCCESS) {
12766 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12767 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12768 "Error writing zone config to "
12769 "buffer in nzd_save(): %s",
12770 isc_result_totext(dzarg.result));
12771 result = dzarg.result;
12772 goto cleanup;
12773 }
12774
12775 data.mv_data = isc_buffer_base(text);
12776 data.mv_size = isc_buffer_usedlength(text);
12777
12778 status = mdb_put(*txnp, dbi, &key, &data, 0);
12779 if (status != MDB_SUCCESS) {
12780 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12781 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12782 "Error inserting zone in "
12783 "NZD database: %s",
12784 mdb_strerror(status));
12785 result = ISC_R_FAILURE;
12786 goto cleanup;
12787 }
12788
12789 commit = true;
12790 }
12791
12792 result = ISC_R_SUCCESS;
12793
12794 cleanup:
12795 if (!commit || result != ISC_R_SUCCESS) {
12796 (void)mdb_txn_abort(*txnp);
12797 } else {
12798 status = mdb_txn_commit(*txnp);
12799 if (status != MDB_SUCCESS) {
12800 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12801 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
12802 "Error committing "
12803 "NZD database: %s",
12804 mdb_strerror(status));
12805 result = ISC_R_FAILURE;
12806 }
12807 }
12808 *txnp = NULL;
12809
12810 if (text != NULL) {
12811 isc_buffer_free(&text);
12812 }
12813
12814 return (result);
12815 }
12816
12817 /*
12818 * Check whether the new zone database for 'view' can be opened for writing.
12819 *
12820 * Caller must hold 'view->new_zone_lock'.
12821 */
12822 static isc_result_t
nzd_writable(dns_view_t * view)12823 nzd_writable(dns_view_t *view) {
12824 isc_result_t result = ISC_R_SUCCESS;
12825 int status;
12826 MDB_dbi dbi;
12827 MDB_txn *txn = NULL;
12828
12829 REQUIRE(view != NULL);
12830
12831 status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, 0, &txn);
12832 if (status != MDB_SUCCESS) {
12833 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12834 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12835 "mdb_txn_begin: %s", mdb_strerror(status));
12836 return (ISC_R_FAILURE);
12837 }
12838
12839 status = mdb_dbi_open(txn, NULL, 0, &dbi);
12840 if (status != MDB_SUCCESS) {
12841 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12842 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12843 "mdb_dbi_open: %s", mdb_strerror(status));
12844 result = ISC_R_FAILURE;
12845 }
12846
12847 mdb_txn_abort(txn);
12848 return (result);
12849 }
12850
12851 /*
12852 * Open the new zone database for 'view' and start a transaction for it.
12853 *
12854 * Caller must hold 'view->new_zone_lock'.
12855 */
12856 static isc_result_t
nzd_open(dns_view_t * view,unsigned int flags,MDB_txn ** txnp,MDB_dbi * dbi)12857 nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
12858 int status;
12859 MDB_txn *txn = NULL;
12860
12861 REQUIRE(view != NULL);
12862 REQUIRE(txnp != NULL && *txnp == NULL);
12863 REQUIRE(dbi != NULL);
12864
12865 status = mdb_txn_begin((MDB_env *)view->new_zone_dbenv, 0, flags, &txn);
12866 if (status != MDB_SUCCESS) {
12867 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12868 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12869 "mdb_txn_begin: %s", mdb_strerror(status));
12870 goto cleanup;
12871 }
12872
12873 status = mdb_dbi_open(txn, NULL, 0, dbi);
12874 if (status != MDB_SUCCESS) {
12875 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12876 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12877 "mdb_dbi_open: %s", mdb_strerror(status));
12878 goto cleanup;
12879 }
12880
12881 *txnp = txn;
12882
12883 cleanup:
12884 if (status != MDB_SUCCESS) {
12885 if (txn != NULL) {
12886 mdb_txn_abort(txn);
12887 }
12888 return (ISC_R_FAILURE);
12889 }
12890
12891 return (ISC_R_SUCCESS);
12892 }
12893
12894 /*
12895 * nzd_env_close() and nzd_env_reopen are a kluge to address the
12896 * problem of an NZD file possibly being created before we drop
12897 * root privileges.
12898 */
12899 static void
nzd_env_close(dns_view_t * view)12900 nzd_env_close(dns_view_t *view) {
12901 const char *dbpath = NULL;
12902 char dbpath_copy[PATH_MAX];
12903 char lockpath[PATH_MAX];
12904 int status, ret;
12905
12906 if (view->new_zone_dbenv == NULL) {
12907 return;
12908 }
12909
12910 status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
12911 INSIST(status == MDB_SUCCESS);
12912 snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
12913 strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
12914 mdb_env_close((MDB_env *)view->new_zone_dbenv);
12915
12916 /*
12917 * Database files must be owned by the eventual user, not by root.
12918 */
12919 ret = chown(dbpath_copy, ns_os_uid(), -1);
12920 UNUSED(ret);
12921
12922 /*
12923 * Some platforms need the lockfile not to exist when we reopen the
12924 * environment.
12925 */
12926 (void)isc_file_remove(lockpath);
12927
12928 view->new_zone_dbenv = NULL;
12929 }
12930
12931 static isc_result_t
nzd_env_reopen(dns_view_t * view)12932 nzd_env_reopen(dns_view_t *view) {
12933 isc_result_t result;
12934 MDB_env *env = NULL;
12935 int status;
12936
12937 if (view->new_zone_db == NULL) {
12938 return (ISC_R_SUCCESS);
12939 }
12940
12941 nzd_env_close(view);
12942
12943 status = mdb_env_create(&env);
12944 if (status != MDB_SUCCESS) {
12945 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
12946 ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
12947 "mdb_env_create failed: %s",
12948 mdb_strerror(status));
12949 CHECK(ISC_R_FAILURE);
12950 }
12951
12952 if (view->new_zone_mapsize != 0ULL) {
12953 status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
12954 if (status != MDB_SUCCESS) {
12955 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
12956 ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
12957 "mdb_env_set_mapsize failed: %s",
12958 mdb_strerror(status));
12959 CHECK(ISC_R_FAILURE);
12960 }
12961 }
12962
12963 status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
12964 if (status != MDB_SUCCESS) {
12965 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
12966 ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
12967 "mdb_env_open of '%s' failed: %s",
12968 view->new_zone_db, mdb_strerror(status));
12969 CHECK(ISC_R_FAILURE);
12970 }
12971
12972 view->new_zone_dbenv = env;
12973 env = NULL;
12974 result = ISC_R_SUCCESS;
12975
12976 cleanup:
12977 if (env != NULL) {
12978 mdb_env_close(env);
12979 }
12980 return (result);
12981 }
12982
12983 /*
12984 * If 'commit' is true, commit the new zone database transaction pointed to by
12985 * 'txnp'; otherwise, abort that transaction.
12986 *
12987 * Caller must hold 'view->new_zone_lock' for the view that the transaction
12988 * pointed to by 'txnp' was started for.
12989 */
12990 static isc_result_t
nzd_close(MDB_txn ** txnp,bool commit)12991 nzd_close(MDB_txn **txnp, bool commit) {
12992 isc_result_t result = ISC_R_SUCCESS;
12993 int status;
12994
12995 REQUIRE(txnp != NULL);
12996
12997 if (*txnp != NULL) {
12998 if (commit) {
12999 status = mdb_txn_commit(*txnp);
13000 if (status != MDB_SUCCESS) {
13001 result = ISC_R_FAILURE;
13002 }
13003 } else {
13004 mdb_txn_abort(*txnp);
13005 }
13006 *txnp = NULL;
13007 }
13008
13009 return (result);
13010 }
13011
13012 /*
13013 * Count the zones configured in the new zone database for 'view' and store the
13014 * result in 'countp'.
13015 *
13016 * Caller must hold 'view->new_zone_lock'.
13017 */
13018 static isc_result_t
nzd_count(dns_view_t * view,int * countp)13019 nzd_count(dns_view_t *view, int *countp) {
13020 isc_result_t result;
13021 int status;
13022 MDB_txn *txn = NULL;
13023 MDB_dbi dbi;
13024 MDB_stat statbuf;
13025
13026 REQUIRE(countp != NULL);
13027
13028 result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
13029 if (result != ISC_R_SUCCESS) {
13030 goto cleanup;
13031 }
13032
13033 status = mdb_stat(txn, dbi, &statbuf);
13034 if (status != MDB_SUCCESS) {
13035 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13036 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13037 "mdb_stat: %s", mdb_strerror(status));
13038 result = ISC_R_FAILURE;
13039 goto cleanup;
13040 }
13041
13042 *countp = statbuf.ms_entries;
13043
13044 cleanup:
13045 (void)nzd_close(&txn, false);
13046
13047 return (result);
13048 }
13049
13050 /*
13051 * Migrate zone configuration from an NZF file to an NZD database.
13052 * Caller must hold view->new_zone_lock.
13053 */
13054 static isc_result_t
migrate_nzf(dns_view_t * view)13055 migrate_nzf(dns_view_t *view) {
13056 isc_result_t result;
13057 cfg_obj_t *nzf_config = NULL;
13058 int status, n;
13059 isc_buffer_t *text = NULL;
13060 bool commit = false;
13061 const cfg_obj_t *zonelist;
13062 const cfg_listelt_t *element;
13063 char tempname[PATH_MAX];
13064 MDB_txn *txn = NULL;
13065 MDB_dbi dbi;
13066 MDB_val key, data;
13067 ns_dzarg_t dzarg;
13068
13069 /*
13070 * If NZF file doesn't exist, or NZD DB exists and already
13071 * has data, return without attempting migration.
13072 */
13073 if (!isc_file_exists(view->new_zone_file)) {
13074 result = ISC_R_SUCCESS;
13075 goto cleanup;
13076 }
13077
13078 result = nzd_count(view, &n);
13079 if (result == ISC_R_SUCCESS && n > 0) {
13080 result = ISC_R_SUCCESS;
13081 goto cleanup;
13082 }
13083
13084 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13085 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13086 "Migrating zones from NZF file '%s' to "
13087 "NZD database '%s'",
13088 view->new_zone_file, view->new_zone_db);
13089 /*
13090 * Instead of blindly copying lines, we parse the NZF file using
13091 * the configuration parser, because it validates it against the
13092 * config type, giving us a guarantee that valid configuration
13093 * will be written to DB.
13094 */
13095 cfg_parser_reset(named_g_addparser);
13096 result = cfg_parse_file(named_g_addparser, view->new_zone_file,
13097 &cfg_type_addzoneconf, &nzf_config);
13098 if (result != ISC_R_SUCCESS) {
13099 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13100 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13101 "Error parsing NZF file '%s': %s",
13102 view->new_zone_file, isc_result_totext(result));
13103 goto cleanup;
13104 }
13105
13106 zonelist = NULL;
13107 CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
13108 if (!cfg_obj_islist(zonelist)) {
13109 CHECK(ISC_R_FAILURE);
13110 }
13111
13112 CHECK(nzd_open(view, 0, &txn, &dbi));
13113
13114 isc_buffer_allocate(view->mctx, &text, 256);
13115
13116 for (element = cfg_list_first(zonelist); element != NULL;
13117 element = cfg_list_next(element))
13118 {
13119 const cfg_obj_t *zconfig;
13120 const cfg_obj_t *zoptions;
13121 char zname[DNS_NAME_FORMATSIZE];
13122 dns_fixedname_t fname;
13123 dns_name_t *name;
13124 const char *origin;
13125 isc_buffer_t b;
13126
13127 zconfig = cfg_listelt_value(element);
13128
13129 origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
13130 if (origin == NULL) {
13131 result = ISC_R_FAILURE;
13132 goto cleanup;
13133 }
13134
13135 /* Normalize zone name */
13136 isc_buffer_constinit(&b, origin, strlen(origin));
13137 isc_buffer_add(&b, strlen(origin));
13138 name = dns_fixedname_initname(&fname);
13139 CHECK(dns_name_fromtext(name, &b, dns_rootname,
13140 DNS_NAME_DOWNCASE, NULL));
13141 dns_name_format(name, zname, sizeof(zname));
13142
13143 key.mv_data = zname;
13144 key.mv_size = strlen(zname);
13145
13146 zoptions = cfg_tuple_get(zconfig, "options");
13147 if (zoptions == NULL) {
13148 result = ISC_R_FAILURE;
13149 goto cleanup;
13150 }
13151
13152 isc_buffer_clear(text);
13153 dzarg.magic = DZARG_MAGIC;
13154 dzarg.text = &text;
13155 dzarg.result = ISC_R_SUCCESS;
13156 cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
13157 if (dzarg.result != ISC_R_SUCCESS) {
13158 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13159 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13160 "Error writing zone config to "
13161 "buffer in migrate_nzf(): %s",
13162 isc_result_totext(result));
13163 result = dzarg.result;
13164 goto cleanup;
13165 }
13166
13167 data.mv_data = isc_buffer_base(text);
13168 data.mv_size = isc_buffer_usedlength(text);
13169
13170 status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
13171 if (status != MDB_SUCCESS) {
13172 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13173 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13174 "Error inserting zone in "
13175 "NZD database: %s",
13176 mdb_strerror(status));
13177 result = ISC_R_FAILURE;
13178 goto cleanup;
13179 }
13180
13181 commit = true;
13182 }
13183
13184 result = ISC_R_SUCCESS;
13185
13186 /*
13187 * Leaving the NZF file in place is harmless as we won't use it
13188 * if an NZD database is found for the view. But we rename NZF file
13189 * to a backup name here.
13190 */
13191 strlcpy(tempname, view->new_zone_file, sizeof(tempname));
13192 if (strlen(tempname) < sizeof(tempname) - 1) {
13193 strlcat(tempname, "~", sizeof(tempname));
13194 isc_file_rename(view->new_zone_file, tempname);
13195 }
13196
13197 cleanup:
13198 if (result != ISC_R_SUCCESS) {
13199 (void)nzd_close(&txn, false);
13200 } else {
13201 result = nzd_close(&txn, commit);
13202 }
13203
13204 if (text != NULL) {
13205 isc_buffer_free(&text);
13206 }
13207
13208 if (nzf_config != NULL) {
13209 cfg_obj_destroy(named_g_addparser, &nzf_config);
13210 }
13211
13212 return (result);
13213 }
13214
13215 #endif /* HAVE_LMDB */
13216
13217 static isc_result_t
newzone_parse(named_server_t * server,char * command,dns_view_t ** viewp,cfg_obj_t ** zoneconfp,const cfg_obj_t ** zoneobjp,bool * redirectp,isc_buffer_t ** text)13218 newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
13219 cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
13220 bool *redirectp, isc_buffer_t **text) {
13221 isc_result_t result;
13222 isc_buffer_t argbuf;
13223 bool redirect = false;
13224 cfg_obj_t *zoneconf = NULL;
13225 const cfg_obj_t *zlist = NULL;
13226 const cfg_obj_t *zoneobj = NULL;
13227 const cfg_obj_t *zoptions = NULL;
13228 const cfg_obj_t *obj = NULL;
13229 const char *viewname = NULL;
13230 dns_rdataclass_t rdclass;
13231 dns_view_t *view = NULL;
13232 const char *bn = NULL;
13233
13234 REQUIRE(viewp != NULL && *viewp == NULL);
13235 REQUIRE(zoneobjp != NULL && *zoneobjp == NULL);
13236 REQUIRE(zoneconfp != NULL && *zoneconfp == NULL);
13237 REQUIRE(redirectp != NULL);
13238
13239 /* Try to parse the argument string */
13240 isc_buffer_init(&argbuf, command, (unsigned int)strlen(command));
13241 isc_buffer_add(&argbuf, strlen(command));
13242
13243 if (strncasecmp(command, "add", 3) == 0) {
13244 bn = "addzone";
13245 } else if (strncasecmp(command, "mod", 3) == 0) {
13246 bn = "modzone";
13247 } else {
13248 UNREACHABLE();
13249 }
13250
13251 /*
13252 * Convert the "addzone" or "modzone" to just "zone", for
13253 * the benefit of the parser
13254 */
13255 isc_buffer_forward(&argbuf, 3);
13256
13257 cfg_parser_reset(named_g_addparser);
13258 CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0,
13259 &cfg_type_addzoneconf, 0, &zoneconf));
13260 CHECK(cfg_map_get(zoneconf, "zone", &zlist));
13261 if (!cfg_obj_islist(zlist)) {
13262 CHECK(ISC_R_FAILURE);
13263 }
13264
13265 /* For now we only support adding one zone at a time */
13266 zoneobj = cfg_listelt_value(cfg_list_first(zlist));
13267
13268 /* Check the zone type for ones that are not supported by addzone. */
13269 zoptions = cfg_tuple_get(zoneobj, "options");
13270
13271 obj = NULL;
13272 (void)cfg_map_get(zoptions, "type", &obj);
13273 if (obj == NULL) {
13274 (void)cfg_map_get(zoptions, "in-view", &obj);
13275 if (obj != NULL) {
13276 (void)putstr(text, "'in-view' zones not supported by ");
13277 (void)putstr(text, bn);
13278 } else {
13279 (void)putstr(text, "zone type not specified");
13280 }
13281 CHECK(ISC_R_FAILURE);
13282 }
13283
13284 if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
13285 strcasecmp(cfg_obj_asstring(obj), "forward") == 0 ||
13286 strcasecmp(cfg_obj_asstring(obj), "delegation-only") == 0)
13287 {
13288 (void)putstr(text, "'");
13289 (void)putstr(text, cfg_obj_asstring(obj));
13290 (void)putstr(text, "' zones not supported by ");
13291 (void)putstr(text, bn);
13292 CHECK(ISC_R_FAILURE);
13293 }
13294
13295 if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0) {
13296 redirect = true;
13297 }
13298
13299 /* Make sense of optional class argument */
13300 obj = cfg_tuple_get(zoneobj, "class");
13301 CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass));
13302
13303 /* Make sense of optional view argument */
13304 obj = cfg_tuple_get(zoneobj, "view");
13305 if (obj && cfg_obj_isstring(obj)) {
13306 viewname = cfg_obj_asstring(obj);
13307 }
13308 if (viewname == NULL || *viewname == '\0') {
13309 viewname = "_default";
13310 }
13311 result = dns_viewlist_find(&server->viewlist, viewname, rdclass, &view);
13312 if (result == ISC_R_NOTFOUND) {
13313 (void)putstr(text, "no matching view found for '");
13314 (void)putstr(text, viewname);
13315 (void)putstr(text, "'");
13316 goto cleanup;
13317 } else if (result != ISC_R_SUCCESS) {
13318 goto cleanup;
13319 }
13320
13321 *viewp = view;
13322 *zoneobjp = zoneobj;
13323 *zoneconfp = zoneconf;
13324 *redirectp = redirect;
13325
13326 return (ISC_R_SUCCESS);
13327
13328 cleanup:
13329 if (zoneconf != NULL) {
13330 cfg_obj_destroy(named_g_addparser, &zoneconf);
13331 }
13332 if (view != NULL) {
13333 dns_view_detach(&view);
13334 }
13335
13336 return (result);
13337 }
13338
13339 static isc_result_t
delete_zoneconf(dns_view_t * view,cfg_parser_t * pctx,const cfg_obj_t * config,const dns_name_t * zname,nzfwriter_t nzfwriter)13340 delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config,
13341 const dns_name_t *zname, nzfwriter_t nzfwriter) {
13342 isc_result_t result = ISC_R_NOTFOUND;
13343 const cfg_listelt_t *elt = NULL;
13344 const cfg_obj_t *zl = NULL;
13345 cfg_list_t *list;
13346 dns_fixedname_t myfixed;
13347 dns_name_t *myname;
13348
13349 REQUIRE(view != NULL);
13350 REQUIRE(pctx != NULL);
13351 REQUIRE(config != NULL);
13352 REQUIRE(zname != NULL);
13353
13354 LOCK(&view->new_zone_lock);
13355
13356 cfg_map_get(config, "zone", &zl);
13357
13358 if (!cfg_obj_islist(zl)) {
13359 CHECK(ISC_R_FAILURE);
13360 }
13361
13362 DE_CONST(&zl->value.list, list);
13363
13364 myname = dns_fixedname_initname(&myfixed);
13365
13366 for (elt = ISC_LIST_HEAD(*list); elt != NULL;
13367 elt = ISC_LIST_NEXT(elt, link))
13368 {
13369 const cfg_obj_t *zconf = cfg_listelt_value(elt);
13370 const char *zn;
13371 cfg_listelt_t *e;
13372
13373 zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
13374 result = dns_name_fromstring(myname, zn, 0, NULL);
13375 if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname)) {
13376 continue;
13377 }
13378
13379 DE_CONST(elt, e);
13380 ISC_LIST_UNLINK(*list, e, link);
13381 cfg_obj_destroy(pctx, &e->obj);
13382 isc_mem_put(pctx->mctx, e, sizeof(*e));
13383 result = ISC_R_SUCCESS;
13384 break;
13385 }
13386
13387 /*
13388 * Write config to NZF file if appropriate
13389 */
13390 if (nzfwriter != NULL && view->new_zone_file != NULL) {
13391 result = nzfwriter(config, view);
13392 }
13393
13394 cleanup:
13395 UNLOCK(&view->new_zone_lock);
13396 return (result);
13397 }
13398
13399 static isc_result_t
do_addzone(named_server_t * server,ns_cfgctx_t * cfg,dns_view_t * view,dns_name_t * name,cfg_obj_t * zoneconf,const cfg_obj_t * zoneobj,bool redirect,isc_buffer_t ** text)13400 do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13401 dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
13402 bool redirect, isc_buffer_t **text) {
13403 isc_result_t result, tresult;
13404 dns_zone_t *zone = NULL;
13405 #ifndef HAVE_LMDB
13406 FILE *fp = NULL;
13407 bool cleanup_config = false;
13408 #else /* HAVE_LMDB */
13409 MDB_txn *txn = NULL;
13410 MDB_dbi dbi;
13411 bool locked = false;
13412
13413 UNUSED(zoneconf);
13414 #endif
13415
13416 /* Zone shouldn't already exist */
13417 if (redirect) {
13418 result = (view->redirect != NULL) ? ISC_R_SUCCESS
13419 : ISC_R_NOTFOUND;
13420 } else {
13421 result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13422 }
13423 if (result == ISC_R_SUCCESS) {
13424 result = ISC_R_EXISTS;
13425 goto cleanup;
13426 } else if (result == DNS_R_PARTIALMATCH) {
13427 /* Create our sub-zone anyway */
13428 dns_zone_detach(&zone);
13429 zone = NULL;
13430 } else if (result != ISC_R_NOTFOUND) {
13431 goto cleanup;
13432 }
13433
13434 result = isc_task_beginexclusive(server->task);
13435 RUNTIME_CHECK(result == ISC_R_SUCCESS);
13436
13437 #ifndef HAVE_LMDB
13438 /*
13439 * Make sure we can open the configuration save file
13440 */
13441 result = isc_stdio_open(view->new_zone_file, "a", &fp);
13442 if (result != ISC_R_SUCCESS) {
13443 isc_task_endexclusive(server->task);
13444 TCHECK(putstr(text, "unable to create '"));
13445 TCHECK(putstr(text, view->new_zone_file));
13446 TCHECK(putstr(text, "': "));
13447 TCHECK(putstr(text, isc_result_totext(result)));
13448 goto cleanup;
13449 }
13450
13451 (void)isc_stdio_close(fp);
13452 fp = NULL;
13453 #else /* HAVE_LMDB */
13454 LOCK(&view->new_zone_lock);
13455 locked = true;
13456 /* Make sure we can open the NZD database */
13457 result = nzd_writable(view);
13458 if (result != ISC_R_SUCCESS) {
13459 isc_task_endexclusive(server->task);
13460 TCHECK(putstr(text, "unable to open NZD database for '"));
13461 TCHECK(putstr(text, view->new_zone_db));
13462 TCHECK(putstr(text, "'"));
13463 result = ISC_R_FAILURE;
13464 goto cleanup;
13465 }
13466 #endif /* HAVE_LMDB */
13467
13468 /* Mark view unfrozen and configure zone */
13469 dns_view_thaw(view);
13470 result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
13471 server->mctx, view, &server->viewlist,
13472 &server->kasplist, cfg->actx, true, false,
13473 false);
13474 dns_view_freeze(view);
13475
13476 isc_task_endexclusive(server->task);
13477
13478 if (result != ISC_R_SUCCESS) {
13479 TCHECK(putstr(text, "configure_zone failed: "));
13480 TCHECK(putstr(text, isc_result_totext(result)));
13481 goto cleanup;
13482 }
13483
13484 /* Is it there yet? */
13485 if (redirect) {
13486 if (view->redirect == NULL) {
13487 CHECK(ISC_R_NOTFOUND);
13488 }
13489 dns_zone_attach(view->redirect, &zone);
13490 } else {
13491 result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13492 if (result != ISC_R_SUCCESS) {
13493 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13494 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13495 "added new zone was not found: %s",
13496 isc_result_totext(result));
13497 goto cleanup;
13498 }
13499 }
13500
13501 #ifndef HAVE_LMDB
13502 /*
13503 * If there wasn't a previous newzone config, just save the one
13504 * we've created. If there was a previous one, merge the new
13505 * zone into it.
13506 */
13507 if (cfg->nzf_config == NULL) {
13508 cfg_obj_attach(zoneconf, &cfg->nzf_config);
13509 } else {
13510 cfg_obj_t *z;
13511 DE_CONST(zoneobj, z);
13512 CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z,
13513 "zone"));
13514 }
13515 cleanup_config = true;
13516 #endif /* HAVE_LMDB */
13517
13518 /*
13519 * Load the zone from the master file. If this fails, we'll
13520 * need to undo the configuration we've done already.
13521 */
13522 result = dns_zone_load(zone, true);
13523 if (result != ISC_R_SUCCESS) {
13524 dns_db_t *dbp = NULL;
13525
13526 TCHECK(putstr(text, "dns_zone_loadnew failed: "));
13527 TCHECK(putstr(text, isc_result_totext(result)));
13528
13529 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13530 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13531 "addzone failed; reverting.");
13532
13533 /* If the zone loaded partially, unload it */
13534 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13535 dns_db_detach(&dbp);
13536 dns_zone_unload(zone);
13537 }
13538
13539 /* Remove the zone from the zone table */
13540 dns_zt_unmount(view->zonetable, zone);
13541 goto cleanup;
13542 }
13543
13544 /* Flag the zone as having been added at runtime */
13545 dns_zone_setadded(zone, true);
13546
13547 #ifdef HAVE_LMDB
13548 /* Save the new zone configuration into the NZD */
13549 CHECK(nzd_open(view, 0, &txn, &dbi));
13550 CHECK(nzd_save(&txn, dbi, zone, zoneobj));
13551 #else /* ifdef HAVE_LMDB */
13552 /* Append the zone configuration to the NZF */
13553 result = nzf_append(view, zoneobj);
13554 #endif /* HAVE_LMDB */
13555
13556 cleanup:
13557
13558 #ifndef HAVE_LMDB
13559 if (fp != NULL) {
13560 (void)isc_stdio_close(fp);
13561 }
13562 if (result != ISC_R_SUCCESS && cleanup_config) {
13563 tresult = delete_zoneconf(view, cfg->add_parser,
13564 cfg->nzf_config, name, NULL);
13565 RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
13566 }
13567 #else /* HAVE_LMDB */
13568 if (txn != NULL) {
13569 (void)nzd_close(&txn, false);
13570 }
13571 if (locked) {
13572 UNLOCK(&view->new_zone_lock);
13573 }
13574 #endif /* HAVE_LMDB */
13575
13576 if (zone != NULL) {
13577 dns_zone_detach(&zone);
13578 }
13579
13580 return (result);
13581 }
13582
13583 static isc_result_t
do_modzone(named_server_t * server,ns_cfgctx_t * cfg,dns_view_t * view,dns_name_t * name,const char * zname,const cfg_obj_t * zoneobj,bool redirect,isc_buffer_t ** text)13584 do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13585 dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
13586 bool redirect, isc_buffer_t **text) {
13587 isc_result_t result, tresult;
13588 dns_zone_t *zone = NULL;
13589 bool added;
13590 bool exclusive = false;
13591 #ifndef HAVE_LMDB
13592 FILE *fp = NULL;
13593 cfg_obj_t *z;
13594 #else /* HAVE_LMDB */
13595 MDB_txn *txn = NULL;
13596 MDB_dbi dbi;
13597 bool locked = false;
13598 #endif /* HAVE_LMDB */
13599
13600 /* Zone must already exist */
13601 if (redirect) {
13602 if (view->redirect != NULL) {
13603 dns_zone_attach(view->redirect, &zone);
13604 result = ISC_R_SUCCESS;
13605 } else {
13606 result = ISC_R_NOTFOUND;
13607 }
13608 } else {
13609 result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13610 }
13611 if (result != ISC_R_SUCCESS) {
13612 goto cleanup;
13613 }
13614
13615 added = dns_zone_getadded(zone);
13616 dns_zone_detach(&zone);
13617
13618 #ifndef HAVE_LMDB
13619 cfg = (ns_cfgctx_t *)view->new_zone_config;
13620 if (cfg == NULL) {
13621 TCHECK(putstr(text, "new zone config is not set"));
13622 CHECK(ISC_R_FAILURE);
13623 }
13624 #endif /* ifndef HAVE_LMDB */
13625
13626 result = isc_task_beginexclusive(server->task);
13627 RUNTIME_CHECK(result == ISC_R_SUCCESS);
13628 exclusive = true;
13629
13630 #ifndef HAVE_LMDB
13631 /* Make sure we can open the configuration save file */
13632 result = isc_stdio_open(view->new_zone_file, "a", &fp);
13633 if (result != ISC_R_SUCCESS) {
13634 TCHECK(putstr(text, "unable to open '"));
13635 TCHECK(putstr(text, view->new_zone_file));
13636 TCHECK(putstr(text, "': "));
13637 TCHECK(putstr(text, isc_result_totext(result)));
13638 goto cleanup;
13639 }
13640 (void)isc_stdio_close(fp);
13641 fp = NULL;
13642 #else /* HAVE_LMDB */
13643 LOCK(&view->new_zone_lock);
13644 locked = true;
13645 /* Make sure we can open the NZD database */
13646 result = nzd_writable(view);
13647 if (result != ISC_R_SUCCESS) {
13648 TCHECK(putstr(text, "unable to open NZD database for '"));
13649 TCHECK(putstr(text, view->new_zone_db));
13650 TCHECK(putstr(text, "'"));
13651 result = ISC_R_FAILURE;
13652 goto cleanup;
13653 }
13654 #endif /* HAVE_LMDB */
13655
13656 /* Reconfigure the zone */
13657 dns_view_thaw(view);
13658 result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
13659 server->mctx, view, &server->viewlist,
13660 &server->kasplist, cfg->actx, true, false,
13661 true);
13662 dns_view_freeze(view);
13663
13664 exclusive = false;
13665 isc_task_endexclusive(server->task);
13666
13667 if (result != ISC_R_SUCCESS) {
13668 TCHECK(putstr(text, "configure_zone failed: "));
13669 TCHECK(putstr(text, isc_result_totext(result)));
13670 goto cleanup;
13671 }
13672
13673 /* Is it there yet? */
13674 if (redirect) {
13675 if (view->redirect == NULL) {
13676 CHECK(ISC_R_NOTFOUND);
13677 }
13678 dns_zone_attach(view->redirect, &zone);
13679 } else {
13680 CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
13681 }
13682
13683 #ifndef HAVE_LMDB
13684 /* Remove old zone from configuration (and NZF file if applicable) */
13685 if (added) {
13686 result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
13687 dns_zone_getorigin(zone),
13688 nzf_writeconf);
13689 if (result != ISC_R_SUCCESS) {
13690 TCHECK(putstr(text, "former zone configuration "
13691 "not deleted: "));
13692 TCHECK(putstr(text, isc_result_totext(result)));
13693 goto cleanup;
13694 }
13695 }
13696 #endif /* HAVE_LMDB */
13697
13698 if (!added) {
13699 if (cfg->vconfig == NULL) {
13700 result = delete_zoneconf(
13701 view, cfg->conf_parser, cfg->config,
13702 dns_zone_getorigin(zone), NULL);
13703 } else {
13704 const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
13705 "options");
13706 result = delete_zoneconf(
13707 view, cfg->conf_parser, voptions,
13708 dns_zone_getorigin(zone), NULL);
13709 }
13710
13711 if (result != ISC_R_SUCCESS) {
13712 TCHECK(putstr(text, "former zone configuration "
13713 "not deleted: "));
13714 TCHECK(putstr(text, isc_result_totext(result)));
13715 goto cleanup;
13716 }
13717 }
13718
13719 /* Load the zone from the master file if it needs reloading. */
13720 result = dns_zone_load(zone, true);
13721
13722 /*
13723 * Dynamic zones need no reloading, so we can pass this result.
13724 */
13725 if (result == DNS_R_DYNAMIC) {
13726 result = ISC_R_SUCCESS;
13727 }
13728
13729 if (result != ISC_R_SUCCESS) {
13730 dns_db_t *dbp = NULL;
13731
13732 TCHECK(putstr(text, "failed to load zone '"));
13733 TCHECK(putstr(text, zname));
13734 TCHECK(putstr(text, "': "));
13735 TCHECK(putstr(text, isc_result_totext(result)));
13736 TCHECK(putstr(text, "\nThe zone is no longer being served. "));
13737 TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
13738 TCHECK(putstr(text, "the problem and restore service."));
13739
13740 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13741 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13742 "modzone failed; removing zone.");
13743
13744 /* If the zone loaded partially, unload it */
13745 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13746 dns_db_detach(&dbp);
13747 dns_zone_unload(zone);
13748 }
13749
13750 /* Remove the zone from the zone table */
13751 dns_zt_unmount(view->zonetable, zone);
13752 goto cleanup;
13753 }
13754
13755 #ifndef HAVE_LMDB
13756 /* Store the new zone configuration; also in NZF if applicable */
13757 DE_CONST(zoneobj, z);
13758 CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone"));
13759 #endif /* HAVE_LMDB */
13760
13761 if (added) {
13762 #ifdef HAVE_LMDB
13763 CHECK(nzd_open(view, 0, &txn, &dbi));
13764 CHECK(nzd_save(&txn, dbi, zone, zoneobj));
13765 #else /* ifdef HAVE_LMDB */
13766 result = nzf_append(view, zoneobj);
13767 if (result != ISC_R_SUCCESS) {
13768 TCHECK(putstr(text, "\nNew zone config not saved: "));
13769 TCHECK(putstr(text, isc_result_totext(result)));
13770 goto cleanup;
13771 }
13772 #endif /* HAVE_LMDB */
13773
13774 TCHECK(putstr(text, "zone '"));
13775 TCHECK(putstr(text, zname));
13776 TCHECK(putstr(text, "' reconfigured."));
13777 } else {
13778 TCHECK(putstr(text, "zone '"));
13779 TCHECK(putstr(text, zname));
13780 TCHECK(putstr(text, "' must also be reconfigured in\n"));
13781 TCHECK(putstr(text, "named.conf to make changes permanent."));
13782 }
13783
13784 cleanup:
13785 if (exclusive) {
13786 isc_task_endexclusive(server->task);
13787 }
13788
13789 #ifndef HAVE_LMDB
13790 if (fp != NULL) {
13791 (void)isc_stdio_close(fp);
13792 }
13793 #else /* HAVE_LMDB */
13794 if (txn != NULL) {
13795 (void)nzd_close(&txn, false);
13796 }
13797 if (locked) {
13798 UNLOCK(&view->new_zone_lock);
13799 }
13800 #endif /* HAVE_LMDB */
13801
13802 if (zone != NULL) {
13803 dns_zone_detach(&zone);
13804 }
13805
13806 return (result);
13807 }
13808
13809 /*
13810 * Act on an "addzone" or "modzone" command from the command channel.
13811 */
13812 isc_result_t
named_server_changezone(named_server_t * server,char * command,isc_buffer_t ** text)13813 named_server_changezone(named_server_t *server, char *command,
13814 isc_buffer_t **text) {
13815 isc_result_t result;
13816 bool addzone;
13817 bool redirect = false;
13818 ns_cfgctx_t *cfg = NULL;
13819 cfg_obj_t *zoneconf = NULL;
13820 const cfg_obj_t *zoneobj = NULL;
13821 const char *zonename;
13822 dns_view_t *view = NULL;
13823 isc_buffer_t buf;
13824 dns_fixedname_t fname;
13825 dns_name_t *dnsname;
13826
13827 REQUIRE(text != NULL);
13828
13829 if (strncasecmp(command, "add", 3) == 0) {
13830 addzone = true;
13831 } else {
13832 INSIST(strncasecmp(command, "mod", 3) == 0);
13833 addzone = false;
13834 }
13835
13836 CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj,
13837 &redirect, text));
13838
13839 /* Are we accepting new zones in this view? */
13840 #ifdef HAVE_LMDB
13841 if (view->new_zone_db == NULL)
13842 #else /* ifdef HAVE_LMDB */
13843 if (view->new_zone_file == NULL)
13844 #endif /* HAVE_LMDB */
13845 {
13846 (void)putstr(text, "Not allowing new zones in view '");
13847 (void)putstr(text, view->name);
13848 (void)putstr(text, "'");
13849 result = ISC_R_NOPERM;
13850 goto cleanup;
13851 }
13852
13853 cfg = (ns_cfgctx_t *)view->new_zone_config;
13854 if (cfg == NULL) {
13855 result = ISC_R_FAILURE;
13856 goto cleanup;
13857 }
13858
13859 zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
13860 isc_buffer_constinit(&buf, zonename, strlen(zonename));
13861 isc_buffer_add(&buf, strlen(zonename));
13862
13863 dnsname = dns_fixedname_initname(&fname);
13864 CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL));
13865
13866 if (redirect) {
13867 if (!dns_name_equal(dnsname, dns_rootname)) {
13868 (void)putstr(text, "redirect zones must be called "
13869 "\".\"");
13870 CHECK(ISC_R_FAILURE);
13871 }
13872 }
13873
13874 if (addzone) {
13875 CHECK(do_addzone(server, cfg, view, dnsname, zoneconf, zoneobj,
13876 redirect, text));
13877 } else {
13878 CHECK(do_modzone(server, cfg, view, dnsname, zonename, zoneobj,
13879 redirect, text));
13880 }
13881
13882 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13883 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13884 "%s zone %s in view %s via %s",
13885 addzone ? "added" : "updated", zonename, view->name,
13886 addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
13887
13888 /* Changing a zone counts as reconfiguration */
13889 CHECK(isc_time_now(&named_g_configtime));
13890
13891 cleanup:
13892 if (isc_buffer_usedlength(*text) > 0) {
13893 (void)putnull(text);
13894 }
13895 if (zoneconf != NULL) {
13896 cfg_obj_destroy(named_g_addparser, &zoneconf);
13897 }
13898 if (view != NULL) {
13899 dns_view_detach(&view);
13900 }
13901
13902 return (result);
13903 }
13904
13905 static bool
inuse(const char * file,bool first,isc_buffer_t ** text)13906 inuse(const char *file, bool first, isc_buffer_t **text) {
13907 if (file != NULL && isc_file_exists(file)) {
13908 if (first) {
13909 (void)putstr(text, "The following files were in use "
13910 "and may now be removed:\n");
13911 } else {
13912 (void)putstr(text, "\n");
13913 }
13914 (void)putstr(text, file);
13915 (void)putnull(text);
13916 return (false);
13917 }
13918 return (first);
13919 }
13920
13921 typedef struct {
13922 dns_zone_t *zone;
13923 bool cleanup;
13924 } ns_dzctx_t;
13925
13926 /*
13927 * Carry out a zone deletion scheduled by named_server_delzone().
13928 */
13929 static void
rmzone(isc_task_t * task,isc_event_t * event)13930 rmzone(isc_task_t *task, isc_event_t *event) {
13931 ns_dzctx_t *dz = (ns_dzctx_t *)event->ev_arg;
13932 dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
13933 dns_catz_zone_t *catz = NULL;
13934 char zonename[DNS_NAME_FORMATSIZE];
13935 dns_view_t *view = NULL;
13936 ns_cfgctx_t *cfg = NULL;
13937 dns_db_t *dbp = NULL;
13938 bool added;
13939 isc_result_t result;
13940 #ifdef HAVE_LMDB
13941 MDB_txn *txn = NULL;
13942 MDB_dbi dbi;
13943 #endif /* ifdef HAVE_LMDB */
13944
13945 REQUIRE(dz != NULL);
13946
13947 isc_event_free(&event);
13948
13949 /* Dig out configuration for this zone */
13950 zone = dz->zone;
13951 view = dns_zone_getview(zone);
13952 cfg = (ns_cfgctx_t *)view->new_zone_config;
13953 dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
13954
13955 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13956 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13957 "deleting zone %s in view %s via delzone", zonename,
13958 view->name);
13959
13960 /*
13961 * Remove the zone from configuration (and NZF file if applicable)
13962 * (If this is a catalog zone member then nzf_config can be NULL)
13963 */
13964 added = dns_zone_getadded(zone);
13965 catz = dns_zone_get_parentcatz(zone);
13966
13967 if (added && catz == NULL && cfg != NULL) {
13968 #ifdef HAVE_LMDB
13969 /* Make sure we can open the NZD database */
13970 LOCK(&view->new_zone_lock);
13971 result = nzd_open(view, 0, &txn, &dbi);
13972 if (result != ISC_R_SUCCESS) {
13973 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13974 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13975 "unable to open NZD database for '%s'",
13976 view->new_zone_db);
13977 } else {
13978 result = nzd_save(&txn, dbi, zone, NULL);
13979 }
13980
13981 if (result != ISC_R_SUCCESS) {
13982 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13983 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13984 "unable to delete zone configuration: %s",
13985 isc_result_totext(result));
13986 }
13987
13988 if (txn != NULL) {
13989 (void)nzd_close(&txn, false);
13990 }
13991 UNLOCK(&view->new_zone_lock);
13992 #else /* ifdef HAVE_LMDB */
13993 result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config,
13994 dns_zone_getorigin(zone),
13995 nzf_writeconf);
13996 if (result != ISC_R_SUCCESS) {
13997 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13998 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
13999 "unable to delete zone configuration: %s",
14000 isc_result_totext(result));
14001 }
14002 #endif /* HAVE_LMDB */
14003 }
14004
14005 if (!added && cfg != NULL) {
14006 if (cfg->vconfig != NULL) {
14007 const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig,
14008 "options");
14009 result = delete_zoneconf(
14010 view, cfg->conf_parser, voptions,
14011 dns_zone_getorigin(zone), NULL);
14012 } else {
14013 result = delete_zoneconf(
14014 view, cfg->conf_parser, cfg->config,
14015 dns_zone_getorigin(zone), NULL);
14016 }
14017 if (result != ISC_R_SUCCESS) {
14018 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14019 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14020 "unable to delete zone configuration: %s",
14021 isc_result_totext(result));
14022 }
14023 }
14024
14025 /* Unload zone database */
14026 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
14027 dns_db_detach(&dbp);
14028 dns_zone_unload(zone);
14029 }
14030
14031 /* Clean up stub/slave zone files if requested to do so */
14032 dns_zone_getraw(zone, &raw);
14033 mayberaw = (raw != NULL) ? raw : zone;
14034
14035 if (added && dz->cleanup) {
14036 const char *file;
14037
14038 file = dns_zone_getfile(mayberaw);
14039 result = isc_file_remove(file);
14040 if (result != ISC_R_SUCCESS) {
14041 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14042 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14043 "file %s not removed: %s", file,
14044 isc_result_totext(result));
14045 }
14046
14047 file = dns_zone_getjournal(mayberaw);
14048 result = isc_file_remove(file);
14049 if (result != ISC_R_SUCCESS) {
14050 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14051 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14052 "file %s not removed: %s", file,
14053 isc_result_totext(result));
14054 }
14055
14056 if (zone != mayberaw) {
14057 file = dns_zone_getfile(zone);
14058 result = isc_file_remove(file);
14059 if (result != ISC_R_SUCCESS) {
14060 isc_log_write(
14061 named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14062 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14063 "file %s not removed: %s", file,
14064 isc_result_totext(result));
14065 }
14066
14067 file = dns_zone_getjournal(zone);
14068 result = isc_file_remove(file);
14069 if (result != ISC_R_SUCCESS) {
14070 isc_log_write(
14071 named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14072 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14073 "file %s not removed: %s", file,
14074 isc_result_totext(result));
14075 }
14076 }
14077 }
14078
14079 if (raw != NULL) {
14080 dns_zone_detach(&raw);
14081 }
14082 dns_zone_detach(&zone);
14083 isc_mem_put(named_g_mctx, dz, sizeof(*dz));
14084 isc_task_detach(&task);
14085 }
14086
14087 /*
14088 * Act on a "delzone" command from the command channel.
14089 */
14090 isc_result_t
named_server_delzone(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14091 named_server_delzone(named_server_t *server, isc_lex_t *lex,
14092 isc_buffer_t **text) {
14093 isc_result_t result, tresult;
14094 dns_zone_t *zone = NULL;
14095 dns_zone_t *raw = NULL;
14096 dns_zone_t *mayberaw;
14097 dns_view_t *view = NULL;
14098 char zonename[DNS_NAME_FORMATSIZE];
14099 bool cleanup = false;
14100 const char *ptr;
14101 bool added;
14102 ns_dzctx_t *dz = NULL;
14103 isc_event_t *dzevent = NULL;
14104 isc_task_t *task = NULL;
14105
14106 REQUIRE(text != NULL);
14107
14108 /* Skip the command name. */
14109 ptr = next_token(lex, text);
14110 if (ptr == NULL) {
14111 return (ISC_R_UNEXPECTEDEND);
14112 }
14113
14114 /* Find out what we are to do. */
14115 ptr = next_token(lex, text);
14116 if (ptr == NULL) {
14117 return (ISC_R_UNEXPECTEDEND);
14118 }
14119
14120 if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) {
14121 cleanup = true;
14122 ptr = next_token(lex, text);
14123 }
14124
14125 CHECK(zone_from_args(server, lex, ptr, &zone, zonename, text, false));
14126 if (zone == NULL) {
14127 result = ISC_R_UNEXPECTEDEND;
14128 goto cleanup;
14129 }
14130
14131 INSIST(zonename != NULL);
14132
14133 /* Is this a policy zone? */
14134 if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
14135 TCHECK(putstr(text, "zone '"));
14136 TCHECK(putstr(text, zonename));
14137 TCHECK(putstr(text,
14138 "' cannot be deleted: response-policy zone."));
14139 result = ISC_R_FAILURE;
14140 goto cleanup;
14141 }
14142
14143 view = dns_zone_getview(zone);
14144 if (dns_zone_gettype(zone) == dns_zone_redirect) {
14145 dns_zone_detach(&view->redirect);
14146 } else {
14147 CHECK(dns_zt_unmount(view->zonetable, zone));
14148 }
14149
14150 /* Send cleanup event */
14151 dz = isc_mem_get(named_g_mctx, sizeof(*dz));
14152
14153 dz->cleanup = cleanup;
14154 dz->zone = NULL;
14155 dns_zone_attach(zone, &dz->zone);
14156 dzevent = isc_event_allocate(named_g_mctx, server, NAMED_EVENT_DELZONE,
14157 rmzone, dz, sizeof(isc_event_t));
14158
14159 dns_zone_gettask(zone, &task);
14160 isc_task_send(task, &dzevent);
14161 dz = NULL;
14162
14163 /* Inform user about cleaning up stub/slave zone files */
14164 dns_zone_getraw(zone, &raw);
14165 mayberaw = (raw != NULL) ? raw : zone;
14166
14167 added = dns_zone_getadded(zone);
14168 if (!added) {
14169 TCHECK(putstr(text, "zone '"));
14170 TCHECK(putstr(text, zonename));
14171 TCHECK(putstr(text, "' is no longer active and will be "
14172 "deleted.\n"));
14173 TCHECK(putstr(text, "To keep it from returning "));
14174 TCHECK(putstr(text, "when the server is restarted, it\n"));
14175 TCHECK(putstr(text, "must also be removed from named.conf."));
14176 } else if (cleanup) {
14177 TCHECK(putstr(text, "zone '"));
14178 TCHECK(putstr(text, zonename));
14179 TCHECK(putstr(text, "' and associated files will be deleted."));
14180 } else if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
14181 dns_zone_gettype(mayberaw) == dns_zone_mirror ||
14182 dns_zone_gettype(mayberaw) == dns_zone_stub)
14183 {
14184 bool first;
14185 const char *file;
14186
14187 TCHECK(putstr(text, "zone '"));
14188 TCHECK(putstr(text, zonename));
14189 TCHECK(putstr(text, "' will be deleted."));
14190
14191 file = dns_zone_getfile(mayberaw);
14192 first = inuse(file, true, text);
14193
14194 file = dns_zone_getjournal(mayberaw);
14195 first = inuse(file, first, text);
14196
14197 if (zone != mayberaw) {
14198 file = dns_zone_getfile(zone);
14199 first = inuse(file, first, text);
14200
14201 file = dns_zone_getjournal(zone);
14202 (void)inuse(file, first, text);
14203 }
14204 }
14205
14206 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14207 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14208 "zone %s scheduled for removal via delzone", zonename);
14209
14210 /* Removing a zone counts as reconfiguration */
14211 CHECK(isc_time_now(&named_g_configtime));
14212
14213 result = ISC_R_SUCCESS;
14214
14215 cleanup:
14216 if (isc_buffer_usedlength(*text) > 0) {
14217 (void)putnull(text);
14218 }
14219 if (raw != NULL) {
14220 dns_zone_detach(&raw);
14221 }
14222 if (zone != NULL) {
14223 dns_zone_detach(&zone);
14224 }
14225
14226 return (result);
14227 }
14228
14229 static const cfg_obj_t *
find_name_in_list_from_map(const cfg_obj_t * config,const char * map_key_for_list,const char * name,bool redirect)14230 find_name_in_list_from_map(const cfg_obj_t *config,
14231 const char *map_key_for_list, const char *name,
14232 bool redirect) {
14233 const cfg_obj_t *list = NULL;
14234 const cfg_listelt_t *element;
14235 const cfg_obj_t *obj = NULL;
14236 dns_fixedname_t fixed1, fixed2;
14237 dns_name_t *name1 = NULL, *name2 = NULL;
14238 isc_result_t result;
14239
14240 if (strcmp(map_key_for_list, "zone") == 0) {
14241 name1 = dns_fixedname_initname(&fixed1);
14242 name2 = dns_fixedname_initname(&fixed2);
14243 result = dns_name_fromstring(name1, name, 0, NULL);
14244 RUNTIME_CHECK(result == ISC_R_SUCCESS);
14245 }
14246
14247 cfg_map_get(config, map_key_for_list, &list);
14248 for (element = cfg_list_first(list); element != NULL;
14249 element = cfg_list_next(element))
14250 {
14251 const char *vname;
14252
14253 obj = cfg_listelt_value(element);
14254 INSIST(obj != NULL);
14255 vname = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
14256 if (vname == NULL) {
14257 obj = NULL;
14258 continue;
14259 }
14260
14261 if (name1 != NULL) {
14262 result = dns_name_fromstring(name2, vname, 0, NULL);
14263 if (result == ISC_R_SUCCESS &&
14264 dns_name_equal(name1, name2))
14265 {
14266 const cfg_obj_t *zoptions;
14267 const cfg_obj_t *typeobj = NULL;
14268 zoptions = cfg_tuple_get(obj, "options");
14269
14270 if (zoptions != NULL) {
14271 cfg_map_get(zoptions, "type", &typeobj);
14272 }
14273 if (redirect && typeobj != NULL &&
14274 strcasecmp(cfg_obj_asstring(typeobj),
14275 "redirect") == 0)
14276 {
14277 break;
14278 } else if (!redirect) {
14279 break;
14280 }
14281 }
14282 } else if (strcasecmp(vname, name) == 0) {
14283 break;
14284 }
14285
14286 obj = NULL;
14287 }
14288
14289 return (obj);
14290 }
14291
14292 static void
emitzone(void * arg,const char * buf,int len)14293 emitzone(void *arg, const char *buf, int len) {
14294 ns_dzarg_t *dzarg = arg;
14295 isc_result_t result;
14296
14297 REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
14298 result = putmem(dzarg->text, buf, len);
14299 if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
14300 dzarg->result = result;
14301 }
14302 }
14303
14304 /*
14305 * Act on a "showzone" command from the command channel.
14306 */
14307 isc_result_t
named_server_showzone(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14308 named_server_showzone(named_server_t *server, isc_lex_t *lex,
14309 isc_buffer_t **text) {
14310 isc_result_t result;
14311 const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
14312 char zonename[DNS_NAME_FORMATSIZE];
14313 const cfg_obj_t *map;
14314 dns_view_t *view = NULL;
14315 dns_zone_t *zone = NULL;
14316 ns_cfgctx_t *cfg = NULL;
14317 #ifdef HAVE_LMDB
14318 cfg_obj_t *nzconfig = NULL;
14319 #endif /* HAVE_LMDB */
14320 bool added, redirect;
14321 ns_dzarg_t dzarg;
14322
14323 REQUIRE(text != NULL);
14324
14325 /* Parse parameters */
14326 CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
14327 if (zone == NULL) {
14328 result = ISC_R_UNEXPECTEDEND;
14329 goto cleanup;
14330 }
14331
14332 redirect = dns_zone_gettype(zone) == dns_zone_redirect;
14333 added = dns_zone_getadded(zone);
14334 view = dns_zone_getview(zone);
14335 dns_zone_detach(&zone);
14336
14337 cfg = (ns_cfgctx_t *)view->new_zone_config;
14338 if (cfg == NULL) {
14339 result = ISC_R_FAILURE;
14340 goto cleanup;
14341 }
14342
14343 if (!added) {
14344 /* Find the view statement */
14345 vconfig = find_name_in_list_from_map(cfg->config, "view",
14346 view->name, false);
14347
14348 /* Find the zone statement */
14349 if (vconfig != NULL) {
14350 map = cfg_tuple_get(vconfig, "options");
14351 } else {
14352 map = cfg->config;
14353 }
14354
14355 zconfig = find_name_in_list_from_map(map, "zone", zonename,
14356 redirect);
14357 }
14358
14359 #ifndef HAVE_LMDB
14360 if (zconfig == NULL && cfg->nzf_config != NULL) {
14361 zconfig = find_name_in_list_from_map(cfg->nzf_config, "zone",
14362 zonename, redirect);
14363 }
14364 #else /* HAVE_LMDB */
14365 if (zconfig == NULL) {
14366 const cfg_obj_t *zlist = NULL;
14367 CHECK(get_newzone_config(view, zonename, &nzconfig));
14368 CHECK(cfg_map_get(nzconfig, "zone", &zlist));
14369 if (!cfg_obj_islist(zlist)) {
14370 CHECK(ISC_R_FAILURE);
14371 }
14372
14373 zconfig = cfg_listelt_value(cfg_list_first(zlist));
14374 }
14375 #endif /* HAVE_LMDB */
14376
14377 if (zconfig == NULL) {
14378 CHECK(ISC_R_NOTFOUND);
14379 }
14380
14381 CHECK(putstr(text, "zone "));
14382 dzarg.magic = DZARG_MAGIC;
14383 dzarg.text = text;
14384 dzarg.result = ISC_R_SUCCESS;
14385 cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
14386 CHECK(dzarg.result);
14387
14388 CHECK(putstr(text, ";"));
14389
14390 result = ISC_R_SUCCESS;
14391
14392 cleanup:
14393 #ifdef HAVE_LMDB
14394 if (nzconfig != NULL) {
14395 cfg_obj_destroy(named_g_addparser, &nzconfig);
14396 }
14397 #endif /* HAVE_LMDB */
14398 if (isc_buffer_usedlength(*text) > 0) {
14399 (void)putnull(text);
14400 }
14401
14402 return (result);
14403 }
14404
14405 static void
newzone_cfgctx_destroy(void ** cfgp)14406 newzone_cfgctx_destroy(void **cfgp) {
14407 ns_cfgctx_t *cfg;
14408
14409 REQUIRE(cfgp != NULL && *cfgp != NULL);
14410
14411 cfg = *cfgp;
14412
14413 if (cfg->conf_parser != NULL) {
14414 if (cfg->config != NULL) {
14415 cfg_obj_destroy(cfg->conf_parser, &cfg->config);
14416 }
14417 if (cfg->vconfig != NULL) {
14418 cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
14419 }
14420 cfg_parser_destroy(&cfg->conf_parser);
14421 }
14422 if (cfg->add_parser != NULL) {
14423 if (cfg->nzf_config != NULL) {
14424 cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
14425 }
14426 cfg_parser_destroy(&cfg->add_parser);
14427 }
14428
14429 if (cfg->actx != NULL) {
14430 cfg_aclconfctx_detach(&cfg->actx);
14431 }
14432
14433 isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
14434 *cfgp = NULL;
14435 }
14436
14437 isc_result_t
named_server_signing(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14438 named_server_signing(named_server_t *server, isc_lex_t *lex,
14439 isc_buffer_t **text) {
14440 isc_result_t result = ISC_R_SUCCESS;
14441 dns_zone_t *zone = NULL;
14442 dns_name_t *origin;
14443 dns_db_t *db = NULL;
14444 dns_dbnode_t *node = NULL;
14445 dns_dbversion_t *version = NULL;
14446 dns_rdatatype_t privatetype;
14447 dns_rdataset_t privset;
14448 bool first = true;
14449 bool list = false, clear = false;
14450 bool chain = false;
14451 bool setserial = false;
14452 bool resalt = false;
14453 uint32_t serial = 0;
14454 char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
14455 unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
14456 unsigned char salt[255];
14457 const char *ptr;
14458 size_t n;
14459
14460 REQUIRE(text != NULL);
14461
14462 dns_rdataset_init(&privset);
14463
14464 /* Skip the command name. */
14465 ptr = next_token(lex, text);
14466 if (ptr == NULL) {
14467 return (ISC_R_UNEXPECTEDEND);
14468 }
14469
14470 /* Find out what we are to do. */
14471 ptr = next_token(lex, text);
14472 if (ptr == NULL) {
14473 return (ISC_R_UNEXPECTEDEND);
14474 }
14475
14476 if (strcasecmp(ptr, "-list") == 0) {
14477 list = true;
14478 } else if ((strcasecmp(ptr, "-clear") == 0) ||
14479 (strcasecmp(ptr, "-clean") == 0))
14480 {
14481 clear = true;
14482 ptr = next_token(lex, text);
14483 if (ptr == NULL) {
14484 return (ISC_R_UNEXPECTEDEND);
14485 }
14486 strlcpy(keystr, ptr, sizeof(keystr));
14487 } else if (strcasecmp(ptr, "-nsec3param") == 0) {
14488 char hashbuf[64], flagbuf[64], iterbuf[64];
14489 char nbuf[256];
14490
14491 chain = true;
14492 ptr = next_token(lex, text);
14493 if (ptr == NULL) {
14494 return (ISC_R_UNEXPECTEDEND);
14495 }
14496
14497 if (strcasecmp(ptr, "none") == 0) {
14498 hash = 0;
14499 } else {
14500 strlcpy(hashbuf, ptr, sizeof(hashbuf));
14501
14502 ptr = next_token(lex, text);
14503 if (ptr == NULL) {
14504 return (ISC_R_UNEXPECTEDEND);
14505 }
14506 strlcpy(flagbuf, ptr, sizeof(flagbuf));
14507
14508 ptr = next_token(lex, text);
14509 if (ptr == NULL) {
14510 return (ISC_R_UNEXPECTEDEND);
14511 }
14512 strlcpy(iterbuf, ptr, sizeof(iterbuf));
14513 n = snprintf(nbuf, sizeof(nbuf), "%s %s %s", hashbuf,
14514 flagbuf, iterbuf);
14515 if (n == sizeof(nbuf)) {
14516 return (ISC_R_NOSPACE);
14517 }
14518 n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
14519 if (n != 3U) {
14520 return (ISC_R_BADNUMBER);
14521 }
14522
14523 if (hash > 0xffU || flags > 0xffU ||
14524 iter > dns_nsec3_maxiterations())
14525 {
14526 return (ISC_R_RANGE);
14527 }
14528
14529 ptr = next_token(lex, text);
14530 if (ptr == NULL) {
14531 return (ISC_R_UNEXPECTEDEND);
14532 } else if (strcasecmp(ptr, "auto") == 0) {
14533 /* Auto-generate a random salt.
14534 * XXXMUKS: This currently uses the
14535 * minimum recommended length by RFC
14536 * 5155 (64 bits). It should be made
14537 * configurable.
14538 */
14539 saltlen = 8;
14540 resalt = true;
14541 } else if (strcmp(ptr, "-") != 0) {
14542 isc_buffer_t buf;
14543
14544 isc_buffer_init(&buf, salt, sizeof(salt));
14545 CHECK(isc_hex_decodestring(ptr, &buf));
14546 saltlen = isc_buffer_usedlength(&buf);
14547 }
14548 }
14549 } else if (strcasecmp(ptr, "-serial") == 0) {
14550 ptr = next_token(lex, text);
14551 if (ptr == NULL) {
14552 return (ISC_R_UNEXPECTEDEND);
14553 }
14554 CHECK(isc_parse_uint32(&serial, ptr, 10));
14555 setserial = true;
14556 } else {
14557 CHECK(DNS_R_SYNTAX);
14558 }
14559
14560 CHECK(zone_from_args(server, lex, NULL, &zone, NULL, text, false));
14561 if (zone == NULL) {
14562 CHECK(ISC_R_UNEXPECTEDEND);
14563 }
14564
14565 if (dns_zone_getkasp(zone) != NULL) {
14566 (void)putstr(text, "zone uses dnssec-policy, use rndc dnssec "
14567 "command instead");
14568 (void)putnull(text);
14569 goto cleanup;
14570 }
14571
14572 if (clear) {
14573 CHECK(dns_zone_keydone(zone, keystr));
14574 (void)putstr(text, "request queued");
14575 (void)putnull(text);
14576 } else if (chain) {
14577 CHECK(dns_zone_setnsec3param(
14578 zone, (uint8_t)hash, (uint8_t)flags, iter,
14579 (uint8_t)saltlen, salt, true, resalt));
14580 (void)putstr(text, "nsec3param request queued");
14581 (void)putnull(text);
14582 } else if (setserial) {
14583 CHECK(dns_zone_setserial(zone, serial));
14584 (void)putstr(text, "serial request queued");
14585 (void)putnull(text);
14586 } else if (list) {
14587 privatetype = dns_zone_getprivatetype(zone);
14588 origin = dns_zone_getorigin(zone);
14589 CHECK(dns_zone_getdb(zone, &db));
14590 CHECK(dns_db_findnode(db, origin, false, &node));
14591 dns_db_currentversion(db, &version);
14592
14593 result = dns_db_findrdataset(db, node, version, privatetype,
14594 dns_rdatatype_none, 0, &privset,
14595 NULL);
14596 if (result == ISC_R_NOTFOUND) {
14597 (void)putstr(text, "No signing records found");
14598 (void)putnull(text);
14599 result = ISC_R_SUCCESS;
14600 goto cleanup;
14601 }
14602
14603 for (result = dns_rdataset_first(&privset);
14604 result == ISC_R_SUCCESS;
14605 result = dns_rdataset_next(&privset))
14606 {
14607 dns_rdata_t priv = DNS_RDATA_INIT;
14608 /*
14609 * In theory, the output buffer could hold a full RDATA
14610 * record which is 16-bit and then some text around
14611 * it
14612 */
14613 char output[UINT16_MAX + BUFSIZ];
14614 isc_buffer_t buf;
14615
14616 dns_rdataset_current(&privset, &priv);
14617
14618 isc_buffer_init(&buf, output, sizeof(output));
14619 CHECK(dns_private_totext(&priv, &buf));
14620 if (!first) {
14621 CHECK(putstr(text, "\n"));
14622 }
14623 CHECK(putstr(text, output));
14624 first = false;
14625 }
14626 if (!first) {
14627 CHECK(putnull(text));
14628 }
14629
14630 if (result == ISC_R_NOMORE) {
14631 result = ISC_R_SUCCESS;
14632 }
14633 }
14634
14635 cleanup:
14636 if (dns_rdataset_isassociated(&privset)) {
14637 dns_rdataset_disassociate(&privset);
14638 }
14639 if (node != NULL) {
14640 dns_db_detachnode(db, &node);
14641 }
14642 if (version != NULL) {
14643 dns_db_closeversion(db, &version, false);
14644 }
14645 if (db != NULL) {
14646 dns_db_detach(&db);
14647 }
14648 if (zone != NULL) {
14649 dns_zone_detach(&zone);
14650 }
14651
14652 return (result);
14653 }
14654
14655 static bool
argcheck(char * cmd,const char * full)14656 argcheck(char *cmd, const char *full) {
14657 size_t l;
14658
14659 if (cmd == NULL || cmd[0] != '-') {
14660 return (false);
14661 }
14662
14663 cmd++;
14664 l = strlen(cmd);
14665 if (l > strlen(full) || strncasecmp(cmd, full, l) != 0) {
14666 return (false);
14667 }
14668
14669 return (true);
14670 }
14671
14672 isc_result_t
named_server_dnssec(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)14673 named_server_dnssec(named_server_t *server, isc_lex_t *lex,
14674 isc_buffer_t **text) {
14675 isc_result_t result = ISC_R_SUCCESS;
14676 dns_zone_t *zone = NULL;
14677 dns_kasp_t *kasp = NULL;
14678 dns_dnsseckeylist_t keys;
14679 dns_dnsseckey_t *key;
14680 char *ptr, *zonetext = NULL;
14681 const char *msg = NULL;
14682 /* variables for -checkds */
14683 bool checkds = false, dspublish = false;
14684 /* variables for -rollover */
14685 bool rollover = false;
14686 /* variables for -key */
14687 bool use_keyid = false;
14688 dns_keytag_t keyid = 0;
14689 uint8_t algorithm = 0;
14690 /* variables for -status */
14691 bool status = false;
14692 char output[4096];
14693 isc_stdtime_t now, when;
14694 isc_time_t timenow, timewhen;
14695 const char *dir;
14696 dns_db_t *db = NULL;
14697 dns_dbversion_t *version = NULL;
14698
14699 REQUIRE(text != NULL);
14700
14701 /* Skip the command name. */
14702 ptr = next_token(lex, text);
14703 if (ptr == NULL) {
14704 return (ISC_R_UNEXPECTEDEND);
14705 }
14706
14707 /* Find out what we are to do. */
14708 ptr = next_token(lex, text);
14709 if (ptr == NULL) {
14710 return (ISC_R_UNEXPECTEDEND);
14711 }
14712
14713 /* Initialize current time and key list. */
14714 TIME_NOW(&timenow);
14715 now = isc_time_seconds(&timenow);
14716 when = now;
14717
14718 ISC_LIST_INIT(keys);
14719
14720 if (strcasecmp(ptr, "-status") == 0) {
14721 status = true;
14722 } else if (strcasecmp(ptr, "-rollover") == 0) {
14723 rollover = true;
14724 } else if (strcasecmp(ptr, "-checkds") == 0) {
14725 checkds = true;
14726 } else {
14727 CHECK(DNS_R_SYNTAX);
14728 }
14729
14730 if (rollover || checkds) {
14731 /* Check for options */
14732 for (;;) {
14733 ptr = next_token(lex, text);
14734 if (ptr == NULL) {
14735 msg = "Bad format";
14736 CHECK(ISC_R_UNEXPECTEDEND);
14737 } else if (argcheck(ptr, "alg")) {
14738 isc_consttextregion_t alg;
14739 ptr = next_token(lex, text);
14740 if (ptr == NULL) {
14741 msg = "No key algorithm specified";
14742 CHECK(ISC_R_UNEXPECTEDEND);
14743 }
14744 alg.base = ptr;
14745 alg.length = strlen(alg.base);
14746 result = dns_secalg_fromtext(
14747 &algorithm, (isc_textregion_t *)&alg);
14748 if (result != ISC_R_SUCCESS) {
14749 msg = "Bad algorithm";
14750 CHECK(DNS_R_SYNTAX);
14751 }
14752 continue;
14753 } else if (argcheck(ptr, "key")) {
14754 uint16_t id;
14755 ptr = next_token(lex, text);
14756 if (ptr == NULL) {
14757 msg = "No key identifier specified";
14758 CHECK(ISC_R_UNEXPECTEDEND);
14759 }
14760 CHECK(isc_parse_uint16(&id, ptr, 10));
14761 keyid = (dns_keytag_t)id;
14762 use_keyid = true;
14763 continue;
14764 } else if (argcheck(ptr, "when")) {
14765 uint32_t tw;
14766 ptr = next_token(lex, text);
14767 if (ptr == NULL) {
14768 msg = "No time specified";
14769 CHECK(ISC_R_UNEXPECTEDEND);
14770 }
14771 CHECK(dns_time32_fromtext(ptr, &tw));
14772 when = (isc_stdtime_t)tw;
14773 continue;
14774 } else if (ptr[0] == '-') {
14775 msg = "Unknown option";
14776 CHECK(DNS_R_SYNTAX);
14777 } else if (checkds) {
14778 /*
14779 * No arguments provided, so we must be
14780 * parsing "published|withdrawn".
14781 */
14782 if (strcasecmp(ptr, "published") == 0) {
14783 dspublish = true;
14784 } else if (strcasecmp(ptr, "withdrawn") != 0) {
14785 CHECK(DNS_R_SYNTAX);
14786 }
14787 } else if (rollover) {
14788 /*
14789 * No arguments provided, so we must be
14790 * parsing the zone.
14791 */
14792 zonetext = ptr;
14793 }
14794 break;
14795 }
14796
14797 if (rollover && !use_keyid) {
14798 msg = "Key id is required when scheduling rollover";
14799 CHECK(DNS_R_SYNTAX);
14800 }
14801
14802 if (algorithm > 0 && !use_keyid) {
14803 msg = "Key id is required when setting algorithm";
14804 CHECK(DNS_R_SYNTAX);
14805 }
14806 }
14807
14808 /* Get zone. */
14809 CHECK(zone_from_args(server, lex, zonetext, &zone, NULL, text, false));
14810 if (zone == NULL) {
14811 msg = "Zone not found";
14812 CHECK(ISC_R_UNEXPECTEDEND);
14813 }
14814
14815 /* Trailing garbage? */
14816 ptr = next_token(lex, text);
14817 if (ptr != NULL) {
14818 msg = "Too many arguments";
14819 CHECK(DNS_R_SYNTAX);
14820 }
14821
14822 /* Get dnssec-policy. */
14823 kasp = dns_zone_getkasp(zone);
14824 if (kasp == NULL) {
14825 msg = "Zone does not have dnssec-policy";
14826 goto cleanup;
14827 }
14828
14829 /* Get DNSSEC keys. */
14830 dir = dns_zone_getkeydirectory(zone);
14831 CHECK(dns_zone_getdb(zone, &db));
14832 dns_db_currentversion(db, &version);
14833 LOCK(&kasp->lock);
14834 result = dns_zone_getdnsseckeys(zone, db, version, now, &keys);
14835 UNLOCK(&kasp->lock);
14836 if (result != ISC_R_SUCCESS) {
14837 if (result != ISC_R_NOTFOUND) {
14838 goto cleanup;
14839 }
14840 }
14841
14842 if (status) {
14843 /*
14844 * Output the DNSSEC status of the key and signing policy.
14845 */
14846 LOCK(&kasp->lock);
14847 dns_keymgr_status(kasp, &keys, now, &output[0], sizeof(output));
14848 UNLOCK(&kasp->lock);
14849 CHECK(putstr(text, output));
14850 } else if (checkds) {
14851 /*
14852 * Mark DS record has been seen, so it may move to the
14853 * rumoured state.
14854 */
14855 char whenbuf[80];
14856 isc_time_set(&timewhen, when, 0);
14857 isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
14858 isc_result_t ret;
14859
14860 LOCK(&kasp->lock);
14861 if (use_keyid) {
14862 result = dns_keymgr_checkds_id(kasp, &keys, dir, now,
14863 when, dspublish, keyid,
14864 (unsigned int)algorithm);
14865 } else {
14866 result = dns_keymgr_checkds(kasp, &keys, dir, now, when,
14867 dspublish);
14868 }
14869 UNLOCK(&kasp->lock);
14870
14871 switch (result) {
14872 case ISC_R_SUCCESS:
14873 /*
14874 * Rekey after checkds command because the next key
14875 * event may have changed.
14876 */
14877 dns_zone_rekey(zone, false);
14878
14879 if (use_keyid) {
14880 char tagbuf[6];
14881 snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
14882 CHECK(putstr(text, "KSK "));
14883 CHECK(putstr(text, tagbuf));
14884 CHECK(putstr(text, ": "));
14885 }
14886 CHECK(putstr(text, "Marked DS as "));
14887 if (dspublish) {
14888 CHECK(putstr(text, "published "));
14889 } else {
14890 CHECK(putstr(text, "withdrawn "));
14891 }
14892 CHECK(putstr(text, "since "));
14893 CHECK(putstr(text, whenbuf));
14894 break;
14895 case DNS_R_TOOMANYKEYS:
14896 CHECK(putstr(text,
14897 "Error: multiple possible keys found, "
14898 "retry command with -key id"));
14899 break;
14900 default:
14901 ret = result;
14902 CHECK(putstr(text,
14903 "Error executing checkds command: "));
14904 CHECK(putstr(text, isc_result_totext(ret)));
14905 break;
14906 }
14907 } else if (rollover) {
14908 /*
14909 * Manually rollover a key.
14910 */
14911 char whenbuf[80];
14912 isc_time_set(&timewhen, when, 0);
14913 isc_time_formattimestamp(&timewhen, whenbuf, sizeof(whenbuf));
14914 isc_result_t ret;
14915
14916 LOCK(&kasp->lock);
14917 result = dns_keymgr_rollover(kasp, &keys, dir, now, when, keyid,
14918 (unsigned int)algorithm);
14919 UNLOCK(&kasp->lock);
14920
14921 switch (result) {
14922 case ISC_R_SUCCESS:
14923 /*
14924 * Rekey after rollover command because the next key
14925 * event may have changed.
14926 */
14927 dns_zone_rekey(zone, false);
14928
14929 if (use_keyid) {
14930 char tagbuf[6];
14931 snprintf(tagbuf, sizeof(tagbuf), "%u", keyid);
14932 CHECK(putstr(text, "Key "));
14933 CHECK(putstr(text, tagbuf));
14934 CHECK(putstr(text, ": "));
14935 }
14936 CHECK(putstr(text, "Rollover scheduled on "));
14937 CHECK(putstr(text, whenbuf));
14938 break;
14939 case DNS_R_TOOMANYKEYS:
14940 CHECK(putstr(text,
14941 "Error: multiple possible keys found, "
14942 "retry command with -alg algorithm"));
14943 break;
14944 default:
14945 ret = result;
14946 CHECK(putstr(text,
14947 "Error executing rollover command: "));
14948 CHECK(putstr(text, isc_result_totext(ret)));
14949 break;
14950 }
14951 }
14952 CHECK(putnull(text));
14953
14954 cleanup:
14955 if (msg != NULL) {
14956 (void)putstr(text, msg);
14957 (void)putnull(text);
14958 }
14959
14960 if (version != NULL) {
14961 dns_db_closeversion(db, &version, false);
14962 }
14963 if (db != NULL) {
14964 dns_db_detach(&db);
14965 }
14966
14967 while (!ISC_LIST_EMPTY(keys)) {
14968 key = ISC_LIST_HEAD(keys);
14969 ISC_LIST_UNLINK(keys, key, link);
14970 dns_dnsseckey_destroy(dns_zone_getmctx(zone), &key);
14971 }
14972
14973 if (zone != NULL) {
14974 dns_zone_detach(&zone);
14975 }
14976
14977 return (result);
14978 }
14979
14980 static isc_result_t
putmem(isc_buffer_t ** b,const char * str,size_t len)14981 putmem(isc_buffer_t **b, const char *str, size_t len) {
14982 isc_result_t result;
14983
14984 result = isc_buffer_reserve(b, (unsigned int)len);
14985 if (result != ISC_R_SUCCESS) {
14986 return (ISC_R_NOSPACE);
14987 }
14988
14989 isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
14990 return (ISC_R_SUCCESS);
14991 }
14992
14993 static isc_result_t
putstr(isc_buffer_t ** b,const char * str)14994 putstr(isc_buffer_t **b, const char *str) {
14995 return (putmem(b, str, strlen(str)));
14996 }
14997
14998 static isc_result_t
putuint8(isc_buffer_t ** b,uint8_t val)14999 putuint8(isc_buffer_t **b, uint8_t val) {
15000 isc_result_t result;
15001
15002 result = isc_buffer_reserve(b, 1);
15003 if (result != ISC_R_SUCCESS) {
15004 return (ISC_R_NOSPACE);
15005 }
15006
15007 isc_buffer_putuint8(*b, val);
15008 return (ISC_R_SUCCESS);
15009 }
15010
15011 static isc_result_t
putnull(isc_buffer_t ** b)15012 putnull(isc_buffer_t **b) {
15013 return (putuint8(b, 0));
15014 }
15015
15016 isc_result_t
named_server_zonestatus(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)15017 named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
15018 isc_buffer_t **text) {
15019 isc_result_t result = ISC_R_SUCCESS;
15020 dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
15021 const char *type, *file;
15022 char zonename[DNS_NAME_FORMATSIZE];
15023 uint32_t serial, signed_serial, nodes;
15024 char serbuf[16], sserbuf[16], nodebuf[16];
15025 char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2];
15026 char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15027 char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15028 char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15029 char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15030 char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15031 isc_time_t loadtime, expiretime, refreshtime;
15032 isc_time_t refreshkeytime, resigntime;
15033 dns_zonetype_t zonetype;
15034 bool dynamic = false, frozen = false;
15035 bool hasraw = false;
15036 bool secure, maintain, allow;
15037 dns_db_t *db = NULL, *rawdb = NULL;
15038 char **incfiles = NULL;
15039 int nfiles = 0;
15040
15041 REQUIRE(text != NULL);
15042
15043 isc_time_settoepoch(&loadtime);
15044 isc_time_settoepoch(&refreshtime);
15045 isc_time_settoepoch(&expiretime);
15046 isc_time_settoepoch(&refreshkeytime);
15047 isc_time_settoepoch(&resigntime);
15048
15049 CHECK(zone_from_args(server, lex, NULL, &zone, zonename, text, true));
15050 if (zone == NULL) {
15051 result = ISC_R_UNEXPECTEDEND;
15052 goto cleanup;
15053 }
15054
15055 /* Inline signing? */
15056 CHECK(dns_zone_getdb(zone, &db));
15057 dns_zone_getraw(zone, &raw);
15058 hasraw = (raw != NULL);
15059 if (hasraw) {
15060 mayberaw = raw;
15061 zonetype = dns_zone_gettype(raw);
15062 CHECK(dns_zone_getdb(raw, &rawdb));
15063 } else {
15064 mayberaw = zone;
15065 zonetype = dns_zone_gettype(zone);
15066 }
15067
15068 type = dns_zonetype_name(zonetype);
15069
15070 /* Serial number */
15071 result = dns_zone_getserial(mayberaw, &serial);
15072
15073 /* This is to mirror old behavior with dns_zone_getserial */
15074 if (result != ISC_R_SUCCESS) {
15075 serial = 0;
15076 }
15077
15078 snprintf(serbuf, sizeof(serbuf), "%u", serial);
15079 if (hasraw) {
15080 result = dns_zone_getserial(zone, &signed_serial);
15081 if (result != ISC_R_SUCCESS) {
15082 serial = 0;
15083 }
15084 snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial);
15085 }
15086
15087 /* Database node count */
15088 nodes = dns_db_nodecount(hasraw ? rawdb : db);
15089 snprintf(nodebuf, sizeof(nodebuf), "%u", nodes);
15090
15091 /* Security */
15092 secure = dns_db_issecure(db);
15093 allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
15094 maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
15095
15096 /* Master files */
15097 file = dns_zone_getfile(mayberaw);
15098 nfiles = dns_zone_getincludes(mayberaw, &incfiles);
15099
15100 /* Load time */
15101 dns_zone_getloadtime(zone, &loadtime);
15102 isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
15103
15104 /* Refresh/expire times */
15105 if (zonetype == dns_zone_secondary || zonetype == dns_zone_mirror ||
15106 zonetype == dns_zone_stub || zonetype == dns_zone_redirect)
15107 {
15108 dns_zone_getexpiretime(mayberaw, &expiretime);
15109 isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
15110 dns_zone_getrefreshtime(mayberaw, &refreshtime);
15111 isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
15112 }
15113
15114 /* Key refresh time */
15115 if (zonetype == dns_zone_primary ||
15116 (zonetype == dns_zone_secondary && hasraw))
15117 {
15118 dns_zone_getrefreshkeytime(zone, &refreshkeytime);
15119 isc_time_formathttptimestamp(&refreshkeytime, kbuf,
15120 sizeof(kbuf));
15121 }
15122
15123 /* Dynamic? */
15124 if (zonetype == dns_zone_primary) {
15125 dynamic = dns_zone_isdynamic(mayberaw, true);
15126 frozen = dynamic && !dns_zone_isdynamic(mayberaw, false);
15127 }
15128
15129 /* Next resign event */
15130 if (secure &&
15131 (zonetype == dns_zone_primary ||
15132 (zonetype == dns_zone_secondary && hasraw)) &&
15133 ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0))
15134 {
15135 dns_name_t *name;
15136 dns_fixedname_t fixed;
15137 dns_rdataset_t next;
15138
15139 dns_rdataset_init(&next);
15140 name = dns_fixedname_initname(&fixed);
15141
15142 result = dns_db_getsigningtime(db, &next, name);
15143 if (result == ISC_R_SUCCESS) {
15144 isc_stdtime_t timenow;
15145 char namebuf[DNS_NAME_FORMATSIZE];
15146 char typebuf[DNS_RDATATYPE_FORMATSIZE];
15147
15148 isc_stdtime_get(&timenow);
15149 dns_name_format(name, namebuf, sizeof(namebuf));
15150 dns_rdatatype_format(next.covers, typebuf,
15151 sizeof(typebuf));
15152 snprintf(resignbuf, sizeof(resignbuf), "%s/%s", namebuf,
15153 typebuf);
15154 isc_time_set(
15155 &resigntime,
15156 next.resign -
15157 dns_zone_getsigresigninginterval(zone),
15158 0);
15159 isc_time_formathttptimestamp(&resigntime, rtbuf,
15160 sizeof(rtbuf));
15161 dns_rdataset_disassociate(&next);
15162 }
15163 }
15164
15165 /* Create text */
15166 CHECK(putstr(text, "name: "));
15167 CHECK(putstr(text, zonename));
15168
15169 CHECK(putstr(text, "\ntype: "));
15170 CHECK(putstr(text, type));
15171
15172 if (file != NULL) {
15173 int i;
15174 CHECK(putstr(text, "\nfiles: "));
15175 CHECK(putstr(text, file));
15176 for (i = 0; i < nfiles; i++) {
15177 CHECK(putstr(text, ", "));
15178 if (incfiles[i] != NULL) {
15179 CHECK(putstr(text, incfiles[i]));
15180 }
15181 }
15182 }
15183
15184 CHECK(putstr(text, "\nserial: "));
15185 CHECK(putstr(text, serbuf));
15186 if (hasraw) {
15187 CHECK(putstr(text, "\nsigned serial: "));
15188 CHECK(putstr(text, sserbuf));
15189 }
15190
15191 CHECK(putstr(text, "\nnodes: "));
15192 CHECK(putstr(text, nodebuf));
15193
15194 if (!isc_time_isepoch(&loadtime)) {
15195 CHECK(putstr(text, "\nlast loaded: "));
15196 CHECK(putstr(text, lbuf));
15197 }
15198
15199 if (!isc_time_isepoch(&refreshtime)) {
15200 CHECK(putstr(text, "\nnext refresh: "));
15201 CHECK(putstr(text, rbuf));
15202 }
15203
15204 if (!isc_time_isepoch(&expiretime)) {
15205 CHECK(putstr(text, "\nexpires: "));
15206 CHECK(putstr(text, xbuf));
15207 }
15208
15209 if (secure) {
15210 CHECK(putstr(text, "\nsecure: yes"));
15211 if (hasraw) {
15212 CHECK(putstr(text, "\ninline signing: yes"));
15213 } else {
15214 CHECK(putstr(text, "\ninline signing: no"));
15215 }
15216 } else {
15217 CHECK(putstr(text, "\nsecure: no"));
15218 }
15219
15220 if (maintain) {
15221 CHECK(putstr(text, "\nkey maintenance: automatic"));
15222 if (!isc_time_isepoch(&refreshkeytime)) {
15223 CHECK(putstr(text, "\nnext key event: "));
15224 CHECK(putstr(text, kbuf));
15225 }
15226 } else if (allow) {
15227 CHECK(putstr(text, "\nkey maintenance: on command"));
15228 } else if (secure || hasraw) {
15229 CHECK(putstr(text, "\nkey maintenance: none"));
15230 }
15231
15232 if (!isc_time_isepoch(&resigntime)) {
15233 CHECK(putstr(text, "\nnext resign node: "));
15234 CHECK(putstr(text, resignbuf));
15235 CHECK(putstr(text, "\nnext resign time: "));
15236 CHECK(putstr(text, rtbuf));
15237 }
15238
15239 if (dynamic) {
15240 CHECK(putstr(text, "\ndynamic: yes"));
15241 if (frozen) {
15242 CHECK(putstr(text, "\nfrozen: yes"));
15243 } else {
15244 CHECK(putstr(text, "\nfrozen: no"));
15245 }
15246 } else {
15247 CHECK(putstr(text, "\ndynamic: no"));
15248 }
15249
15250 CHECK(putstr(text, "\nreconfigurable via modzone: "));
15251 CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
15252
15253 cleanup:
15254 /* Indicate truncated output if possible. */
15255 if (result == ISC_R_NOSPACE) {
15256 (void)putstr(text, "\n...");
15257 }
15258 if ((result == ISC_R_SUCCESS || result == ISC_R_NOSPACE)) {
15259 (void)putnull(text);
15260 }
15261
15262 if (db != NULL) {
15263 dns_db_detach(&db);
15264 }
15265 if (rawdb != NULL) {
15266 dns_db_detach(&rawdb);
15267 }
15268 if (incfiles != NULL && mayberaw != NULL) {
15269 int i;
15270 isc_mem_t *mctx = dns_zone_getmctx(mayberaw);
15271
15272 for (i = 0; i < nfiles; i++) {
15273 if (incfiles[i] != NULL) {
15274 isc_mem_free(mctx, incfiles[i]);
15275 }
15276 }
15277 isc_mem_free(mctx, incfiles);
15278 }
15279 if (raw != NULL) {
15280 dns_zone_detach(&raw);
15281 }
15282 if (zone != NULL) {
15283 dns_zone_detach(&zone);
15284 }
15285 return (result);
15286 }
15287
15288 isc_result_t
named_server_nta(named_server_t * server,isc_lex_t * lex,bool readonly,isc_buffer_t ** text)15289 named_server_nta(named_server_t *server, isc_lex_t *lex, bool readonly,
15290 isc_buffer_t **text) {
15291 dns_view_t *view;
15292 dns_ntatable_t *ntatable = NULL;
15293 isc_result_t result = ISC_R_SUCCESS;
15294 char *ptr, *nametext = NULL, *viewname;
15295 char namebuf[DNS_NAME_FORMATSIZE];
15296 char viewbuf[DNS_NAME_FORMATSIZE];
15297 isc_stdtime_t now, when;
15298 isc_time_t t;
15299 char tbuf[64];
15300 const char *msg = NULL;
15301 bool dump = false, force = false;
15302 dns_fixedname_t fn;
15303 const dns_name_t *ntaname;
15304 dns_name_t *fname;
15305 dns_ttl_t ntattl;
15306 bool ttlset = false, excl = false, viewfound = false;
15307 dns_rdataclass_t rdclass = dns_rdataclass_in;
15308 bool first = true;
15309
15310 REQUIRE(text != NULL);
15311
15312 UNUSED(force);
15313
15314 fname = dns_fixedname_initname(&fn);
15315
15316 /* Skip the command name. */
15317 ptr = next_token(lex, text);
15318 if (ptr == NULL) {
15319 return (ISC_R_UNEXPECTEDEND);
15320 }
15321
15322 for (;;) {
15323 /* Check for options */
15324 ptr = next_token(lex, text);
15325 if (ptr == NULL) {
15326 return (ISC_R_UNEXPECTEDEND);
15327 }
15328
15329 if (strcmp(ptr, "--") == 0) {
15330 break;
15331 } else if (argcheck(ptr, "dump")) {
15332 dump = true;
15333 } else if (argcheck(ptr, "remove")) {
15334 ntattl = 0;
15335 ttlset = true;
15336 } else if (argcheck(ptr, "force")) {
15337 force = true;
15338 continue;
15339 } else if (argcheck(ptr, "lifetime")) {
15340 isc_textregion_t tr;
15341
15342 ptr = next_token(lex, text);
15343 if (ptr == NULL) {
15344 msg = "No lifetime specified";
15345 CHECK(ISC_R_UNEXPECTEDEND);
15346 }
15347
15348 tr.base = ptr;
15349 tr.length = strlen(ptr);
15350 result = dns_ttl_fromtext(&tr, &ntattl);
15351 if (result != ISC_R_SUCCESS) {
15352 msg = "could not parse NTA lifetime";
15353 CHECK(result);
15354 }
15355
15356 if (ntattl > 604800) {
15357 msg = "NTA lifetime cannot exceed one week";
15358 CHECK(ISC_R_RANGE);
15359 }
15360
15361 ttlset = true;
15362 continue;
15363 } else if (argcheck(ptr, "class")) {
15364 isc_textregion_t tr;
15365
15366 ptr = next_token(lex, text);
15367 if (ptr == NULL) {
15368 msg = "No class specified";
15369 CHECK(ISC_R_UNEXPECTEDEND);
15370 }
15371
15372 tr.base = ptr;
15373 tr.length = strlen(ptr);
15374 CHECK(dns_rdataclass_fromtext(&rdclass, &tr));
15375 continue;
15376 } else if (ptr[0] == '-') {
15377 msg = "Unknown option";
15378 CHECK(DNS_R_SYNTAX);
15379 } else {
15380 nametext = ptr;
15381 }
15382
15383 break;
15384 }
15385
15386 /*
15387 * If -dump was specified, list NTA's and return
15388 */
15389 if (dump) {
15390 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15391 view = ISC_LIST_NEXT(view, link))
15392 {
15393 if (ntatable != NULL) {
15394 dns_ntatable_detach(&ntatable);
15395 }
15396 result = dns_view_getntatable(view, &ntatable);
15397 if (result == ISC_R_NOTFOUND) {
15398 continue;
15399 }
15400
15401 CHECK(dns_ntatable_totext(ntatable, view->name, text));
15402 }
15403 CHECK(putnull(text));
15404
15405 goto cleanup;
15406 }
15407
15408 if (readonly) {
15409 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15410 NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
15411 "rejecting restricted control channel "
15412 "NTA command");
15413 CHECK(ISC_R_FAILURE);
15414 }
15415
15416 /* Get the NTA name if not found above. */
15417 if (nametext == NULL) {
15418 nametext = next_token(lex, text);
15419 }
15420 if (nametext == NULL) {
15421 return (ISC_R_UNEXPECTEDEND);
15422 }
15423
15424 /* Copy nametext as it'll be overwritten by next_token() */
15425 strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE);
15426
15427 if (strcmp(namebuf, ".") == 0) {
15428 ntaname = dns_rootname;
15429 } else {
15430 isc_buffer_t b;
15431 isc_buffer_init(&b, namebuf, strlen(namebuf));
15432 isc_buffer_add(&b, strlen(namebuf));
15433 CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL));
15434 ntaname = fname;
15435 }
15436
15437 /* Look for the view name. */
15438 viewname = next_token(lex, text);
15439 if (viewname != NULL) {
15440 strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE);
15441 viewname = viewbuf;
15442 }
15443
15444 if (next_token(lex, text) != NULL) {
15445 CHECK(DNS_R_SYNTAX);
15446 }
15447
15448 isc_stdtime_get(&now);
15449
15450 result = isc_task_beginexclusive(server->task);
15451 RUNTIME_CHECK(result == ISC_R_SUCCESS);
15452 excl = true;
15453 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15454 view = ISC_LIST_NEXT(view, link))
15455 {
15456 if (viewname != NULL && strcmp(view->name, viewname) != 0) {
15457 continue;
15458 }
15459 viewfound = true;
15460
15461 if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) {
15462 continue;
15463 }
15464
15465 if (view->nta_lifetime == 0) {
15466 continue;
15467 }
15468
15469 if (!ttlset) {
15470 ntattl = view->nta_lifetime;
15471 }
15472
15473 if (ntatable != NULL) {
15474 dns_ntatable_detach(&ntatable);
15475 }
15476
15477 result = dns_view_getntatable(view, &ntatable);
15478 if (result == ISC_R_NOTFOUND) {
15479 result = ISC_R_SUCCESS;
15480 continue;
15481 }
15482
15483 result = dns_view_flushnode(view, ntaname, true);
15484 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15485 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15486 "flush tree '%s' in cache view '%s': %s", namebuf,
15487 view->name, isc_result_totext(result));
15488
15489 if (ntattl != 0) {
15490 CHECK(dns_ntatable_add(ntatable, ntaname, force, now,
15491 ntattl));
15492
15493 when = now + ntattl;
15494 isc_time_set(&t, when, 0);
15495 isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
15496
15497 if (!first) {
15498 CHECK(putstr(text, "\n"));
15499 }
15500 first = false;
15501
15502 CHECK(putstr(text, "Negative trust anchor added: "));
15503 CHECK(putstr(text, namebuf));
15504 CHECK(putstr(text, "/"));
15505 CHECK(putstr(text, view->name));
15506 CHECK(putstr(text, ", expires "));
15507 CHECK(putstr(text, tbuf));
15508
15509 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15510 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15511 "added NTA '%s' (%d sec) in view '%s'",
15512 namebuf, ntattl, view->name);
15513 } else {
15514 bool wasremoved;
15515
15516 result = dns_ntatable_delete(ntatable, ntaname);
15517 if (result == ISC_R_SUCCESS) {
15518 wasremoved = true;
15519 } else if (result == ISC_R_NOTFOUND) {
15520 wasremoved = false;
15521 } else {
15522 goto cleanup;
15523 }
15524
15525 if (!first) {
15526 CHECK(putstr(text, "\n"));
15527 }
15528 first = false;
15529
15530 CHECK(putstr(text, "Negative trust anchor "));
15531 CHECK(putstr(text,
15532 wasremoved ? "removed: " : "not found: "));
15533 CHECK(putstr(text, namebuf));
15534 CHECK(putstr(text, "/"));
15535 CHECK(putstr(text, view->name));
15536
15537 if (wasremoved) {
15538 isc_log_write(
15539 named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15540 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
15541 "removed NTA '%s' in view %s", namebuf,
15542 view->name);
15543 }
15544 }
15545
15546 result = dns_view_saventa(view);
15547 if (result != ISC_R_SUCCESS) {
15548 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15549 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15550 "error writing NTA file "
15551 "for view '%s': %s",
15552 view->name, isc_result_totext(result));
15553 }
15554 }
15555
15556 if (!viewfound) {
15557 msg = "No such view";
15558 CHECK(ISC_R_NOTFOUND);
15559 }
15560
15561 (void)putnull(text);
15562
15563 cleanup:
15564 if (msg != NULL) {
15565 (void)putstr(text, msg);
15566 (void)putnull(text);
15567 }
15568
15569 if (excl) {
15570 isc_task_endexclusive(server->task);
15571 }
15572 if (ntatable != NULL) {
15573 dns_ntatable_detach(&ntatable);
15574 }
15575 return (result);
15576 }
15577
15578 isc_result_t
named_server_saventa(named_server_t * server)15579 named_server_saventa(named_server_t *server) {
15580 dns_view_t *view;
15581
15582 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15583 view = ISC_LIST_NEXT(view, link))
15584 {
15585 isc_result_t result = dns_view_saventa(view);
15586
15587 if (result != ISC_R_SUCCESS) {
15588 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15589 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15590 "error writing NTA file "
15591 "for view '%s': %s",
15592 view->name, isc_result_totext(result));
15593 }
15594 }
15595
15596 return (ISC_R_SUCCESS);
15597 }
15598
15599 isc_result_t
named_server_loadnta(named_server_t * server)15600 named_server_loadnta(named_server_t *server) {
15601 dns_view_t *view;
15602
15603 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15604 view = ISC_LIST_NEXT(view, link))
15605 {
15606 isc_result_t result = dns_view_loadnta(view);
15607
15608 if ((result != ISC_R_SUCCESS) &&
15609 (result != ISC_R_FILENOTFOUND) &&
15610 (result != ISC_R_NOTFOUND))
15611 {
15612 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15613 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
15614 "error loading NTA file "
15615 "for view '%s': %s",
15616 view->name, isc_result_totext(result));
15617 }
15618 }
15619
15620 return (ISC_R_SUCCESS);
15621 }
15622
15623 static isc_result_t
mkey_refresh(dns_view_t * view,isc_buffer_t ** text)15624 mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
15625 isc_result_t result;
15626 char msg[DNS_NAME_FORMATSIZE + 500] = "";
15627
15628 snprintf(msg, sizeof(msg), "refreshing managed keys for '%s'",
15629 view->name);
15630 CHECK(putstr(text, msg));
15631 CHECK(dns_zone_synckeyzone(view->managed_keys));
15632
15633 cleanup:
15634 return (result);
15635 }
15636
15637 static isc_result_t
mkey_destroy(named_server_t * server,dns_view_t * view,isc_buffer_t ** text)15638 mkey_destroy(named_server_t *server, dns_view_t *view, isc_buffer_t **text) {
15639 isc_result_t result;
15640 char msg[DNS_NAME_FORMATSIZE + 500] = "";
15641 bool exclusive = false;
15642 const char *file = NULL;
15643 dns_db_t *dbp = NULL;
15644 dns_zone_t *mkzone = NULL;
15645 bool removed_a_file = false;
15646
15647 if (view->managed_keys == NULL) {
15648 CHECK(ISC_R_NOTFOUND);
15649 }
15650
15651 snprintf(msg, sizeof(msg), "destroying managed-keys database for '%s'",
15652 view->name);
15653 CHECK(putstr(text, msg));
15654
15655 result = isc_task_beginexclusive(server->task);
15656 RUNTIME_CHECK(result == ISC_R_SUCCESS);
15657 exclusive = true;
15658
15659 /* Remove and clean up managed keys zone from view */
15660 mkzone = view->managed_keys;
15661 view->managed_keys = NULL;
15662 (void)dns_zone_flush(mkzone);
15663
15664 /* Unload zone database */
15665 if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) {
15666 dns_db_detach(&dbp);
15667 dns_zone_unload(mkzone);
15668 }
15669
15670 /* Delete files */
15671 file = dns_zone_getfile(mkzone);
15672 result = isc_file_remove(file);
15673 if (result == ISC_R_SUCCESS) {
15674 removed_a_file = true;
15675 } else {
15676 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15677 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
15678 "file %s not removed: %s", file,
15679 isc_result_totext(result));
15680 }
15681
15682 file = dns_zone_getjournal(mkzone);
15683 result = isc_file_remove(file);
15684 if (result == ISC_R_SUCCESS) {
15685 removed_a_file = true;
15686 } else {
15687 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
15688 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
15689 "file %s not removed: %s", file,
15690 isc_result_totext(result));
15691 }
15692
15693 if (!removed_a_file) {
15694 CHECK(putstr(text, "error: no files could be removed"));
15695 CHECK(ISC_R_FAILURE);
15696 }
15697
15698 dns_zone_detach(&mkzone);
15699 result = ISC_R_SUCCESS;
15700
15701 cleanup:
15702 if (exclusive) {
15703 isc_task_endexclusive(server->task);
15704 }
15705 return (result);
15706 }
15707
15708 static isc_result_t
mkey_dumpzone(dns_view_t * view,isc_buffer_t ** text)15709 mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
15710 isc_result_t result;
15711 dns_db_t *db = NULL;
15712 dns_dbversion_t *ver = NULL;
15713 dns_rriterator_t rrit;
15714 isc_stdtime_t now;
15715 dns_name_t *prevname = NULL;
15716
15717 isc_stdtime_get(&now);
15718
15719 CHECK(dns_zone_getdb(view->managed_keys, &db));
15720 dns_db_currentversion(db, &ver);
15721 dns_rriterator_init(&rrit, db, ver, 0);
15722 for (result = dns_rriterator_first(&rrit); result == ISC_R_SUCCESS;
15723 result = dns_rriterator_nextrrset(&rrit))
15724 {
15725 char buf[DNS_NAME_FORMATSIZE + 500];
15726 dns_name_t *name = NULL;
15727 dns_rdataset_t *kdset = NULL;
15728 dns_rdata_t rdata = DNS_RDATA_INIT;
15729 dns_rdata_keydata_t kd;
15730 uint32_t ttl;
15731
15732 dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
15733 if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
15734 !dns_rdataset_isassociated(kdset))
15735 {
15736 continue;
15737 }
15738
15739 if (name != prevname) {
15740 char nbuf[DNS_NAME_FORMATSIZE];
15741 dns_name_format(name, nbuf, sizeof(nbuf));
15742 snprintf(buf, sizeof(buf), "\n\n name: %s", nbuf);
15743 CHECK(putstr(text, buf));
15744 }
15745
15746 for (result = dns_rdataset_first(kdset);
15747 result == ISC_R_SUCCESS; result = dns_rdataset_next(kdset))
15748 {
15749 char alg[DNS_SECALG_FORMATSIZE];
15750 char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
15751 dns_keytag_t keyid;
15752 isc_region_t r;
15753 isc_time_t t;
15754 bool revoked;
15755
15756 dns_rdata_reset(&rdata);
15757 dns_rdataset_current(kdset, &rdata);
15758 result = dns_rdata_tostruct(&rdata, &kd, NULL);
15759 RUNTIME_CHECK(result == ISC_R_SUCCESS);
15760
15761 dns_rdata_toregion(&rdata, &r);
15762 isc_region_consume(&r, 12);
15763 keyid = dst_region_computeid(&r);
15764
15765 snprintf(buf, sizeof(buf), "\n keyid: %u", keyid);
15766 CHECK(putstr(text, buf));
15767
15768 dns_secalg_format(kd.algorithm, alg, sizeof(alg));
15769 snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
15770 CHECK(putstr(text, buf));
15771
15772 revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
15773 snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
15774 revoked ? " REVOKE" : "",
15775 ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP"
15776 : "",
15777 (kd.flags == 0) ? " (none)" : "");
15778 CHECK(putstr(text, buf));
15779
15780 isc_time_set(&t, kd.refresh, 0);
15781 isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
15782 snprintf(buf, sizeof(buf), "\n\tnext refresh: %s",
15783 tbuf);
15784 CHECK(putstr(text, buf));
15785
15786 if (kd.removehd != 0) {
15787 isc_time_set(&t, kd.removehd, 0);
15788 isc_time_formathttptimestamp(&t, tbuf,
15789 sizeof(tbuf));
15790 snprintf(buf, sizeof(buf), "\n\tremove at: %s",
15791 tbuf);
15792 CHECK(putstr(text, buf));
15793 }
15794
15795 isc_time_set(&t, kd.addhd, 0);
15796 isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
15797 if (kd.addhd == 0) {
15798 snprintf(buf, sizeof(buf), "\n\tno trust");
15799 } else if (revoked) {
15800 snprintf(buf, sizeof(buf), "\n\ttrust revoked");
15801 } else if (kd.addhd <= now) {
15802 snprintf(buf, sizeof(buf),
15803 "\n\ttrusted since: %s", tbuf);
15804 } else if (kd.addhd > now) {
15805 snprintf(buf, sizeof(buf),
15806 "\n\ttrust pending: %s", tbuf);
15807 }
15808 CHECK(putstr(text, buf));
15809 }
15810 }
15811
15812 if (result == ISC_R_NOMORE) {
15813 result = ISC_R_SUCCESS;
15814 }
15815
15816 cleanup:
15817 if (ver != NULL) {
15818 dns_rriterator_destroy(&rrit);
15819 dns_db_closeversion(db, &ver, false);
15820 }
15821 if (db != NULL) {
15822 dns_db_detach(&db);
15823 }
15824
15825 return (result);
15826 }
15827
15828 static isc_result_t
mkey_status(dns_view_t * view,isc_buffer_t ** text)15829 mkey_status(dns_view_t *view, isc_buffer_t **text) {
15830 isc_result_t result;
15831 char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
15832 isc_time_t t;
15833
15834 CHECK(putstr(text, "view: "));
15835 CHECK(putstr(text, view->name));
15836
15837 CHECK(putstr(text, "\nnext scheduled event: "));
15838
15839 dns_zone_getrefreshkeytime(view->managed_keys, &t);
15840 if (isc_time_isepoch(&t)) {
15841 CHECK(putstr(text, "never"));
15842 } else {
15843 isc_time_formathttptimestamp(&t, msg, sizeof(msg));
15844 CHECK(putstr(text, msg));
15845 }
15846
15847 CHECK(mkey_dumpzone(view, text));
15848
15849 cleanup:
15850 return (result);
15851 }
15852
15853 isc_result_t
named_server_mkeys(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)15854 named_server_mkeys(named_server_t *server, isc_lex_t *lex,
15855 isc_buffer_t **text) {
15856 char *cmd, *classtxt, *viewtxt = NULL;
15857 isc_result_t result = ISC_R_SUCCESS;
15858 dns_view_t *view = NULL;
15859 dns_rdataclass_t rdclass;
15860 char msg[DNS_NAME_FORMATSIZE + 500] = "";
15861 enum { NONE, STATUS, REFRESH, SYNC, DESTROY } opt = NONE;
15862 bool found = false;
15863 bool first = true;
15864
15865 REQUIRE(text != NULL);
15866
15867 /* Skip rndc command name */
15868 cmd = next_token(lex, text);
15869 if (cmd == NULL) {
15870 return (ISC_R_UNEXPECTEDEND);
15871 }
15872
15873 /* Get managed-keys subcommand */
15874 cmd = next_token(lex, text);
15875 if (cmd == NULL) {
15876 return (ISC_R_UNEXPECTEDEND);
15877 }
15878
15879 if (strcasecmp(cmd, "status") == 0) {
15880 opt = STATUS;
15881 } else if (strcasecmp(cmd, "refresh") == 0) {
15882 opt = REFRESH;
15883 } else if (strcasecmp(cmd, "sync") == 0) {
15884 opt = SYNC;
15885 } else if (strcasecmp(cmd, "destroy") == 0) {
15886 opt = DESTROY;
15887 } else {
15888 snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
15889 (void)putstr(text, msg);
15890 result = ISC_R_UNEXPECTED;
15891 goto cleanup;
15892 }
15893
15894 /* Look for the optional class name. */
15895 classtxt = next_token(lex, text);
15896 if (classtxt != NULL) {
15897 isc_textregion_t r;
15898 r.base = classtxt;
15899 r.length = strlen(classtxt);
15900 result = dns_rdataclass_fromtext(&rdclass, &r);
15901 if (result != ISC_R_SUCCESS) {
15902 snprintf(msg, sizeof(msg), "unknown class '%s'",
15903 classtxt);
15904 (void)putstr(text, msg);
15905 goto cleanup;
15906 }
15907 viewtxt = next_token(lex, text);
15908 }
15909
15910 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
15911 view = ISC_LIST_NEXT(view, link))
15912 {
15913 if (viewtxt != NULL && (rdclass != view->rdclass ||
15914 strcmp(view->name, viewtxt) != 0))
15915 {
15916 continue;
15917 }
15918
15919 if (view->managed_keys == NULL) {
15920 if (viewtxt != NULL) {
15921 snprintf(msg, sizeof(msg),
15922 "view '%s': no managed keys", viewtxt);
15923 CHECK(putstr(text, msg));
15924 goto cleanup;
15925 } else {
15926 continue;
15927 }
15928 }
15929
15930 found = true;
15931
15932 switch (opt) {
15933 case REFRESH:
15934 if (!first) {
15935 CHECK(putstr(text, "\n"));
15936 }
15937 CHECK(mkey_refresh(view, text));
15938 break;
15939 case STATUS:
15940 if (!first) {
15941 CHECK(putstr(text, "\n\n"));
15942 }
15943 CHECK(mkey_status(view, text));
15944 break;
15945 case SYNC:
15946 CHECK(dns_zone_flush(view->managed_keys));
15947 break;
15948 case DESTROY:
15949 if (!first) {
15950 CHECK(putstr(text, "\n"));
15951 }
15952 CHECK(mkey_destroy(server, view, text));
15953 break;
15954 default:
15955 UNREACHABLE();
15956 }
15957
15958 if (viewtxt != NULL) {
15959 break;
15960 }
15961 first = false;
15962 }
15963
15964 if (!found) {
15965 CHECK(putstr(text, "no views with managed keys"));
15966 }
15967
15968 cleanup:
15969 if (isc_buffer_usedlength(*text) > 0) {
15970 (void)putnull(text);
15971 }
15972
15973 return (result);
15974 }
15975
15976 isc_result_t
named_server_dnstap(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)15977 named_server_dnstap(named_server_t *server, isc_lex_t *lex,
15978 isc_buffer_t **text) {
15979 #ifdef HAVE_DNSTAP
15980 char *ptr;
15981 isc_result_t result;
15982 bool reopen = false;
15983 int backups = 0;
15984
15985 REQUIRE(text != NULL);
15986
15987 if (server->dtenv == NULL) {
15988 return (ISC_R_NOTFOUND);
15989 }
15990
15991 /* Check the command name. */
15992 ptr = next_token(lex, text);
15993 if (ptr == NULL) {
15994 return (ISC_R_UNEXPECTEDEND);
15995 }
15996
15997 /* "dnstap-reopen" was used in 9.11.0b1 */
15998 if (strcasecmp(ptr, "dnstap-reopen") == 0) {
15999 reopen = true;
16000 } else {
16001 ptr = next_token(lex, text);
16002 if (ptr == NULL) {
16003 return (ISC_R_UNEXPECTEDEND);
16004 }
16005 }
16006
16007 if (reopen || strcasecmp(ptr, "-reopen") == 0) {
16008 backups = ISC_LOG_ROLLNEVER;
16009 } else if ((strcasecmp(ptr, "-roll") == 0)) {
16010 unsigned int n;
16011 ptr = next_token(lex, text);
16012 if (ptr != NULL) {
16013 unsigned int u;
16014 n = sscanf(ptr, "%u", &u);
16015 if (n != 1U || u > INT_MAX) {
16016 return (ISC_R_BADNUMBER);
16017 }
16018 backups = u;
16019 } else {
16020 backups = ISC_LOG_ROLLINFINITE;
16021 }
16022 } else {
16023 return (DNS_R_SYNTAX);
16024 }
16025
16026 result = dns_dt_reopen(server->dtenv, backups);
16027 return (result);
16028 #else /* ifdef HAVE_DNSTAP */
16029 UNUSED(server);
16030 UNUSED(lex);
16031 UNUSED(text);
16032 return (ISC_R_NOTIMPLEMENTED);
16033 #endif /* ifdef HAVE_DNSTAP */
16034 }
16035
16036 isc_result_t
named_server_tcptimeouts(isc_lex_t * lex,isc_buffer_t ** text)16037 named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) {
16038 char *ptr;
16039 isc_result_t result = ISC_R_SUCCESS;
16040 uint32_t initial, idle, keepalive, advertised;
16041 char msg[128];
16042
16043 /* Skip the command name. */
16044 ptr = next_token(lex, text);
16045 if (ptr == NULL) {
16046 return (ISC_R_UNEXPECTEDEND);
16047 }
16048
16049 isc_nm_gettimeouts(named_g_nm, &initial, &idle, &keepalive,
16050 &advertised);
16051
16052 /* Look for optional arguments. */
16053 ptr = next_token(lex, NULL);
16054 if (ptr != NULL) {
16055 CHECK(isc_parse_uint32(&initial, ptr, 10));
16056 initial *= 100;
16057 if (initial > MAX_INITIAL_TIMEOUT) {
16058 CHECK(ISC_R_RANGE);
16059 }
16060 if (initial < MIN_INITIAL_TIMEOUT) {
16061 CHECK(ISC_R_RANGE);
16062 }
16063
16064 ptr = next_token(lex, text);
16065 if (ptr == NULL) {
16066 return (ISC_R_UNEXPECTEDEND);
16067 }
16068 CHECK(isc_parse_uint32(&idle, ptr, 10));
16069 idle *= 100;
16070 if (idle > MAX_IDLE_TIMEOUT) {
16071 CHECK(ISC_R_RANGE);
16072 }
16073 if (idle < MIN_IDLE_TIMEOUT) {
16074 CHECK(ISC_R_RANGE);
16075 }
16076
16077 ptr = next_token(lex, text);
16078 if (ptr == NULL) {
16079 return (ISC_R_UNEXPECTEDEND);
16080 }
16081 CHECK(isc_parse_uint32(&keepalive, ptr, 10));
16082 keepalive *= 100;
16083 if (keepalive > MAX_KEEPALIVE_TIMEOUT) {
16084 CHECK(ISC_R_RANGE);
16085 }
16086 if (keepalive < MIN_KEEPALIVE_TIMEOUT) {
16087 CHECK(ISC_R_RANGE);
16088 }
16089
16090 ptr = next_token(lex, text);
16091 if (ptr == NULL) {
16092 return (ISC_R_UNEXPECTEDEND);
16093 }
16094 CHECK(isc_parse_uint32(&advertised, ptr, 10));
16095 advertised *= 100;
16096 if (advertised > MAX_ADVERTISED_TIMEOUT) {
16097 CHECK(ISC_R_RANGE);
16098 }
16099
16100 result = isc_task_beginexclusive(named_g_server->task);
16101 RUNTIME_CHECK(result == ISC_R_SUCCESS);
16102
16103 isc_nm_settimeouts(named_g_nm, initial, idle, keepalive,
16104 advertised);
16105
16106 isc_task_endexclusive(named_g_server->task);
16107 }
16108
16109 snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100);
16110 CHECK(putstr(text, msg));
16111 snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100);
16112 CHECK(putstr(text, msg));
16113 snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n",
16114 keepalive / 100);
16115 CHECK(putstr(text, msg));
16116 snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u",
16117 advertised / 100);
16118 CHECK(putstr(text, msg));
16119
16120 cleanup:
16121 if (isc_buffer_usedlength(*text) > 0) {
16122 (void)putnull(text);
16123 }
16124
16125 return (result);
16126 }
16127
16128 isc_result_t
named_server_servestale(named_server_t * server,isc_lex_t * lex,isc_buffer_t ** text)16129 named_server_servestale(named_server_t *server, isc_lex_t *lex,
16130 isc_buffer_t **text) {
16131 char *ptr, *classtxt, *viewtxt = NULL;
16132 char msg[128];
16133 dns_rdataclass_t rdclass = dns_rdataclass_in;
16134 dns_view_t *view;
16135 bool found = false;
16136 dns_stale_answer_t staleanswersok = dns_stale_answer_conf;
16137 bool wantstatus = false;
16138 isc_result_t result = ISC_R_SUCCESS;
16139 bool exclusive = false;
16140
16141 REQUIRE(text != NULL);
16142
16143 /* Skip the command name. */
16144 ptr = next_token(lex, text);
16145 if (ptr == NULL) {
16146 return (ISC_R_UNEXPECTEDEND);
16147 }
16148
16149 ptr = next_token(lex, NULL);
16150 if (ptr == NULL) {
16151 return (ISC_R_UNEXPECTEDEND);
16152 }
16153
16154 if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
16155 !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
16156 {
16157 staleanswersok = dns_stale_answer_yes;
16158 } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
16159 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
16160 {
16161 staleanswersok = dns_stale_answer_no;
16162 } else if (strcasecmp(ptr, "reset") == 0) {
16163 staleanswersok = dns_stale_answer_conf;
16164 } else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
16165 wantstatus = true;
16166 } else {
16167 return (DNS_R_SYNTAX);
16168 }
16169
16170 /* Look for the optional class name. */
16171 classtxt = next_token(lex, text);
16172 if (classtxt != NULL) {
16173 isc_textregion_t r;
16174
16175 /* Look for the optional view name. */
16176 viewtxt = next_token(lex, text);
16177
16178 /*
16179 * If 'classtext' is not a valid class then it us a view name.
16180 */
16181 r.base = classtxt;
16182 r.length = strlen(classtxt);
16183 result = dns_rdataclass_fromtext(&rdclass, &r);
16184 if (result != ISC_R_SUCCESS) {
16185 if (viewtxt != NULL) {
16186 snprintf(msg, sizeof(msg), "unknown class '%s'",
16187 classtxt);
16188 (void)putstr(text, msg);
16189 goto cleanup;
16190 }
16191
16192 viewtxt = classtxt;
16193 classtxt = NULL;
16194 }
16195 }
16196
16197 result = isc_task_beginexclusive(server->task);
16198 RUNTIME_CHECK(result == ISC_R_SUCCESS);
16199 exclusive = true;
16200
16201 for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
16202 view = ISC_LIST_NEXT(view, link))
16203 {
16204 dns_ttl_t stale_ttl = 0;
16205 uint32_t stale_refresh = 0;
16206 dns_db_t *db = NULL;
16207
16208 if (classtxt != NULL && rdclass != view->rdclass) {
16209 continue;
16210 }
16211
16212 if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0) {
16213 continue;
16214 }
16215
16216 if (!wantstatus) {
16217 view->staleanswersok = staleanswersok;
16218 found = true;
16219 continue;
16220 }
16221
16222 db = NULL;
16223 dns_db_attach(view->cachedb, &db);
16224 (void)dns_db_getservestalettl(db, &stale_ttl);
16225 (void)dns_db_getservestalerefresh(db, &stale_refresh);
16226 dns_db_detach(&db);
16227 if (found) {
16228 CHECK(putstr(text, "\n"));
16229 }
16230 CHECK(putstr(text, view->name));
16231 CHECK(putstr(text, ": "));
16232 switch (view->staleanswersok) {
16233 case dns_stale_answer_yes:
16234 if (stale_ttl > 0) {
16235 CHECK(putstr(text, "on (rndc)"));
16236 } else {
16237 CHECK(putstr(text, "off (not-cached)"));
16238 }
16239 break;
16240 case dns_stale_answer_no:
16241 CHECK(putstr(text, "off (rndc)"));
16242 break;
16243 case dns_stale_answer_conf:
16244 if (view->staleanswersenable && stale_ttl > 0) {
16245 CHECK(putstr(text, "on"));
16246 } else if (view->staleanswersenable) {
16247 CHECK(putstr(text, "off (not-cached)"));
16248 } else {
16249 CHECK(putstr(text, "off"));
16250 }
16251 break;
16252 }
16253 if (stale_ttl > 0) {
16254 snprintf(msg, sizeof(msg),
16255 " (stale-answer-ttl=%u max-stale-ttl=%u "
16256 "stale-refresh-time=%u)",
16257 view->staleanswerttl, stale_ttl,
16258 stale_refresh);
16259 CHECK(putstr(text, msg));
16260 }
16261 found = true;
16262 }
16263
16264 if (!found) {
16265 result = ISC_R_NOTFOUND;
16266 }
16267
16268 cleanup:
16269 if (exclusive) {
16270 isc_task_endexclusive(named_g_server->task);
16271 }
16272
16273 if (isc_buffer_usedlength(*text) > 0) {
16274 (void)putnull(text);
16275 }
16276
16277 return (result);
16278 }
16279