turns printfs back on
[freebsd-src/fkvm-freebsd.git] / contrib / bind9 / bin / named / server.c
blob79bd125c5498da62fde05ba4c6bd1c47109fd3f3
1 /*
2 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: server.c,v 1.419.18.57.10.3 2008/07/23 12:04:32 marka Exp $ */
20 /*! \file */
22 #include <config.h>
24 #include <stdlib.h>
26 #include <isc/app.h>
27 #include <isc/base64.h>
28 #include <isc/dir.h>
29 #include <isc/entropy.h>
30 #include <isc/file.h>
31 #include <isc/hash.h>
32 #include <isc/lex.h>
33 #include <isc/parseint.h>
34 #include <isc/print.h>
35 #include <isc/resource.h>
36 #include <isc/stdio.h>
37 #include <isc/string.h>
38 #include <isc/task.h>
39 #include <isc/timer.h>
40 #include <isc/util.h>
42 #include <isccfg/namedconf.h>
44 #include <bind9/check.h>
46 #include <dns/acache.h>
47 #include <dns/adb.h>
48 #include <dns/cache.h>
49 #include <dns/db.h>
50 #include <dns/dispatch.h>
51 #ifdef DLZ
52 #include <dns/dlz.h>
53 #endif
54 #include <dns/forward.h>
55 #include <dns/journal.h>
56 #include <dns/keytable.h>
57 #include <dns/lib.h>
58 #include <dns/master.h>
59 #include <dns/masterdump.h>
60 #include <dns/order.h>
61 #include <dns/peer.h>
62 #include <dns/portlist.h>
63 #include <dns/rdataclass.h>
64 #include <dns/rdataset.h>
65 #include <dns/rdatastruct.h>
66 #include <dns/resolver.h>
67 #include <dns/rootns.h>
68 #include <dns/secalg.h>
69 #include <dns/stats.h>
70 #include <dns/tkey.h>
71 #include <dns/view.h>
72 #include <dns/zone.h>
73 #include <dns/zt.h>
75 #include <dst/dst.h>
76 #include <dst/result.h>
78 #include <named/client.h>
79 #include <named/config.h>
80 #include <named/control.h>
81 #include <named/interfacemgr.h>
82 #include <named/log.h>
83 #include <named/logconf.h>
84 #include <named/lwresd.h>
85 #include <named/main.h>
86 #include <named/os.h>
87 #include <named/server.h>
88 #include <named/tkeyconf.h>
89 #include <named/tsigconf.h>
90 #include <named/zoneconf.h>
91 #ifdef HAVE_LIBSCF
92 #include <named/ns_smf_globals.h>
93 #include <stdlib.h>
94 #endif
96 /*%
97 * Check an operation for failure. Assumes that the function
98 * using it has a 'result' variable and a 'cleanup' label.
100 #define CHECK(op) \
101 do { result = (op); \
102 if (result != ISC_R_SUCCESS) goto cleanup; \
103 } while (0)
105 #define CHECKM(op, msg) \
106 do { result = (op); \
107 if (result != ISC_R_SUCCESS) { \
108 isc_log_write(ns_g_lctx, \
109 NS_LOGCATEGORY_GENERAL, \
110 NS_LOGMODULE_SERVER, \
111 ISC_LOG_ERROR, \
112 "%s: %s", msg, \
113 isc_result_totext(result)); \
114 goto cleanup; \
116 } while (0) \
118 #define CHECKMF(op, msg, file) \
119 do { result = (op); \
120 if (result != ISC_R_SUCCESS) { \
121 isc_log_write(ns_g_lctx, \
122 NS_LOGCATEGORY_GENERAL, \
123 NS_LOGMODULE_SERVER, \
124 ISC_LOG_ERROR, \
125 "%s '%s': %s", msg, file, \
126 isc_result_totext(result)); \
127 goto cleanup; \
129 } while (0) \
131 #define CHECKFATAL(op, msg) \
132 do { result = (op); \
133 if (result != ISC_R_SUCCESS) \
134 fatal(msg, result); \
135 } while (0) \
137 struct ns_dispatch {
138 isc_sockaddr_t addr;
139 unsigned int dispatchgen;
140 dns_dispatch_t *dispatch;
141 ISC_LINK(struct ns_dispatch) link;
144 struct dumpcontext {
145 isc_mem_t *mctx;
146 isc_boolean_t dumpcache;
147 isc_boolean_t dumpzones;
148 FILE *fp;
149 ISC_LIST(struct viewlistentry) viewlist;
150 struct viewlistentry *view;
151 struct zonelistentry *zone;
152 dns_dumpctx_t *mdctx;
153 dns_db_t *db;
154 dns_db_t *cache;
155 isc_task_t *task;
156 dns_dbversion_t *version;
159 struct viewlistentry {
160 dns_view_t *view;
161 ISC_LINK(struct viewlistentry) link;
162 ISC_LIST(struct zonelistentry) zonelist;
165 struct zonelistentry {
166 dns_zone_t *zone;
167 ISC_LINK(struct zonelistentry) link;
171 * These zones should not leak onto the Internet.
173 static const struct {
174 const char *zone;
175 isc_boolean_t rfc1918;
176 } empty_zones[] = {
177 #ifdef notyet
178 /* RFC 1918 */
179 { "10.IN-ADDR.ARPA", ISC_TRUE },
180 { "16.172.IN-ADDR.ARPA", ISC_TRUE },
181 { "17.172.IN-ADDR.ARPA", ISC_TRUE },
182 { "18.172.IN-ADDR.ARPA", ISC_TRUE },
183 { "19.172.IN-ADDR.ARPA", ISC_TRUE },
184 { "20.172.IN-ADDR.ARPA", ISC_TRUE },
185 { "21.172.IN-ADDR.ARPA", ISC_TRUE },
186 { "22.172.IN-ADDR.ARPA", ISC_TRUE },
187 { "23.172.IN-ADDR.ARPA", ISC_TRUE },
188 { "24.172.IN-ADDR.ARPA", ISC_TRUE },
189 { "25.172.IN-ADDR.ARPA", ISC_TRUE },
190 { "26.172.IN-ADDR.ARPA", ISC_TRUE },
191 { "27.172.IN-ADDR.ARPA", ISC_TRUE },
192 { "28.172.IN-ADDR.ARPA", ISC_TRUE },
193 { "29.172.IN-ADDR.ARPA", ISC_TRUE },
194 { "30.172.IN-ADDR.ARPA", ISC_TRUE },
195 { "31.172.IN-ADDR.ARPA", ISC_TRUE },
196 { "168.192.IN-ADDR.ARPA", ISC_TRUE },
197 #endif
199 /* RFC 3330 */
200 { "127.IN-ADDR.ARPA", ISC_FALSE }, /* LOOPBACK */
201 { "254.169.IN-ADDR.ARPA", ISC_FALSE }, /* LINK LOCAL */
202 { "2.0.192.IN-ADDR.ARPA", ISC_FALSE }, /* TEST NET */
203 { "255.255.255.255.IN-ADDR.ARPA", ISC_FALSE }, /* BROADCAST */
205 /* Local IPv6 Unicast Addresses */
206 { "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.ARPA", ISC_FALSE },
207 { "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.ARPA", ISC_FALSE },
208 /* LOCALLY ASSIGNED LOCAL ADDRES S SCOPE */
209 { "D.F.IP6.ARPA", ISC_FALSE },
210 { "8.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */
211 { "9.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */
212 { "A.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */
213 { "B.E.F.IP6.ARPA", ISC_FALSE }, /* LINK LOCAL */
215 { NULL, ISC_FALSE }
218 static void
219 fatal(const char *msg, isc_result_t result);
221 static void
222 ns_server_reload(isc_task_t *task, isc_event_t *event);
224 static isc_result_t
225 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
226 cfg_aclconfctx_t *actx,
227 isc_mem_t *mctx, ns_listenelt_t **target);
228 static isc_result_t
229 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
230 cfg_aclconfctx_t *actx,
231 isc_mem_t *mctx, ns_listenlist_t **target);
233 static isc_result_t
234 configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
235 const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype);
237 static isc_result_t
238 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
239 const cfg_obj_t *alternates);
241 static isc_result_t
242 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
243 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
244 cfg_aclconfctx_t *aclconf);
246 static void
247 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
250 * Configure a single view ACL at '*aclp'. Get its configuration by
251 * calling 'getvcacl' (for per-view configuration) and maybe 'getscacl'
252 * (for a global default).
254 static isc_result_t
255 configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
256 const char *aclname, cfg_aclconfctx_t *actx,
257 isc_mem_t *mctx, dns_acl_t **aclp)
259 isc_result_t result;
260 const cfg_obj_t *maps[3];
261 const cfg_obj_t *aclobj = NULL;
262 int i = 0;
264 if (*aclp != NULL)
265 dns_acl_detach(aclp);
266 if (vconfig != NULL)
267 maps[i++] = cfg_tuple_get(vconfig, "options");
268 if (config != NULL) {
269 const cfg_obj_t *options = NULL;
270 (void)cfg_map_get(config, "options", &options);
271 if (options != NULL)
272 maps[i++] = options;
274 maps[i] = NULL;
276 (void)ns_config_get(maps, aclname, &aclobj);
277 if (aclobj == NULL)
279 * No value available. *aclp == NULL.
281 return (ISC_R_SUCCESS);
283 result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx,
284 actx, mctx, aclp);
286 return (result);
289 static isc_result_t
290 configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key,
291 dns_keytable_t *keytable, isc_mem_t *mctx)
293 dns_rdataclass_t viewclass;
294 dns_rdata_dnskey_t keystruct;
295 isc_uint32_t flags, proto, alg;
296 const char *keystr, *keynamestr;
297 unsigned char keydata[4096];
298 isc_buffer_t keydatabuf;
299 unsigned char rrdata[4096];
300 isc_buffer_t rrdatabuf;
301 isc_region_t r;
302 dns_fixedname_t fkeyname;
303 dns_name_t *keyname;
304 isc_buffer_t namebuf;
305 isc_result_t result;
306 dst_key_t *dstkey = NULL;
308 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
309 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
310 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
311 keyname = dns_fixedname_name(&fkeyname);
312 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
314 if (vconfig == NULL)
315 viewclass = dns_rdataclass_in;
316 else {
317 const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
318 CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
319 &viewclass));
321 keystruct.common.rdclass = viewclass;
322 keystruct.common.rdtype = dns_rdatatype_dnskey;
324 * The key data in keystruct is not dynamically allocated.
326 keystruct.mctx = NULL;
328 ISC_LINK_INIT(&keystruct.common, link);
330 if (flags > 0xffff)
331 CHECKM(ISC_R_RANGE, "key flags");
332 if (proto > 0xff)
333 CHECKM(ISC_R_RANGE, "key protocol");
334 if (alg > 0xff)
335 CHECKM(ISC_R_RANGE, "key algorithm");
336 keystruct.flags = (isc_uint16_t)flags;
337 keystruct.protocol = (isc_uint8_t)proto;
338 keystruct.algorithm = (isc_uint8_t)alg;
340 isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
341 isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
343 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
344 CHECK(isc_base64_decodestring(keystr, &keydatabuf));
345 isc_buffer_usedregion(&keydatabuf, &r);
346 keystruct.datalen = r.length;
347 keystruct.data = r.base;
349 if ((keystruct.algorithm == DST_ALG_RSASHA1 ||
350 keystruct.algorithm == DST_ALG_RSAMD5) &&
351 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
352 cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING,
353 "trusted key '%s' has a weak exponent",
354 keynamestr);
356 CHECK(dns_rdata_fromstruct(NULL,
357 keystruct.common.rdclass,
358 keystruct.common.rdtype,
359 &keystruct, &rrdatabuf));
360 dns_fixedname_init(&fkeyname);
361 isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr));
362 isc_buffer_add(&namebuf, strlen(keynamestr));
363 CHECK(dns_name_fromtext(keyname, &namebuf,
364 dns_rootname, ISC_FALSE,
365 NULL));
366 CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
367 mctx, &dstkey));
369 CHECK(dns_keytable_add(keytable, &dstkey));
370 INSIST(dstkey == NULL);
371 return (ISC_R_SUCCESS);
373 cleanup:
374 if (result == DST_R_NOCRYPTO) {
375 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
376 "ignoring trusted key for '%s': no crypto support",
377 keynamestr);
378 result = ISC_R_SUCCESS;
379 } else {
380 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
381 "configuring trusted key for '%s': %s",
382 keynamestr, isc_result_totext(result));
383 result = ISC_R_FAILURE;
386 if (dstkey != NULL)
387 dst_key_free(&dstkey);
389 return (result);
393 * Configure DNSSEC keys for a view. Currently used only for
394 * the security roots.
396 * The per-view configuration values and the server-global defaults are read
397 * from 'vconfig' and 'config'. The variable to be configured is '*target'.
399 static isc_result_t
400 configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config,
401 isc_mem_t *mctx, dns_keytable_t **target)
403 isc_result_t result;
404 const cfg_obj_t *keys = NULL;
405 const cfg_obj_t *voptions = NULL;
406 const cfg_listelt_t *element, *element2;
407 const cfg_obj_t *keylist;
408 const cfg_obj_t *key;
409 dns_keytable_t *keytable = NULL;
411 CHECK(dns_keytable_create(mctx, &keytable));
413 if (vconfig != NULL)
414 voptions = cfg_tuple_get(vconfig, "options");
416 keys = NULL;
417 if (voptions != NULL)
418 (void)cfg_map_get(voptions, "trusted-keys", &keys);
419 if (keys == NULL)
420 (void)cfg_map_get(config, "trusted-keys", &keys);
422 for (element = cfg_list_first(keys);
423 element != NULL;
424 element = cfg_list_next(element))
426 keylist = cfg_listelt_value(element);
427 for (element2 = cfg_list_first(keylist);
428 element2 != NULL;
429 element2 = cfg_list_next(element2))
431 key = cfg_listelt_value(element2);
432 CHECK(configure_view_dnsseckey(vconfig, key,
433 keytable, mctx));
437 dns_keytable_detach(target);
438 *target = keytable; /* Transfer ownership. */
439 keytable = NULL;
440 result = ISC_R_SUCCESS;
442 cleanup:
443 return (result);
446 static isc_result_t
447 mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver)
449 const cfg_listelt_t *element;
450 const cfg_obj_t *obj;
451 const char *str;
452 dns_fixedname_t fixed;
453 dns_name_t *name;
454 isc_boolean_t value;
455 isc_result_t result;
456 isc_buffer_t b;
458 dns_fixedname_init(&fixed);
459 name = dns_fixedname_name(&fixed);
460 for (element = cfg_list_first(mbs);
461 element != NULL;
462 element = cfg_list_next(element))
464 obj = cfg_listelt_value(element);
465 str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
466 isc_buffer_init(&b, str, strlen(str));
467 isc_buffer_add(&b, strlen(str));
468 CHECK(dns_name_fromtext(name, &b, dns_rootname,
469 ISC_FALSE, NULL));
470 value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
471 CHECK(dns_resolver_setmustbesecure(resolver, name, value));
474 result = ISC_R_SUCCESS;
476 cleanup:
477 return (result);
481 * Get a dispatch appropriate for the resolver of a given view.
483 static isc_result_t
484 get_view_querysource_dispatch(const cfg_obj_t **maps,
485 int af, dns_dispatch_t **dispatchp)
487 isc_result_t result;
488 dns_dispatch_t *disp;
489 isc_sockaddr_t sa;
490 unsigned int attrs, attrmask;
491 const cfg_obj_t *obj = NULL;
494 * Make compiler happy.
496 result = ISC_R_FAILURE;
498 switch (af) {
499 case AF_INET:
500 result = ns_config_get(maps, "query-source", &obj);
501 INSIST(result == ISC_R_SUCCESS);
502 break;
503 case AF_INET6:
504 result = ns_config_get(maps, "query-source-v6", &obj);
505 INSIST(result == ISC_R_SUCCESS);
506 break;
507 default:
508 INSIST(0);
511 sa = *(cfg_obj_assockaddr(obj));
512 INSIST(isc_sockaddr_pf(&sa) == af);
515 * If we don't support this address family, we're done!
517 switch (af) {
518 case AF_INET:
519 result = isc_net_probeipv4();
520 break;
521 case AF_INET6:
522 result = isc_net_probeipv6();
523 break;
524 default:
525 INSIST(0);
527 if (result != ISC_R_SUCCESS)
528 return (ISC_R_SUCCESS);
531 * Try to find a dispatcher that we can share.
533 attrs = 0;
534 attrs |= DNS_DISPATCHATTR_UDP;
535 switch (af) {
536 case AF_INET:
537 attrs |= DNS_DISPATCHATTR_IPV4;
538 break;
539 case AF_INET6:
540 attrs |= DNS_DISPATCHATTR_IPV6;
541 break;
544 if (isc_sockaddr_getport(&sa) != 0) {
545 INSIST(obj != NULL);
546 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
547 "using specific query-source port suppresses port "
548 "randomization and can be insecure.");
551 attrmask = 0;
552 attrmask |= DNS_DISPATCHATTR_UDP;
553 attrmask |= DNS_DISPATCHATTR_TCP;
554 attrmask |= DNS_DISPATCHATTR_IPV4;
555 attrmask |= DNS_DISPATCHATTR_IPV6;
557 disp = NULL;
558 result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
559 ns_g_taskmgr, &sa, 4096,
560 1024, 32768, 16411, 16433,
561 attrs, attrmask, &disp);
562 if (result != ISC_R_SUCCESS) {
563 isc_sockaddr_t any;
564 char buf[ISC_SOCKADDR_FORMATSIZE];
566 switch (af) {
567 case AF_INET:
568 isc_sockaddr_any(&any);
569 break;
570 case AF_INET6:
571 isc_sockaddr_any6(&any);
572 break;
574 if (isc_sockaddr_equal(&sa, &any))
575 return (ISC_R_SUCCESS);
576 isc_sockaddr_format(&sa, buf, sizeof(buf));
577 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
578 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
579 "could not get query source dispatcher (%s)",
580 buf);
581 return (result);
584 *dispatchp = disp;
586 return (ISC_R_SUCCESS);
589 static isc_result_t
590 configure_order(dns_order_t *order, const cfg_obj_t *ent) {
591 dns_rdataclass_t rdclass;
592 dns_rdatatype_t rdtype;
593 const cfg_obj_t *obj;
594 dns_fixedname_t fixed;
595 unsigned int mode = 0;
596 const char *str;
597 isc_buffer_t b;
598 isc_result_t result;
599 isc_boolean_t addroot;
601 result = ns_config_getclass(cfg_tuple_get(ent, "class"),
602 dns_rdataclass_any, &rdclass);
603 if (result != ISC_R_SUCCESS)
604 return (result);
606 result = ns_config_gettype(cfg_tuple_get(ent, "type"),
607 dns_rdatatype_any, &rdtype);
608 if (result != ISC_R_SUCCESS)
609 return (result);
611 obj = cfg_tuple_get(ent, "name");
612 if (cfg_obj_isstring(obj))
613 str = cfg_obj_asstring(obj);
614 else
615 str = "*";
616 addroot = ISC_TF(strcmp(str, "*") == 0);
617 isc_buffer_init(&b, str, strlen(str));
618 isc_buffer_add(&b, strlen(str));
619 dns_fixedname_init(&fixed);
620 result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
621 dns_rootname, ISC_FALSE, NULL);
622 if (result != ISC_R_SUCCESS)
623 return (result);
625 obj = cfg_tuple_get(ent, "ordering");
626 INSIST(cfg_obj_isstring(obj));
627 str = cfg_obj_asstring(obj);
628 if (!strcasecmp(str, "fixed"))
629 mode = DNS_RDATASETATTR_FIXEDORDER;
630 else if (!strcasecmp(str, "random"))
631 mode = DNS_RDATASETATTR_RANDOMIZE;
632 else if (!strcasecmp(str, "cyclic"))
633 mode = 0;
634 else
635 INSIST(0);
638 * "*" should match everything including the root (BIND 8 compat).
639 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
640 * explicit entry for "." when the name is "*".
642 if (addroot) {
643 result = dns_order_add(order, dns_rootname,
644 rdtype, rdclass, mode);
645 if (result != ISC_R_SUCCESS)
646 return (result);
649 return (dns_order_add(order, dns_fixedname_name(&fixed),
650 rdtype, rdclass, mode));
653 static isc_result_t
654 configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
655 isc_netaddr_t na;
656 dns_peer_t *peer;
657 const cfg_obj_t *obj;
658 const char *str;
659 isc_result_t result;
660 unsigned int prefixlen;
662 cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
664 peer = NULL;
665 result = dns_peer_new(mctx, &na, &peer);
666 if (result != ISC_R_SUCCESS)
667 return (result);
669 obj = NULL;
670 (void)cfg_map_get(cpeer, "bogus", &obj);
671 if (obj != NULL)
672 CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
674 obj = NULL;
675 (void)cfg_map_get(cpeer, "provide-ixfr", &obj);
676 if (obj != NULL)
677 CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
679 obj = NULL;
680 (void)cfg_map_get(cpeer, "request-ixfr", &obj);
681 if (obj != NULL)
682 CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
684 obj = NULL;
685 (void)cfg_map_get(cpeer, "edns", &obj);
686 if (obj != NULL)
687 CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
689 obj = NULL;
690 (void)cfg_map_get(cpeer, "edns-udp-size", &obj);
691 if (obj != NULL) {
692 isc_uint32_t udpsize = cfg_obj_asuint32(obj);
693 if (udpsize < 512)
694 udpsize = 512;
695 if (udpsize > 4096)
696 udpsize = 4096;
697 CHECK(dns_peer_setudpsize(peer, (isc_uint16_t)udpsize));
700 obj = NULL;
701 (void)cfg_map_get(cpeer, "max-udp-size", &obj);
702 if (obj != NULL) {
703 isc_uint32_t udpsize = cfg_obj_asuint32(obj);
704 if (udpsize < 512)
705 udpsize = 512;
706 if (udpsize > 4096)
707 udpsize = 4096;
708 CHECK(dns_peer_setmaxudp(peer, (isc_uint16_t)udpsize));
711 obj = NULL;
712 (void)cfg_map_get(cpeer, "transfers", &obj);
713 if (obj != NULL)
714 CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
716 obj = NULL;
717 (void)cfg_map_get(cpeer, "transfer-format", &obj);
718 if (obj != NULL) {
719 str = cfg_obj_asstring(obj);
720 if (strcasecmp(str, "many-answers") == 0)
721 CHECK(dns_peer_settransferformat(peer,
722 dns_many_answers));
723 else if (strcasecmp(str, "one-answer") == 0)
724 CHECK(dns_peer_settransferformat(peer,
725 dns_one_answer));
726 else
727 INSIST(0);
730 obj = NULL;
731 (void)cfg_map_get(cpeer, "keys", &obj);
732 if (obj != NULL) {
733 result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
734 if (result != ISC_R_SUCCESS)
735 goto cleanup;
738 obj = NULL;
739 if (na.family == AF_INET)
740 (void)cfg_map_get(cpeer, "transfer-source", &obj);
741 else
742 (void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
743 if (obj != NULL) {
744 result = dns_peer_settransfersource(peer,
745 cfg_obj_assockaddr(obj));
746 if (result != ISC_R_SUCCESS)
747 goto cleanup;
748 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
751 obj = NULL;
752 if (na.family == AF_INET)
753 (void)cfg_map_get(cpeer, "notify-source", &obj);
754 else
755 (void)cfg_map_get(cpeer, "notify-source-v6", &obj);
756 if (obj != NULL) {
757 result = dns_peer_setnotifysource(peer,
758 cfg_obj_assockaddr(obj));
759 if (result != ISC_R_SUCCESS)
760 goto cleanup;
761 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
764 obj = NULL;
765 if (na.family == AF_INET)
766 (void)cfg_map_get(cpeer, "query-source", &obj);
767 else
768 (void)cfg_map_get(cpeer, "query-source-v6", &obj);
769 if (obj != NULL) {
770 result = dns_peer_setquerysource(peer,
771 cfg_obj_assockaddr(obj));
772 if (result != ISC_R_SUCCESS)
773 goto cleanup;
774 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
777 *peerp = peer;
778 return (ISC_R_SUCCESS);
780 cleanup:
781 dns_peer_detach(&peer);
782 return (result);
785 static isc_result_t
786 disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
787 isc_result_t result;
788 const cfg_obj_t *algorithms;
789 const cfg_listelt_t *element;
790 const char *str;
791 dns_fixedname_t fixed;
792 dns_name_t *name;
793 isc_buffer_t b;
795 dns_fixedname_init(&fixed);
796 name = dns_fixedname_name(&fixed);
797 str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
798 isc_buffer_init(&b, str, strlen(str));
799 isc_buffer_add(&b, strlen(str));
800 CHECK(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL));
802 algorithms = cfg_tuple_get(disabled, "algorithms");
803 for (element = cfg_list_first(algorithms);
804 element != NULL;
805 element = cfg_list_next(element))
807 isc_textregion_t r;
808 dns_secalg_t alg;
810 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
811 r.length = strlen(r.base);
813 result = dns_secalg_fromtext(&alg, &r);
814 if (result != ISC_R_SUCCESS) {
815 isc_uint8_t ui;
816 result = isc_parse_uint8(&ui, r.base, 10);
817 alg = ui;
819 if (result != ISC_R_SUCCESS) {
820 cfg_obj_log(cfg_listelt_value(element),
821 ns_g_lctx, ISC_LOG_ERROR,
822 "invalid algorithm");
823 CHECK(result);
825 CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
827 cleanup:
828 return (result);
831 static isc_boolean_t
832 on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
833 const cfg_listelt_t *element;
834 dns_fixedname_t fixed;
835 dns_name_t *name;
836 isc_result_t result;
837 const cfg_obj_t *value;
838 const char *str;
839 isc_buffer_t b;
841 dns_fixedname_init(&fixed);
842 name = dns_fixedname_name(&fixed);
844 for (element = cfg_list_first(disablelist);
845 element != NULL;
846 element = cfg_list_next(element))
848 value = cfg_listelt_value(element);
849 str = cfg_obj_asstring(value);
850 isc_buffer_init(&b, str, strlen(str));
851 isc_buffer_add(&b, strlen(str));
852 result = dns_name_fromtext(name, &b, dns_rootname,
853 ISC_TRUE, NULL);
854 RUNTIME_CHECK(result == ISC_R_SUCCESS);
855 if (dns_name_equal(name, zonename))
856 return (ISC_TRUE);
858 return (ISC_FALSE);
861 static void
862 check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv,
863 isc_mem_t *mctx)
865 char **argv = NULL;
866 unsigned int i;
867 isc_result_t result;
869 result = dns_zone_getdbtype(*zonep, &argv, mctx);
870 if (result != ISC_R_SUCCESS) {
871 dns_zone_detach(zonep);
872 return;
876 * Check that all the arguments match.
878 for (i = 0; i < dbtypec; i++)
879 if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0) {
880 dns_zone_detach(zonep);
881 break;
885 * Check that there are not extra arguments.
887 if (i == dbtypec && argv[i] != NULL)
888 dns_zone_detach(zonep);
889 isc_mem_free(mctx, argv);
894 * Configure 'view' according to 'vconfig', taking defaults from 'config'
895 * where values are missing in 'vconfig'.
897 * When configuring the default view, 'vconfig' will be NULL and the
898 * global defaults in 'config' used exclusively.
900 static isc_result_t
901 configure_view(dns_view_t *view, const cfg_obj_t *config,
902 const cfg_obj_t *vconfig, isc_mem_t *mctx,
903 cfg_aclconfctx_t *actx, isc_boolean_t need_hints)
905 const cfg_obj_t *maps[4];
906 const cfg_obj_t *cfgmaps[3];
907 const cfg_obj_t *options = NULL;
908 const cfg_obj_t *voptions = NULL;
909 const cfg_obj_t *forwardtype;
910 const cfg_obj_t *forwarders;
911 const cfg_obj_t *alternates;
912 const cfg_obj_t *zonelist;
913 #ifdef DLZ
914 const cfg_obj_t *dlz;
915 unsigned int dlzargc;
916 char **dlzargv;
917 #endif
918 const cfg_obj_t *disabled;
919 const cfg_obj_t *obj;
920 const cfg_listelt_t *element;
921 in_port_t port;
922 dns_cache_t *cache = NULL;
923 isc_result_t result;
924 isc_uint32_t max_adb_size;
925 isc_uint32_t max_cache_size;
926 isc_uint32_t max_acache_size;
927 isc_uint32_t lame_ttl;
928 dns_tsig_keyring_t *ring;
929 dns_view_t *pview = NULL; /* Production view */
930 isc_mem_t *cmctx;
931 dns_dispatch_t *dispatch4 = NULL;
932 dns_dispatch_t *dispatch6 = NULL;
933 isc_boolean_t reused_cache = ISC_FALSE;
934 int i;
935 const char *str;
936 dns_order_t *order = NULL;
937 isc_uint32_t udpsize;
938 unsigned int check = 0;
939 dns_zone_t *zone = NULL;
940 isc_uint32_t max_clients_per_query;
941 const char *sep = ": view ";
942 const char *viewname = view->name;
943 const char *forview = " for view ";
944 isc_boolean_t rfc1918;
945 isc_boolean_t empty_zones_enable;
946 const cfg_obj_t *disablelist = NULL;
948 REQUIRE(DNS_VIEW_VALID(view));
950 cmctx = NULL;
952 if (config != NULL)
953 (void)cfg_map_get(config, "options", &options);
955 i = 0;
956 if (vconfig != NULL) {
957 voptions = cfg_tuple_get(vconfig, "options");
958 maps[i++] = voptions;
960 if (options != NULL)
961 maps[i++] = options;
962 maps[i++] = ns_g_defaults;
963 maps[i] = NULL;
965 i = 0;
966 if (voptions != NULL)
967 cfgmaps[i++] = voptions;
968 if (config != NULL)
969 cfgmaps[i++] = config;
970 cfgmaps[i] = NULL;
972 if (!strcmp(viewname, "_default")) {
973 sep = "";
974 viewname = "";
975 forview = "";
979 * Set the view's port number for outgoing queries.
981 CHECKM(ns_config_getport(config, &port), "port");
982 dns_view_setdstport(view, port);
985 * Create additional cache for this view and zones under the view
986 * if explicitly enabled.
987 * XXX950 default to on.
989 obj = NULL;
990 (void)ns_config_get(maps, "acache-enable", &obj);
991 if (obj != NULL && cfg_obj_asboolean(obj)) {
992 cmctx = NULL;
993 CHECK(isc_mem_create(0, 0, &cmctx));
994 CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr,
995 ns_g_timermgr));
996 isc_mem_detach(&cmctx);
998 if (view->acache != NULL) {
999 obj = NULL;
1000 result = ns_config_get(maps, "acache-cleaning-interval", &obj);
1001 INSIST(result == ISC_R_SUCCESS);
1002 dns_acache_setcleaninginterval(view->acache,
1003 cfg_obj_asuint32(obj) * 60);
1005 obj = NULL;
1006 result = ns_config_get(maps, "max-acache-size", &obj);
1007 INSIST(result == ISC_R_SUCCESS);
1008 if (cfg_obj_isstring(obj)) {
1009 str = cfg_obj_asstring(obj);
1010 INSIST(strcasecmp(str, "unlimited") == 0);
1011 max_acache_size = ISC_UINT32_MAX;
1012 } else {
1013 isc_resourcevalue_t value;
1015 value = cfg_obj_asuint64(obj);
1016 if (value > ISC_UINT32_MAX) {
1017 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1018 "'max-acache-size "
1019 "%" ISC_PRINT_QUADFORMAT
1020 "d' is too large",
1021 value);
1022 result = ISC_R_RANGE;
1023 goto cleanup;
1025 max_acache_size = (isc_uint32_t)value;
1027 dns_acache_setcachesize(view->acache, max_acache_size);
1031 * Configure the zones.
1033 zonelist = NULL;
1034 if (voptions != NULL)
1035 (void)cfg_map_get(voptions, "zone", &zonelist);
1036 else
1037 (void)cfg_map_get(config, "zone", &zonelist);
1038 for (element = cfg_list_first(zonelist);
1039 element != NULL;
1040 element = cfg_list_next(element))
1042 const cfg_obj_t *zconfig = cfg_listelt_value(element);
1043 CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
1044 actx));
1047 #ifdef DLZ
1049 * Create Dynamically Loadable Zone driver.
1051 dlz = NULL;
1052 if (voptions != NULL)
1053 (void)cfg_map_get(voptions, "dlz", &dlz);
1054 else
1055 (void)cfg_map_get(config, "dlz", &dlz);
1057 obj = NULL;
1058 if (dlz != NULL) {
1059 (void)cfg_map_get(cfg_tuple_get(dlz, "options"),
1060 "database", &obj);
1061 if (obj != NULL) {
1062 char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
1063 if (s == NULL) {
1064 result = ISC_R_NOMEMORY;
1065 goto cleanup;
1068 result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv);
1069 if (result != ISC_R_SUCCESS) {
1070 isc_mem_free(mctx, s);
1071 goto cleanup;
1074 obj = cfg_tuple_get(dlz, "name");
1075 result = dns_dlzcreate(mctx, cfg_obj_asstring(obj),
1076 dlzargv[0], dlzargc, dlzargv,
1077 &view->dlzdatabase);
1078 isc_mem_free(mctx, s);
1079 isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
1080 if (result != ISC_R_SUCCESS)
1081 goto cleanup;
1084 #endif
1087 * Configure the view's cache. Try to reuse an existing
1088 * cache if possible, otherwise create a new cache.
1089 * Note that the ADB is not preserved in either case.
1091 * XXX Determining when it is safe to reuse a cache is
1092 * tricky. When the view's configuration changes, the cached
1093 * data may become invalid because it reflects our old
1094 * view of the world. As more view attributes become
1095 * configurable, we will have to add code here to check
1096 * whether they have changed in ways that could
1097 * invalidate the cache.
1099 result = dns_viewlist_find(&ns_g_server->viewlist,
1100 view->name, view->rdclass,
1101 &pview);
1102 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
1103 goto cleanup;
1104 if (pview != NULL) {
1105 INSIST(pview->cache != NULL);
1106 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1107 NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3),
1108 "reusing existing cache");
1109 reused_cache = ISC_TRUE;
1110 dns_cache_attach(pview->cache, &cache);
1111 dns_view_detach(&pview);
1112 } else {
1113 CHECK(isc_mem_create(0, 0, &cmctx));
1114 CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr,
1115 view->rdclass, "rbt", 0, NULL, &cache));
1117 dns_view_setcache(view, cache);
1120 * cache-file cannot be inherited if views are present, but this
1121 * should be caught by the configuration checking stage.
1123 obj = NULL;
1124 result = ns_config_get(maps, "cache-file", &obj);
1125 if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
1126 CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
1127 if (!reused_cache)
1128 CHECK(dns_cache_load(cache));
1131 obj = NULL;
1132 result = ns_config_get(maps, "cleaning-interval", &obj);
1133 INSIST(result == ISC_R_SUCCESS);
1134 dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60);
1136 obj = NULL;
1137 result = ns_config_get(maps, "max-cache-size", &obj);
1138 INSIST(result == ISC_R_SUCCESS);
1139 if (cfg_obj_isstring(obj)) {
1140 str = cfg_obj_asstring(obj);
1141 INSIST(strcasecmp(str, "unlimited") == 0);
1142 max_cache_size = ISC_UINT32_MAX;
1143 } else {
1144 isc_resourcevalue_t value;
1145 value = cfg_obj_asuint64(obj);
1146 if (value > ISC_UINT32_MAX) {
1147 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1148 "'max-cache-size "
1149 "%" ISC_PRINT_QUADFORMAT "d' is too large",
1150 value);
1151 result = ISC_R_RANGE;
1152 goto cleanup;
1154 max_cache_size = (isc_uint32_t)value;
1156 dns_cache_setcachesize(cache, max_cache_size);
1158 dns_cache_detach(&cache);
1161 * Check-names.
1163 obj = NULL;
1164 result = ns_checknames_get(maps, "response", &obj);
1165 INSIST(result == ISC_R_SUCCESS);
1167 str = cfg_obj_asstring(obj);
1168 if (strcasecmp(str, "fail") == 0) {
1169 check = DNS_RESOLVER_CHECKNAMES |
1170 DNS_RESOLVER_CHECKNAMESFAIL;
1171 view->checknames = ISC_TRUE;
1172 } else if (strcasecmp(str, "warn") == 0) {
1173 check = DNS_RESOLVER_CHECKNAMES;
1174 view->checknames = ISC_FALSE;
1175 } else if (strcasecmp(str, "ignore") == 0) {
1176 check = 0;
1177 view->checknames = ISC_FALSE;
1178 } else
1179 INSIST(0);
1182 * Resolver.
1184 * XXXRTH Hardwired number of tasks.
1186 CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4));
1187 CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6));
1188 if (dispatch4 == NULL && dispatch6 == NULL) {
1189 UNEXPECTED_ERROR(__FILE__, __LINE__,
1190 "unable to obtain neither an IPv4 nor"
1191 " an IPv6 dispatch");
1192 result = ISC_R_UNEXPECTED;
1193 goto cleanup;
1195 CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31,
1196 ns_g_socketmgr, ns_g_timermgr,
1197 check, ns_g_dispatchmgr,
1198 dispatch4, dispatch6));
1201 * Set the ADB cache size to 1/8th of the max-cache-size.
1203 max_adb_size = 0;
1204 if (max_cache_size != 0) {
1205 max_adb_size = max_cache_size / 8;
1206 if (max_adb_size == 0)
1207 max_adb_size = 1; /* Force minimum. */
1209 dns_adb_setadbsize(view->adb, max_adb_size);
1212 * Set resolver's lame-ttl.
1214 obj = NULL;
1215 result = ns_config_get(maps, "lame-ttl", &obj);
1216 INSIST(result == ISC_R_SUCCESS);
1217 lame_ttl = cfg_obj_asuint32(obj);
1218 if (lame_ttl > 1800)
1219 lame_ttl = 1800;
1220 dns_resolver_setlamettl(view->resolver, lame_ttl);
1222 obj = NULL;
1223 result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
1224 INSIST(result == ISC_R_SUCCESS);
1225 dns_resolver_setzeronosoattl(view->resolver, cfg_obj_asboolean(obj));
1228 * Set the resolver's EDNS UDP size.
1230 obj = NULL;
1231 result = ns_config_get(maps, "edns-udp-size", &obj);
1232 INSIST(result == ISC_R_SUCCESS);
1233 udpsize = cfg_obj_asuint32(obj);
1234 if (udpsize < 512)
1235 udpsize = 512;
1236 if (udpsize > 4096)
1237 udpsize = 4096;
1238 dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize);
1241 * Set the maximum UDP response size.
1243 obj = NULL;
1244 result = ns_config_get(maps, "max-udp-size", &obj);
1245 INSIST(result == ISC_R_SUCCESS);
1246 udpsize = cfg_obj_asuint32(obj);
1247 if (udpsize < 512)
1248 udpsize = 512;
1249 if (udpsize > 4096)
1250 udpsize = 4096;
1251 view->maxudp = udpsize;
1254 * Set supported DNSSEC algorithms.
1256 dns_resolver_reset_algorithms(view->resolver);
1257 disabled = NULL;
1258 (void)ns_config_get(maps, "disable-algorithms", &disabled);
1259 if (disabled != NULL) {
1260 for (element = cfg_list_first(disabled);
1261 element != NULL;
1262 element = cfg_list_next(element))
1263 CHECK(disable_algorithms(cfg_listelt_value(element),
1264 view->resolver));
1268 * A global or view "forwarders" option, if present,
1269 * creates an entry for "." in the forwarding table.
1271 forwardtype = NULL;
1272 forwarders = NULL;
1273 (void)ns_config_get(maps, "forward", &forwardtype);
1274 (void)ns_config_get(maps, "forwarders", &forwarders);
1275 if (forwarders != NULL)
1276 CHECK(configure_forward(config, view, dns_rootname,
1277 forwarders, forwardtype));
1280 * Dual Stack Servers.
1282 alternates = NULL;
1283 (void)ns_config_get(maps, "dual-stack-servers", &alternates);
1284 if (alternates != NULL)
1285 CHECK(configure_alternates(config, view, alternates));
1288 * We have default hints for class IN if we need them.
1290 if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
1291 dns_view_sethints(view, ns_g_server->in_roothints);
1294 * If we still have no hints, this is a non-IN view with no
1295 * "hints zone" configured. Issue a warning, except if this
1296 * is a root server. Root servers never need to consult
1297 * their hints, so it's no point requiring users to configure
1298 * them.
1300 if (view->hints == NULL) {
1301 dns_zone_t *rootzone = NULL;
1302 (void)dns_view_findzone(view, dns_rootname, &rootzone);
1303 if (rootzone != NULL) {
1304 dns_zone_detach(&rootzone);
1305 need_hints = ISC_FALSE;
1307 if (need_hints)
1308 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1309 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1310 "no root hints for view '%s'",
1311 view->name);
1315 * Configure the view's TSIG keys.
1317 ring = NULL;
1318 CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
1319 dns_view_setkeyring(view, ring);
1322 * Configure the view's peer list.
1325 const cfg_obj_t *peers = NULL;
1326 const cfg_listelt_t *element;
1327 dns_peerlist_t *newpeers = NULL;
1329 (void)ns_config_get(cfgmaps, "server", &peers);
1330 CHECK(dns_peerlist_new(mctx, &newpeers));
1331 for (element = cfg_list_first(peers);
1332 element != NULL;
1333 element = cfg_list_next(element))
1335 const cfg_obj_t *cpeer = cfg_listelt_value(element);
1336 dns_peer_t *peer;
1338 CHECK(configure_peer(cpeer, mctx, &peer));
1339 dns_peerlist_addpeer(newpeers, peer);
1340 dns_peer_detach(&peer);
1342 dns_peerlist_detach(&view->peers);
1343 view->peers = newpeers; /* Transfer ownership. */
1347 * Configure the views rrset-order.
1350 const cfg_obj_t *rrsetorder = NULL;
1351 const cfg_listelt_t *element;
1353 (void)ns_config_get(maps, "rrset-order", &rrsetorder);
1354 CHECK(dns_order_create(mctx, &order));
1355 for (element = cfg_list_first(rrsetorder);
1356 element != NULL;
1357 element = cfg_list_next(element))
1359 const cfg_obj_t *ent = cfg_listelt_value(element);
1361 CHECK(configure_order(order, ent));
1363 if (view->order != NULL)
1364 dns_order_detach(&view->order);
1365 dns_order_attach(order, &view->order);
1366 dns_order_detach(&order);
1369 * Copy the aclenv object.
1371 dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv);
1374 * Configure the "match-clients" and "match-destinations" ACL.
1376 CHECK(configure_view_acl(vconfig, config, "match-clients", actx,
1377 ns_g_mctx, &view->matchclients));
1378 CHECK(configure_view_acl(vconfig, config, "match-destinations", actx,
1379 ns_g_mctx, &view->matchdestinations));
1382 * Configure the "match-recursive-only" option.
1384 obj = NULL;
1385 (void)ns_config_get(maps, "match-recursive-only", &obj);
1386 if (obj != NULL && cfg_obj_asboolean(obj))
1387 view->matchrecursiveonly = ISC_TRUE;
1388 else
1389 view->matchrecursiveonly = ISC_FALSE;
1392 * Configure other configurable data.
1394 obj = NULL;
1395 result = ns_config_get(maps, "recursion", &obj);
1396 INSIST(result == ISC_R_SUCCESS);
1397 view->recursion = cfg_obj_asboolean(obj);
1399 obj = NULL;
1400 result = ns_config_get(maps, "auth-nxdomain", &obj);
1401 INSIST(result == ISC_R_SUCCESS);
1402 view->auth_nxdomain = cfg_obj_asboolean(obj);
1404 obj = NULL;
1405 result = ns_config_get(maps, "minimal-responses", &obj);
1406 INSIST(result == ISC_R_SUCCESS);
1407 view->minimalresponses = cfg_obj_asboolean(obj);
1409 obj = NULL;
1410 result = ns_config_get(maps, "transfer-format", &obj);
1411 INSIST(result == ISC_R_SUCCESS);
1412 str = cfg_obj_asstring(obj);
1413 if (strcasecmp(str, "many-answers") == 0)
1414 view->transfer_format = dns_many_answers;
1415 else if (strcasecmp(str, "one-answer") == 0)
1416 view->transfer_format = dns_one_answer;
1417 else
1418 INSIST(0);
1421 * Set sources where additional data and CNAME/DNAME
1422 * targets for authoritative answers may be found.
1424 obj = NULL;
1425 result = ns_config_get(maps, "additional-from-auth", &obj);
1426 INSIST(result == ISC_R_SUCCESS);
1427 view->additionalfromauth = cfg_obj_asboolean(obj);
1428 if (view->recursion && ! view->additionalfromauth) {
1429 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
1430 "'additional-from-auth no' is only supported "
1431 "with 'recursion no'");
1432 view->additionalfromauth = ISC_TRUE;
1435 obj = NULL;
1436 result = ns_config_get(maps, "additional-from-cache", &obj);
1437 INSIST(result == ISC_R_SUCCESS);
1438 view->additionalfromcache = cfg_obj_asboolean(obj);
1439 if (view->recursion && ! view->additionalfromcache) {
1440 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
1441 "'additional-from-cache no' is only supported "
1442 "with 'recursion no'");
1443 view->additionalfromcache = ISC_TRUE;
1447 * Set "allow-query-cache" and "allow-recursion" acls if
1448 * configured in named.conf.
1450 CHECK(configure_view_acl(vconfig, config, "allow-query-cache",
1451 actx, ns_g_mctx, &view->queryacl));
1453 if (strcmp(view->name, "_bind") != 0)
1454 CHECK(configure_view_acl(vconfig, config, "allow-recursion",
1455 actx, ns_g_mctx, &view->recursionacl));
1458 * Warning if both "recursion no;" and allow-recursion are active
1459 * except for "allow-recursion { none; };".
1461 if (!view->recursion && view->recursionacl != NULL &&
1462 (view->recursionacl->length != 1 ||
1463 view->recursionacl->elements[0].type != dns_aclelementtype_any ||
1464 view->recursionacl->elements[0].negative != ISC_TRUE))
1465 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1466 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1467 "both \"recursion no;\" and \"allow-recursion\" "
1468 "active%s%s", forview, viewname);
1471 * "allow-query-cache" inherits from "allow-recursion" if set,
1472 * otherwise from "allow-query" if set.
1473 * "allow-recursion" inherits from "allow-query-cache" if set,
1474 * otherwise from "allow-query" if set.
1476 if (view->queryacl == NULL && view->recursionacl != NULL)
1477 dns_acl_attach(view->recursionacl, &view->queryacl);
1478 if (view->queryacl == NULL)
1479 CHECK(configure_view_acl(vconfig, config, "allow-query",
1480 actx, ns_g_mctx, &view->queryacl));
1481 if (view->recursionacl == NULL && view->queryacl != NULL)
1482 dns_acl_attach(view->queryacl, &view->recursionacl);
1485 * Set default "allow-recursion" and "allow-query-cache" acls.
1487 if (view->recursionacl == NULL && view->recursion)
1488 CHECK(configure_view_acl(NULL, ns_g_config, "allow-recursion",
1489 actx, ns_g_mctx, &view->recursionacl));
1490 if (view->queryacl == NULL)
1491 CHECK(configure_view_acl(NULL, ns_g_config,
1492 "allow-query-cache", actx,
1493 ns_g_mctx, &view->queryacl));
1495 CHECK(configure_view_acl(vconfig, config, "sortlist",
1496 actx, ns_g_mctx, &view->sortlist));
1498 obj = NULL;
1499 result = ns_config_get(maps, "request-ixfr", &obj);
1500 INSIST(result == ISC_R_SUCCESS);
1501 view->requestixfr = cfg_obj_asboolean(obj);
1503 obj = NULL;
1504 result = ns_config_get(maps, "provide-ixfr", &obj);
1505 INSIST(result == ISC_R_SUCCESS);
1506 view->provideixfr = cfg_obj_asboolean(obj);
1508 obj = NULL;
1509 result = ns_config_get(maps, "max-clients-per-query", &obj);
1510 INSIST(result == ISC_R_SUCCESS);
1511 max_clients_per_query = cfg_obj_asuint32(obj);
1513 obj = NULL;
1514 result = ns_config_get(maps, "clients-per-query", &obj);
1515 INSIST(result == ISC_R_SUCCESS);
1516 dns_resolver_setclientsperquery(view->resolver,
1517 cfg_obj_asuint32(obj),
1518 max_clients_per_query);
1520 obj = NULL;
1521 result = ns_config_get(maps, "dnssec-enable", &obj);
1522 INSIST(result == ISC_R_SUCCESS);
1523 view->enablednssec = cfg_obj_asboolean(obj);
1525 obj = NULL;
1526 result = ns_config_get(maps, "dnssec-accept-expired", &obj);
1527 INSIST(result == ISC_R_SUCCESS);
1528 view->acceptexpired = cfg_obj_asboolean(obj);
1530 obj = NULL;
1531 result = ns_config_get(maps, "dnssec-validation", &obj);
1532 INSIST(result == ISC_R_SUCCESS);
1533 view->enablevalidation = cfg_obj_asboolean(obj);
1535 obj = NULL;
1536 result = ns_config_get(maps, "dnssec-lookaside", &obj);
1537 if (result == ISC_R_SUCCESS) {
1538 for (element = cfg_list_first(obj);
1539 element != NULL;
1540 element = cfg_list_next(element))
1542 const char *str;
1543 isc_buffer_t b;
1544 dns_name_t *dlv;
1546 obj = cfg_listelt_value(element);
1547 #if 0
1548 dns_fixedname_t fixed;
1549 dns_name_t *name;
1552 * When we support multiple dnssec-lookaside
1553 * entries this is how to find the domain to be
1554 * checked. XXXMPA
1556 dns_fixedname_init(&fixed);
1557 name = dns_fixedname_name(&fixed);
1558 str = cfg_obj_asstring(cfg_tuple_get(obj,
1559 "domain"));
1560 isc_buffer_init(&b, str, strlen(str));
1561 isc_buffer_add(&b, strlen(str));
1562 CHECK(dns_name_fromtext(name, &b, dns_rootname,
1563 ISC_TRUE, NULL));
1564 #endif
1565 str = cfg_obj_asstring(cfg_tuple_get(obj,
1566 "trust-anchor"));
1567 isc_buffer_init(&b, str, strlen(str));
1568 isc_buffer_add(&b, strlen(str));
1569 dlv = dns_fixedname_name(&view->dlv_fixed);
1570 CHECK(dns_name_fromtext(dlv, &b, dns_rootname,
1571 ISC_TRUE, NULL));
1572 view->dlv = dns_fixedname_name(&view->dlv_fixed);
1574 } else
1575 view->dlv = NULL;
1578 * For now, there is only one kind of trusted keys, the
1579 * "security roots".
1581 CHECK(configure_view_dnsseckeys(vconfig, config, mctx,
1582 &view->secroots));
1583 dns_resolver_resetmustbesecure(view->resolver);
1584 obj = NULL;
1585 result = ns_config_get(maps, "dnssec-must-be-secure", &obj);
1586 if (result == ISC_R_SUCCESS)
1587 CHECK(mustbesecure(obj, view->resolver));
1589 obj = NULL;
1590 result = ns_config_get(maps, "max-cache-ttl", &obj);
1591 INSIST(result == ISC_R_SUCCESS);
1592 view->maxcachettl = cfg_obj_asuint32(obj);
1594 obj = NULL;
1595 result = ns_config_get(maps, "max-ncache-ttl", &obj);
1596 INSIST(result == ISC_R_SUCCESS);
1597 view->maxncachettl = cfg_obj_asuint32(obj);
1598 if (view->maxncachettl > 7 * 24 * 3600)
1599 view->maxncachettl = 7 * 24 * 3600;
1601 obj = NULL;
1602 result = ns_config_get(maps, "preferred-glue", &obj);
1603 if (result == ISC_R_SUCCESS) {
1604 str = cfg_obj_asstring(obj);
1605 if (strcasecmp(str, "a") == 0)
1606 view->preferred_glue = dns_rdatatype_a;
1607 else if (strcasecmp(str, "aaaa") == 0)
1608 view->preferred_glue = dns_rdatatype_aaaa;
1609 else
1610 view->preferred_glue = 0;
1611 } else
1612 view->preferred_glue = 0;
1614 obj = NULL;
1615 result = ns_config_get(maps, "root-delegation-only", &obj);
1616 if (result == ISC_R_SUCCESS) {
1617 dns_view_setrootdelonly(view, ISC_TRUE);
1618 if (!cfg_obj_isvoid(obj)) {
1619 dns_fixedname_t fixed;
1620 dns_name_t *name;
1621 isc_buffer_t b;
1622 const char *str;
1623 const cfg_obj_t *exclude;
1625 dns_fixedname_init(&fixed);
1626 name = dns_fixedname_name(&fixed);
1627 for (element = cfg_list_first(obj);
1628 element != NULL;
1629 element = cfg_list_next(element)) {
1630 exclude = cfg_listelt_value(element);
1631 str = cfg_obj_asstring(exclude);
1632 isc_buffer_init(&b, str, strlen(str));
1633 isc_buffer_add(&b, strlen(str));
1634 CHECK(dns_name_fromtext(name, &b, dns_rootname,
1635 ISC_FALSE, NULL));
1636 CHECK(dns_view_excludedelegationonly(view,
1637 name));
1640 } else
1641 dns_view_setrootdelonly(view, ISC_FALSE);
1644 * Setup automatic empty zones. If recursion is off then
1645 * they are disabled by default.
1647 obj = NULL;
1648 (void)ns_config_get(maps, "empty-zones-enable", &obj);
1649 (void)ns_config_get(maps, "disable-empty-zone", &disablelist);
1650 if (obj == NULL && disablelist == NULL &&
1651 view->rdclass == dns_rdataclass_in) {
1652 rfc1918 = ISC_FALSE;
1653 empty_zones_enable = view->recursion;
1654 } else if (view->rdclass == dns_rdataclass_in) {
1655 rfc1918 = ISC_TRUE;
1656 if (obj != NULL)
1657 empty_zones_enable = cfg_obj_asboolean(obj);
1658 else
1659 empty_zones_enable = view->recursion;
1660 } else {
1661 rfc1918 = ISC_FALSE;
1662 empty_zones_enable = ISC_FALSE;
1664 if (empty_zones_enable) {
1665 const char *empty;
1666 int empty_zone = 0;
1667 dns_fixedname_t fixed;
1668 dns_name_t *name;
1669 isc_buffer_t buffer;
1670 const char *str;
1671 char server[DNS_NAME_FORMATSIZE + 1];
1672 char contact[DNS_NAME_FORMATSIZE + 1];
1673 isc_boolean_t logit;
1674 const char *empty_dbtype[4] =
1675 { "_builtin", "empty", NULL, NULL };
1676 int empty_dbtypec = 4;
1678 dns_fixedname_init(&fixed);
1679 name = dns_fixedname_name(&fixed);
1681 obj = NULL;
1682 result = ns_config_get(maps, "empty-server", &obj);
1683 if (result == ISC_R_SUCCESS) {
1684 str = cfg_obj_asstring(obj);
1685 isc_buffer_init(&buffer, str, strlen(str));
1686 isc_buffer_add(&buffer, strlen(str));
1687 CHECK(dns_name_fromtext(name, &buffer, dns_rootname,
1688 ISC_FALSE, NULL));
1689 isc_buffer_init(&buffer, server, sizeof(server) - 1);
1690 CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
1691 server[isc_buffer_usedlength(&buffer)] = 0;
1692 empty_dbtype[2] = server;
1693 } else
1694 empty_dbtype[2] = "@";
1696 obj = NULL;
1697 result = ns_config_get(maps, "empty-contact", &obj);
1698 if (result == ISC_R_SUCCESS) {
1699 str = cfg_obj_asstring(obj);
1700 isc_buffer_init(&buffer, str, strlen(str));
1701 isc_buffer_add(&buffer, strlen(str));
1702 CHECK(dns_name_fromtext(name, &buffer, dns_rootname,
1703 ISC_FALSE, NULL));
1704 isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
1705 CHECK(dns_name_totext(name, ISC_FALSE, &buffer));
1706 contact[isc_buffer_usedlength(&buffer)] = 0;
1707 empty_dbtype[3] = contact;
1708 } else
1709 empty_dbtype[3] = ".";
1711 logit = ISC_TRUE;
1712 for (empty = empty_zones[empty_zone].zone;
1713 empty != NULL;
1714 empty = empty_zones[++empty_zone].zone)
1716 dns_forwarders_t *forwarders = NULL;
1717 dns_view_t *pview = NULL;
1719 isc_buffer_init(&buffer, empty, strlen(empty));
1720 isc_buffer_add(&buffer, strlen(empty));
1722 * Look for zone on drop list.
1724 CHECK(dns_name_fromtext(name, &buffer, dns_rootname,
1725 ISC_FALSE, NULL));
1726 if (disablelist != NULL &&
1727 on_disable_list(disablelist, name))
1728 continue;
1731 * This zone already exists.
1733 (void)dns_view_findzone(view, name, &zone);
1734 if (zone != NULL) {
1735 dns_zone_detach(&zone);
1736 continue;
1740 * If we would forward this name don't add a
1741 * empty zone for it.
1743 result = dns_fwdtable_find(view->fwdtable, name,
1744 &forwarders);
1745 if (result == ISC_R_SUCCESS &&
1746 forwarders->fwdpolicy == dns_fwdpolicy_only)
1747 continue;
1749 if (!rfc1918 && empty_zones[empty_zone].rfc1918) {
1750 if (logit) {
1751 isc_log_write(ns_g_lctx,
1752 NS_LOGCATEGORY_GENERAL,
1753 NS_LOGMODULE_SERVER,
1754 ISC_LOG_WARNING,
1755 "Warning%s%s: "
1756 "'empty-zones-enable/"
1757 "disable-empty-zone' "
1758 "not set: disabling "
1759 "RFC 1918 empty zones",
1760 sep, viewname);
1761 logit = ISC_FALSE;
1763 continue;
1767 * See if we can re-use a existing zone.
1769 result = dns_viewlist_find(&ns_g_server->viewlist,
1770 view->name, view->rdclass,
1771 &pview);
1772 if (result != ISC_R_NOTFOUND &&
1773 result != ISC_R_SUCCESS)
1774 goto cleanup;
1776 if (pview != NULL) {
1777 (void)dns_view_findzone(pview, name, &zone);
1778 dns_view_detach(&pview);
1779 if (zone != NULL)
1780 check_dbtype(&zone, empty_dbtypec,
1781 empty_dbtype, mctx);
1782 if (zone != NULL) {
1783 dns_zone_setview(zone, view);
1784 CHECK(dns_view_addzone(view, zone));
1785 dns_zone_detach(&zone);
1786 continue;
1790 CHECK(dns_zone_create(&zone, mctx));
1791 CHECK(dns_zone_setorigin(zone, name));
1792 dns_zone_setview(zone, view);
1793 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
1794 dns_zone_setclass(zone, view->rdclass);
1795 dns_zone_settype(zone, dns_zone_master);
1796 CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
1797 empty_dbtype));
1798 if (view->queryacl != NULL)
1799 dns_zone_setqueryacl(zone, view->queryacl);
1800 dns_zone_setdialup(zone, dns_dialuptype_no);
1801 dns_zone_setnotifytype(zone, dns_notifytype_no);
1802 dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS,
1803 ISC_TRUE);
1804 CHECK(dns_view_addzone(view, zone));
1805 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1806 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
1807 "automatic empty zone%s%s: %s",
1808 sep, viewname, empty);
1809 dns_zone_detach(&zone);
1813 result = ISC_R_SUCCESS;
1815 cleanup:
1816 if (zone != NULL)
1817 dns_zone_detach(&zone);
1818 if (dispatch4 != NULL)
1819 dns_dispatch_detach(&dispatch4);
1820 if (dispatch6 != NULL)
1821 dns_dispatch_detach(&dispatch6);
1822 if (order != NULL)
1823 dns_order_detach(&order);
1824 if (cmctx != NULL)
1825 isc_mem_detach(&cmctx);
1827 if (cache != NULL)
1828 dns_cache_detach(&cache);
1830 return (result);
1833 static isc_result_t
1834 configure_hints(dns_view_t *view, const char *filename) {
1835 isc_result_t result;
1836 dns_db_t *db;
1838 db = NULL;
1839 result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
1840 if (result == ISC_R_SUCCESS) {
1841 dns_view_sethints(view, db);
1842 dns_db_detach(&db);
1845 return (result);
1848 static isc_result_t
1849 configure_alternates(const cfg_obj_t *config, dns_view_t *view,
1850 const cfg_obj_t *alternates)
1852 const cfg_obj_t *portobj;
1853 const cfg_obj_t *addresses;
1854 const cfg_listelt_t *element;
1855 isc_result_t result = ISC_R_SUCCESS;
1856 in_port_t port;
1859 * Determine which port to send requests to.
1861 if (ns_g_lwresdonly && ns_g_port != 0)
1862 port = ns_g_port;
1863 else
1864 CHECKM(ns_config_getport(config, &port), "port");
1866 if (alternates != NULL) {
1867 portobj = cfg_tuple_get(alternates, "port");
1868 if (cfg_obj_isuint32(portobj)) {
1869 isc_uint32_t val = cfg_obj_asuint32(portobj);
1870 if (val > ISC_UINT16_MAX) {
1871 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
1872 "port '%u' out of range", val);
1873 return (ISC_R_RANGE);
1875 port = (in_port_t) val;
1879 addresses = NULL;
1880 if (alternates != NULL)
1881 addresses = cfg_tuple_get(alternates, "addresses");
1883 for (element = cfg_list_first(addresses);
1884 element != NULL;
1885 element = cfg_list_next(element))
1887 const cfg_obj_t *alternate = cfg_listelt_value(element);
1888 isc_sockaddr_t sa;
1890 if (!cfg_obj_issockaddr(alternate)) {
1891 dns_fixedname_t fixed;
1892 dns_name_t *name;
1893 const char *str = cfg_obj_asstring(cfg_tuple_get(
1894 alternate, "name"));
1895 isc_buffer_t buffer;
1896 in_port_t myport = port;
1898 isc_buffer_init(&buffer, str, strlen(str));
1899 isc_buffer_add(&buffer, strlen(str));
1900 dns_fixedname_init(&fixed);
1901 name = dns_fixedname_name(&fixed);
1902 CHECK(dns_name_fromtext(name, &buffer, dns_rootname,
1903 ISC_FALSE, NULL));
1905 portobj = cfg_tuple_get(alternate, "port");
1906 if (cfg_obj_isuint32(portobj)) {
1907 isc_uint32_t val = cfg_obj_asuint32(portobj);
1908 if (val > ISC_UINT16_MAX) {
1909 cfg_obj_log(portobj, ns_g_lctx,
1910 ISC_LOG_ERROR,
1911 "port '%u' out of range",
1912 val);
1913 return (ISC_R_RANGE);
1915 myport = (in_port_t) val;
1917 CHECK(dns_resolver_addalternate(view->resolver, NULL,
1918 name, myport));
1919 continue;
1922 sa = *cfg_obj_assockaddr(alternate);
1923 if (isc_sockaddr_getport(&sa) == 0)
1924 isc_sockaddr_setport(&sa, port);
1925 CHECK(dns_resolver_addalternate(view->resolver, &sa,
1926 NULL, 0));
1929 cleanup:
1930 return (result);
1933 static isc_result_t
1934 configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
1935 const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype)
1937 const cfg_obj_t *portobj;
1938 const cfg_obj_t *faddresses;
1939 const cfg_listelt_t *element;
1940 dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
1941 isc_sockaddrlist_t addresses;
1942 isc_sockaddr_t *sa;
1943 isc_result_t result;
1944 in_port_t port;
1947 * Determine which port to send forwarded requests to.
1949 if (ns_g_lwresdonly && ns_g_port != 0)
1950 port = ns_g_port;
1951 else
1952 CHECKM(ns_config_getport(config, &port), "port");
1954 if (forwarders != NULL) {
1955 portobj = cfg_tuple_get(forwarders, "port");
1956 if (cfg_obj_isuint32(portobj)) {
1957 isc_uint32_t val = cfg_obj_asuint32(portobj);
1958 if (val > ISC_UINT16_MAX) {
1959 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
1960 "port '%u' out of range", val);
1961 return (ISC_R_RANGE);
1963 port = (in_port_t) val;
1967 faddresses = NULL;
1968 if (forwarders != NULL)
1969 faddresses = cfg_tuple_get(forwarders, "addresses");
1971 ISC_LIST_INIT(addresses);
1973 for (element = cfg_list_first(faddresses);
1974 element != NULL;
1975 element = cfg_list_next(element))
1977 const cfg_obj_t *forwarder = cfg_listelt_value(element);
1978 sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t));
1979 if (sa == NULL) {
1980 result = ISC_R_NOMEMORY;
1981 goto cleanup;
1983 *sa = *cfg_obj_assockaddr(forwarder);
1984 if (isc_sockaddr_getport(sa) == 0)
1985 isc_sockaddr_setport(sa, port);
1986 ISC_LINK_INIT(sa, link);
1987 ISC_LIST_APPEND(addresses, sa, link);
1990 if (ISC_LIST_EMPTY(addresses)) {
1991 if (forwardtype != NULL)
1992 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
1993 "no forwarders seen; disabling "
1994 "forwarding");
1995 fwdpolicy = dns_fwdpolicy_none;
1996 } else {
1997 if (forwardtype == NULL)
1998 fwdpolicy = dns_fwdpolicy_first;
1999 else {
2000 const char *forwardstr = cfg_obj_asstring(forwardtype);
2001 if (strcasecmp(forwardstr, "first") == 0)
2002 fwdpolicy = dns_fwdpolicy_first;
2003 else if (strcasecmp(forwardstr, "only") == 0)
2004 fwdpolicy = dns_fwdpolicy_only;
2005 else
2006 INSIST(0);
2010 result = dns_fwdtable_add(view->fwdtable, origin, &addresses,
2011 fwdpolicy);
2012 if (result != ISC_R_SUCCESS) {
2013 char namebuf[DNS_NAME_FORMATSIZE];
2014 dns_name_format(origin, namebuf, sizeof(namebuf));
2015 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
2016 "could not set up forwarding for domain '%s': %s",
2017 namebuf, isc_result_totext(result));
2018 goto cleanup;
2021 result = ISC_R_SUCCESS;
2023 cleanup:
2025 while (!ISC_LIST_EMPTY(addresses)) {
2026 sa = ISC_LIST_HEAD(addresses);
2027 ISC_LIST_UNLINK(addresses, sa, link);
2028 isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t));
2031 return (result);
2035 * Create a new view and add it to the list.
2037 * If 'vconfig' is NULL, create the default view.
2039 * The view created is attached to '*viewp'.
2041 static isc_result_t
2042 create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
2043 dns_view_t **viewp)
2045 isc_result_t result;
2046 const char *viewname;
2047 dns_rdataclass_t viewclass;
2048 dns_view_t *view = NULL;
2050 if (vconfig != NULL) {
2051 const cfg_obj_t *classobj = NULL;
2053 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
2054 classobj = cfg_tuple_get(vconfig, "class");
2055 result = ns_config_getclass(classobj, dns_rdataclass_in,
2056 &viewclass);
2057 } else {
2058 viewname = "_default";
2059 viewclass = dns_rdataclass_in;
2061 result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
2062 if (result == ISC_R_SUCCESS)
2063 return (ISC_R_EXISTS);
2064 if (result != ISC_R_NOTFOUND)
2065 return (result);
2066 INSIST(view == NULL);
2068 result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
2069 if (result != ISC_R_SUCCESS)
2070 return (result);
2072 ISC_LIST_APPEND(*viewlist, view, link);
2073 dns_view_attach(view, viewp);
2074 return (ISC_R_SUCCESS);
2078 * Configure or reconfigure a zone.
2080 static isc_result_t
2081 configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
2082 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
2083 cfg_aclconfctx_t *aclconf)
2085 dns_view_t *pview = NULL; /* Production view */
2086 dns_zone_t *zone = NULL; /* New or reused zone */
2087 dns_zone_t *dupzone = NULL;
2088 const cfg_obj_t *options = NULL;
2089 const cfg_obj_t *zoptions = NULL;
2090 const cfg_obj_t *typeobj = NULL;
2091 const cfg_obj_t *forwarders = NULL;
2092 const cfg_obj_t *forwardtype = NULL;
2093 const cfg_obj_t *only = NULL;
2094 isc_result_t result;
2095 isc_result_t tresult;
2096 isc_buffer_t buffer;
2097 dns_fixedname_t fixorigin;
2098 dns_name_t *origin;
2099 const char *zname;
2100 dns_rdataclass_t zclass;
2101 const char *ztypestr;
2103 options = NULL;
2104 (void)cfg_map_get(config, "options", &options);
2106 zoptions = cfg_tuple_get(zconfig, "options");
2109 * Get the zone origin as a dns_name_t.
2111 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
2112 isc_buffer_init(&buffer, zname, strlen(zname));
2113 isc_buffer_add(&buffer, strlen(zname));
2114 dns_fixedname_init(&fixorigin);
2115 CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
2116 &buffer, dns_rootname, ISC_FALSE, NULL));
2117 origin = dns_fixedname_name(&fixorigin);
2119 CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
2120 view->rdclass, &zclass));
2121 if (zclass != view->rdclass) {
2122 const char *vname = NULL;
2123 if (vconfig != NULL)
2124 vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
2125 "name"));
2126 else
2127 vname = "<default view>";
2129 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2130 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
2131 "zone '%s': wrong class for view '%s'",
2132 zname, vname);
2133 result = ISC_R_FAILURE;
2134 goto cleanup;
2137 (void)cfg_map_get(zoptions, "type", &typeobj);
2138 if (typeobj == NULL) {
2139 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
2140 "zone '%s' 'type' not specified", zname);
2141 return (ISC_R_FAILURE);
2143 ztypestr = cfg_obj_asstring(typeobj);
2146 * "hints zones" aren't zones. If we've got one,
2147 * configure it and return.
2149 if (strcasecmp(ztypestr, "hint") == 0) {
2150 const cfg_obj_t *fileobj = NULL;
2151 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
2152 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2153 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
2154 "zone '%s': 'file' not specified",
2155 zname);
2156 result = ISC_R_FAILURE;
2157 goto cleanup;
2159 if (dns_name_equal(origin, dns_rootname)) {
2160 const char *hintsfile = cfg_obj_asstring(fileobj);
2162 result = configure_hints(view, hintsfile);
2163 if (result != ISC_R_SUCCESS) {
2164 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2165 NS_LOGMODULE_SERVER,
2166 ISC_LOG_ERROR,
2167 "could not configure root hints "
2168 "from '%s': %s", hintsfile,
2169 isc_result_totext(result));
2170 goto cleanup;
2173 * Hint zones may also refer to delegation only points.
2175 only = NULL;
2176 tresult = cfg_map_get(zoptions, "delegation-only",
2177 &only);
2178 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
2179 CHECK(dns_view_adddelegationonly(view, origin));
2180 } else {
2181 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2182 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2183 "ignoring non-root hint zone '%s'",
2184 zname);
2185 result = ISC_R_SUCCESS;
2187 /* Skip ordinary zone processing. */
2188 goto cleanup;
2192 * "forward zones" aren't zones either. Translate this syntax into
2193 * the appropriate selective forwarding configuration and return.
2195 if (strcasecmp(ztypestr, "forward") == 0) {
2196 forwardtype = NULL;
2197 forwarders = NULL;
2199 (void)cfg_map_get(zoptions, "forward", &forwardtype);
2200 (void)cfg_map_get(zoptions, "forwarders", &forwarders);
2201 result = configure_forward(config, view, origin, forwarders,
2202 forwardtype);
2203 goto cleanup;
2207 * "delegation-only zones" aren't zones either.
2209 if (strcasecmp(ztypestr, "delegation-only") == 0) {
2210 result = dns_view_adddelegationonly(view, origin);
2211 goto cleanup;
2215 * Check for duplicates in the new zone table.
2217 result = dns_view_findzone(view, origin, &dupzone);
2218 if (result == ISC_R_SUCCESS) {
2220 * We already have this zone!
2222 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
2223 "zone '%s' already exists", zname);
2224 dns_zone_detach(&dupzone);
2225 result = ISC_R_EXISTS;
2226 goto cleanup;
2228 INSIST(dupzone == NULL);
2231 * See if we can reuse an existing zone. This is
2232 * only possible if all of these are true:
2233 * - The zone's view exists
2234 * - A zone with the right name exists in the view
2235 * - The zone is compatible with the config
2236 * options (e.g., an existing master zone cannot
2237 * be reused if the options specify a slave zone)
2239 result = dns_viewlist_find(&ns_g_server->viewlist,
2240 view->name, view->rdclass,
2241 &pview);
2242 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
2243 goto cleanup;
2244 if (pview != NULL)
2245 result = dns_view_findzone(pview, origin, &zone);
2246 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
2247 goto cleanup;
2248 if (zone != NULL && !ns_zone_reusable(zone, zconfig))
2249 dns_zone_detach(&zone);
2251 if (zone != NULL) {
2253 * We found a reusable zone. Make it use the
2254 * new view.
2256 dns_zone_setview(zone, view);
2257 if (view->acache != NULL)
2258 dns_zone_setacache(zone, view->acache);
2259 } else {
2261 * We cannot reuse an existing zone, we have
2262 * to create a new one.
2264 CHECK(dns_zone_create(&zone, mctx));
2265 CHECK(dns_zone_setorigin(zone, origin));
2266 dns_zone_setview(zone, view);
2267 if (view->acache != NULL)
2268 dns_zone_setacache(zone, view->acache);
2269 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
2273 * If the zone contains a 'forwarders' statement, configure
2274 * selective forwarding.
2276 forwarders = NULL;
2277 if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
2279 forwardtype = NULL;
2280 (void)cfg_map_get(zoptions, "forward", &forwardtype);
2281 CHECK(configure_forward(config, view, origin, forwarders,
2282 forwardtype));
2286 * Stub and forward zones may also refer to delegation only points.
2288 only = NULL;
2289 if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
2291 if (cfg_obj_asboolean(only))
2292 CHECK(dns_view_adddelegationonly(view, origin));
2296 * Configure the zone.
2298 CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone));
2301 * Add the zone to its view in the new view list.
2303 CHECK(dns_view_addzone(view, zone));
2305 cleanup:
2306 if (zone != NULL)
2307 dns_zone_detach(&zone);
2308 if (pview != NULL)
2309 dns_view_detach(&pview);
2311 return (result);
2315 * Configure a single server quota.
2317 static void
2318 configure_server_quota(const cfg_obj_t **maps, const char *name,
2319 isc_quota_t *quota)
2321 const cfg_obj_t *obj = NULL;
2322 isc_result_t result;
2324 result = ns_config_get(maps, name, &obj);
2325 INSIST(result == ISC_R_SUCCESS);
2326 isc_quota_max(quota, cfg_obj_asuint32(obj));
2330 * This function is called as soon as the 'directory' statement has been
2331 * parsed. This can be extended to support other options if necessary.
2333 static isc_result_t
2334 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
2335 isc_result_t result;
2336 const char *directory;
2338 REQUIRE(strcasecmp("directory", clausename) == 0);
2340 UNUSED(arg);
2341 UNUSED(clausename);
2344 * Change directory.
2346 directory = cfg_obj_asstring(obj);
2348 if (! isc_file_ischdiridempotent(directory))
2349 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
2350 "option 'directory' contains relative path '%s'",
2351 directory);
2353 result = isc_dir_chdir(directory);
2354 if (result != ISC_R_SUCCESS) {
2355 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
2356 "change directory to '%s' failed: %s",
2357 directory, isc_result_totext(result));
2358 return (result);
2361 return (ISC_R_SUCCESS);
2364 static void
2365 scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
2366 isc_boolean_t match_mapped = server->aclenv.match_mapped;
2368 ns_interfacemgr_scan(server->interfacemgr, verbose);
2370 * Update the "localhost" and "localnets" ACLs to match the
2371 * current set of network interfaces.
2373 dns_aclenv_copy(&server->aclenv,
2374 ns_interfacemgr_getaclenv(server->interfacemgr));
2376 server->aclenv.match_mapped = match_mapped;
2379 static isc_result_t
2380 add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
2381 isc_boolean_t wcardport_ok)
2383 ns_listenelt_t *lelt = NULL;
2384 dns_acl_t *src_acl = NULL;
2385 dns_aclelement_t aelt;
2386 isc_result_t result;
2387 isc_sockaddr_t any_sa6;
2389 REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
2391 isc_sockaddr_any6(&any_sa6);
2392 if (!isc_sockaddr_equal(&any_sa6, addr) &&
2393 (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
2394 aelt.type = dns_aclelementtype_ipprefix;
2395 aelt.negative = ISC_FALSE;
2396 aelt.u.ip_prefix.prefixlen = 128;
2397 isc_netaddr_fromin6(&aelt.u.ip_prefix.address,
2398 &addr->type.sin6.sin6_addr);
2400 result = dns_acl_create(mctx, 1, &src_acl);
2401 if (result != ISC_R_SUCCESS)
2402 return (result);
2403 result = dns_acl_appendelement(src_acl, &aelt);
2404 if (result != ISC_R_SUCCESS)
2405 goto clean;
2407 result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
2408 src_acl, &lelt);
2409 if (result != ISC_R_SUCCESS)
2410 goto clean;
2411 ISC_LIST_APPEND(list->elts, lelt, link);
2414 return (ISC_R_SUCCESS);
2416 clean:
2417 INSIST(lelt == NULL);
2418 dns_acl_detach(&src_acl);
2420 return (result);
2424 * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
2425 * to update the listening interfaces accordingly.
2426 * We currently only consider IPv6, because this only affects IPv6 wildcard
2427 * sockets.
2429 static void
2430 adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
2431 isc_result_t result;
2432 ns_listenlist_t *list = NULL;
2433 dns_view_t *view;
2434 dns_zone_t *zone, *next;
2435 isc_sockaddr_t addr, *addrp;
2437 result = ns_listenlist_create(mctx, &list);
2438 if (result != ISC_R_SUCCESS)
2439 return;
2441 for (view = ISC_LIST_HEAD(server->viewlist);
2442 view != NULL;
2443 view = ISC_LIST_NEXT(view, link)) {
2444 dns_dispatch_t *dispatch6;
2446 dispatch6 = dns_resolver_dispatchv6(view->resolver);
2447 if (dispatch6 == NULL)
2448 continue;
2449 result = dns_dispatch_getlocaladdress(dispatch6, &addr);
2450 if (result != ISC_R_SUCCESS)
2451 goto fail;
2454 * We always add non-wildcard address regardless of whether
2455 * the port is 'any' (the fourth arg is TRUE): if the port is
2456 * specific, we need to add it since it may conflict with a
2457 * listening interface; if it's zero, we'll dynamically open
2458 * query ports, and some of them may override an existing
2459 * wildcard IPv6 port.
2461 result = add_listenelt(mctx, list, &addr, ISC_TRUE);
2462 if (result != ISC_R_SUCCESS)
2463 goto fail;
2466 zone = NULL;
2467 for (result = dns_zone_first(server->zonemgr, &zone);
2468 result == ISC_R_SUCCESS;
2469 next = NULL, result = dns_zone_next(zone, &next), zone = next) {
2470 dns_view_t *zoneview;
2473 * At this point the zone list may contain a stale zone
2474 * just removed from the configuration. To see the validity,
2475 * check if the corresponding view is in our current view list.
2476 * There may also be old zones that are still in the process
2477 * of shutting down and have detached from their old view
2478 * (zoneview == NULL).
2480 zoneview = dns_zone_getview(zone);
2481 if (zoneview == NULL)
2482 continue;
2483 for (view = ISC_LIST_HEAD(server->viewlist);
2484 view != NULL && view != zoneview;
2485 view = ISC_LIST_NEXT(view, link))
2487 if (view == NULL)
2488 continue;
2490 addrp = dns_zone_getnotifysrc6(zone);
2491 result = add_listenelt(mctx, list, addrp, ISC_FALSE);
2492 if (result != ISC_R_SUCCESS)
2493 goto fail;
2495 addrp = dns_zone_getxfrsource6(zone);
2496 result = add_listenelt(mctx, list, addrp, ISC_FALSE);
2497 if (result != ISC_R_SUCCESS)
2498 goto fail;
2501 ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
2503 clean:
2504 ns_listenlist_detach(&list);
2505 return;
2507 fail:
2509 * Even when we failed the procedure, most of other interfaces
2510 * should work correctly. We therefore just warn it.
2512 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2513 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2514 "could not adjust the listen-on list; "
2515 "some interfaces may not work");
2516 goto clean;
2520 * This event callback is invoked to do periodic network
2521 * interface scanning.
2523 static void
2524 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
2525 isc_result_t result;
2526 ns_server_t *server = (ns_server_t *) event->ev_arg;
2527 INSIST(task == server->task);
2528 UNUSED(task);
2529 isc_event_free(&event);
2531 * XXX should scan interfaces unlocked and get exclusive access
2532 * only to replace ACLs.
2534 result = isc_task_beginexclusive(server->task);
2535 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2536 scan_interfaces(server, ISC_FALSE);
2537 isc_task_endexclusive(server->task);
2540 static void
2541 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
2542 ns_server_t *server = (ns_server_t *) event->ev_arg;
2543 dns_view_t *view;
2545 UNUSED(task);
2546 isc_event_free(&event);
2547 view = ISC_LIST_HEAD(server->viewlist);
2548 while (view != NULL) {
2549 dns_view_dialup(view);
2550 view = ISC_LIST_NEXT(view, link);
2554 static void
2555 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
2556 static unsigned int oldrequests = 0;
2557 unsigned int requests = ns_client_requests;
2559 UNUSED(task);
2560 isc_event_free(&event);
2563 * Don't worry about wrapping as the overflow result will be right.
2565 dns_pps = (requests - oldrequests) / 1200;
2566 oldrequests = requests;
2570 * Replace the current value of '*field', a dynamically allocated
2571 * string or NULL, with a dynamically allocated copy of the
2572 * null-terminated string pointed to by 'value', or NULL.
2574 static isc_result_t
2575 setstring(ns_server_t *server, char **field, const char *value) {
2576 char *copy;
2578 if (value != NULL) {
2579 copy = isc_mem_strdup(server->mctx, value);
2580 if (copy == NULL)
2581 return (ISC_R_NOMEMORY);
2582 } else {
2583 copy = NULL;
2586 if (*field != NULL)
2587 isc_mem_free(server->mctx, *field);
2589 *field = copy;
2590 return (ISC_R_SUCCESS);
2594 * Replace the current value of '*field', a dynamically allocated
2595 * string or NULL, with another dynamically allocated string
2596 * or NULL if whether 'obj' is a string or void value, respectively.
2598 static isc_result_t
2599 setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) {
2600 if (cfg_obj_isvoid(obj))
2601 return (setstring(server, field, NULL));
2602 else
2603 return (setstring(server, field, cfg_obj_asstring(obj)));
2606 static void
2607 set_limit(const cfg_obj_t **maps, const char *configname,
2608 const char *description, isc_resource_t resourceid,
2609 isc_resourcevalue_t defaultvalue)
2611 const cfg_obj_t *obj = NULL;
2612 const char *resource;
2613 isc_resourcevalue_t value;
2614 isc_result_t result;
2616 if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
2617 return;
2619 if (cfg_obj_isstring(obj)) {
2620 resource = cfg_obj_asstring(obj);
2621 if (strcasecmp(resource, "unlimited") == 0)
2622 value = ISC_RESOURCE_UNLIMITED;
2623 else {
2624 INSIST(strcasecmp(resource, "default") == 0);
2625 value = defaultvalue;
2627 } else
2628 value = cfg_obj_asuint64(obj);
2630 result = isc_resource_setlimit(resourceid, value);
2631 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2632 result == ISC_R_SUCCESS ?
2633 ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
2634 "set maximum %s to %" ISC_PRINT_QUADFORMAT "d: %s",
2635 description, value, isc_result_totext(result));
2638 #define SETLIMIT(cfgvar, resource, description) \
2639 set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
2640 ns_g_init ## resource)
2642 static void
2643 set_limits(const cfg_obj_t **maps) {
2644 SETLIMIT("stacksize", stacksize, "stack size");
2645 SETLIMIT("datasize", datasize, "data size");
2646 SETLIMIT("coresize", coresize, "core size");
2647 SETLIMIT("files", openfiles, "open files");
2650 static isc_result_t
2651 portlist_fromconf(dns_portlist_t *portlist, unsigned int family,
2652 const cfg_obj_t *ports)
2654 const cfg_listelt_t *element;
2655 isc_result_t result = ISC_R_SUCCESS;
2657 for (element = cfg_list_first(ports);
2658 element != NULL;
2659 element = cfg_list_next(element)) {
2660 const cfg_obj_t *obj = cfg_listelt_value(element);
2661 in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
2663 result = dns_portlist_add(portlist, family, port);
2664 if (result != ISC_R_SUCCESS)
2665 break;
2667 return (result);
2670 static isc_result_t
2671 removed(dns_zone_t *zone, void *uap) {
2672 const char *type;
2674 if (dns_zone_getview(zone) != uap)
2675 return (ISC_R_SUCCESS);
2677 switch (dns_zone_gettype(zone)) {
2678 case dns_zone_master:
2679 type = "master";
2680 break;
2681 case dns_zone_slave:
2682 type = "slave";
2683 break;
2684 case dns_zone_stub:
2685 type = "stub";
2686 break;
2687 default:
2688 type = "other";
2689 break;
2691 dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type);
2692 return (ISC_R_SUCCESS);
2695 static isc_result_t
2696 load_configuration(const char *filename, ns_server_t *server,
2697 isc_boolean_t first_time)
2699 cfg_aclconfctx_t aclconfctx;
2700 cfg_obj_t *config;
2701 cfg_parser_t *parser = NULL;
2702 const cfg_listelt_t *element;
2703 const cfg_obj_t *builtin_views;
2704 const cfg_obj_t *maps[3];
2705 const cfg_obj_t *obj;
2706 const cfg_obj_t *options;
2707 const cfg_obj_t *v4ports, *v6ports;
2708 const cfg_obj_t *views;
2709 dns_view_t *view = NULL;
2710 dns_view_t *view_next;
2711 dns_viewlist_t tmpviewlist;
2712 dns_viewlist_t viewlist;
2713 in_port_t listen_port;
2714 int i;
2715 isc_interval_t interval;
2716 isc_resourcevalue_t files;
2717 isc_result_t result;
2718 isc_uint32_t heartbeat_interval;
2719 isc_uint32_t interface_interval;
2720 isc_uint32_t reserved;
2721 isc_uint32_t udpsize;
2723 cfg_aclconfctx_init(&aclconfctx);
2724 ISC_LIST_INIT(viewlist);
2726 /* Ensure exclusive access to configuration data. */
2727 result = isc_task_beginexclusive(server->task);
2728 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2731 * Parse the global default pseudo-config file.
2733 if (first_time) {
2734 CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
2735 RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
2736 &ns_g_defaults) ==
2737 ISC_R_SUCCESS);
2741 * Parse the configuration file using the new config code.
2743 result = ISC_R_FAILURE;
2744 config = NULL;
2747 * Unless this is lwresd with the -C option, parse the config file.
2749 if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
2750 isc_log_write(ns_g_lctx,
2751 NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2752 ISC_LOG_INFO, "loading configuration from '%s'",
2753 filename);
2754 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
2755 cfg_parser_setcallback(parser, directory_callback, NULL);
2756 result = cfg_parse_file(parser, filename, &cfg_type_namedconf,
2757 &config);
2761 * If this is lwresd with the -C option, or lwresd with no -C or -c
2762 * option where the above parsing failed, parse resolv.conf.
2764 if (ns_g_lwresdonly &&
2765 (lwresd_g_useresolvconf ||
2766 (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
2768 isc_log_write(ns_g_lctx,
2769 NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2770 ISC_LOG_INFO, "loading configuration from '%s'",
2771 lwresd_g_resolvconffile);
2772 if (parser != NULL)
2773 cfg_parser_destroy(&parser);
2774 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
2775 result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser,
2776 &config);
2778 CHECK(result);
2781 * Check the validity of the configuration.
2783 CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));
2786 * Fill in the maps array, used for resolving defaults.
2788 i = 0;
2789 options = NULL;
2790 result = cfg_map_get(config, "options", &options);
2791 if (result == ISC_R_SUCCESS)
2792 maps[i++] = options;
2793 maps[i++] = ns_g_defaults;
2794 maps[i++] = NULL;
2797 * Set process limits, which (usually) needs to be done as root.
2799 set_limits(maps);
2802 * Sanity check on "files" limit.
2804 result = isc_resource_curlimit(isc_resource_openfiles, &files);
2805 if (result == ISC_R_SUCCESS && files < FD_SETSIZE) {
2806 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2807 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2808 "the 'files' limit (%" ISC_PRINT_QUADFORMAT "u) "
2809 "is less than FD_SETSIZE (%d), increase "
2810 "'files' in named.conf or recompile with a "
2811 "smaller FD_SETSIZE.", files, FD_SETSIZE);
2812 if (files > FD_SETSIZE)
2813 files = FD_SETSIZE;
2814 } else
2815 files = FD_SETSIZE;
2818 * Set the number of socket reserved for TCP, stdio etc.
2820 obj = NULL;
2821 result = ns_config_get(maps, "reserved-sockets", &obj);
2822 INSIST(result == ISC_R_SUCCESS);
2823 reserved = cfg_obj_asuint32(obj);
2824 if (files < 128U) /* Prevent underflow. */
2825 reserved = 0;
2826 else if (reserved > files - 128U) /* Mimimum UDP space. */
2827 reserved = files - 128;
2828 if (reserved < 128U) /* Mimimum TCP/stdio space. */
2829 reserved = 128;
2830 if (reserved + 128U > files) {
2831 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2832 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2833 "less than 128 UDP sockets available after "
2834 "applying 'reserved-sockets' and 'files'");
2836 isc__socketmgr_setreserved(ns_g_socketmgr, reserved);
2839 * Configure various server options.
2841 configure_server_quota(maps, "transfers-out", &server->xfroutquota);
2842 configure_server_quota(maps, "tcp-clients", &server->tcpquota);
2843 configure_server_quota(maps, "recursive-clients",
2844 &server->recursionquota);
2845 if (server->recursionquota.max > 1000)
2846 isc_quota_soft(&server->recursionquota,
2847 server->recursionquota.max - 100);
2848 else
2849 isc_quota_soft(&server->recursionquota, 0);
2851 CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx,
2852 ns_g_mctx, &server->blackholeacl));
2853 if (server->blackholeacl != NULL)
2854 dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
2855 server->blackholeacl);
2857 obj = NULL;
2858 result = ns_config_get(maps, "match-mapped-addresses", &obj);
2859 INSIST(result == ISC_R_SUCCESS);
2860 server->aclenv.match_mapped = cfg_obj_asboolean(obj);
2862 v4ports = NULL;
2863 v6ports = NULL;
2864 (void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports);
2865 (void)ns_config_get(maps, "avoid-v6-udp-ports", &v6ports);
2866 if (v4ports != NULL || v6ports != NULL) {
2867 dns_portlist_t *portlist = NULL;
2868 result = dns_portlist_create(ns_g_mctx, &portlist);
2869 if (result == ISC_R_SUCCESS && v4ports != NULL)
2870 result = portlist_fromconf(portlist, AF_INET, v4ports);
2871 if (result == ISC_R_SUCCESS && v6ports != NULL)
2872 portlist_fromconf(portlist, AF_INET6, v6ports);
2873 if (result == ISC_R_SUCCESS)
2874 dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, portlist);
2875 if (portlist != NULL)
2876 dns_portlist_detach(&portlist);
2877 CHECK(result);
2878 } else
2879 dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, NULL);
2882 * Set the EDNS UDP size when we don't match a view.
2884 obj = NULL;
2885 result = ns_config_get(maps, "edns-udp-size", &obj);
2886 INSIST(result == ISC_R_SUCCESS);
2887 udpsize = cfg_obj_asuint32(obj);
2888 if (udpsize < 512)
2889 udpsize = 512;
2890 if (udpsize > 4096)
2891 udpsize = 4096;
2892 ns_g_udpsize = (isc_uint16_t)udpsize;
2895 * Configure the zone manager.
2897 obj = NULL;
2898 result = ns_config_get(maps, "transfers-in", &obj);
2899 INSIST(result == ISC_R_SUCCESS);
2900 dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
2902 obj = NULL;
2903 result = ns_config_get(maps, "transfers-per-ns", &obj);
2904 INSIST(result == ISC_R_SUCCESS);
2905 dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
2907 obj = NULL;
2908 result = ns_config_get(maps, "serial-query-rate", &obj);
2909 INSIST(result == ISC_R_SUCCESS);
2910 dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
2913 * Determine which port to use for listening for incoming connections.
2915 if (ns_g_port != 0)
2916 listen_port = ns_g_port;
2917 else
2918 CHECKM(ns_config_getport(config, &listen_port), "port");
2921 * Find the listen queue depth.
2923 obj = NULL;
2924 result = ns_config_get(maps, "tcp-listen-queue", &obj);
2925 INSIST(result == ISC_R_SUCCESS);
2926 ns_g_listen = cfg_obj_asuint32(obj);
2927 if (ns_g_listen < 3)
2928 ns_g_listen = 3;
2931 * Configure the interface manager according to the "listen-on"
2932 * statement.
2935 const cfg_obj_t *clistenon = NULL;
2936 ns_listenlist_t *listenon = NULL;
2938 clistenon = NULL;
2940 * Even though listen-on is present in the default
2941 * configuration, we can't use it here, since it isn't
2942 * used if we're in lwresd mode. This way is easier.
2944 if (options != NULL)
2945 (void)cfg_map_get(options, "listen-on", &clistenon);
2946 if (clistenon != NULL) {
2947 result = ns_listenlist_fromconfig(clistenon,
2948 config,
2949 &aclconfctx,
2950 ns_g_mctx,
2951 &listenon);
2952 } else if (!ns_g_lwresdonly) {
2954 * Not specified, use default.
2956 CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
2957 ISC_TRUE, &listenon));
2959 if (listenon != NULL) {
2960 ns_interfacemgr_setlistenon4(server->interfacemgr,
2961 listenon);
2962 ns_listenlist_detach(&listenon);
2966 * Ditto for IPv6.
2969 const cfg_obj_t *clistenon = NULL;
2970 ns_listenlist_t *listenon = NULL;
2972 if (options != NULL)
2973 (void)cfg_map_get(options, "listen-on-v6", &clistenon);
2974 if (clistenon != NULL) {
2975 result = ns_listenlist_fromconfig(clistenon,
2976 config,
2977 &aclconfctx,
2978 ns_g_mctx,
2979 &listenon);
2980 } else if (!ns_g_lwresdonly) {
2982 * Not specified, use default.
2984 CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
2985 ISC_FALSE, &listenon));
2987 if (listenon != NULL) {
2988 ns_interfacemgr_setlistenon6(server->interfacemgr,
2989 listenon);
2990 ns_listenlist_detach(&listenon);
2995 * Rescan the interface list to pick up changes in the
2996 * listen-on option. It's important that we do this before we try
2997 * to configure the query source, since the dispatcher we use might
2998 * be shared with an interface.
3000 scan_interfaces(server, ISC_TRUE);
3003 * Arrange for further interface scanning to occur periodically
3004 * as specified by the "interface-interval" option.
3006 obj = NULL;
3007 result = ns_config_get(maps, "interface-interval", &obj);
3008 INSIST(result == ISC_R_SUCCESS);
3009 interface_interval = cfg_obj_asuint32(obj) * 60;
3010 if (interface_interval == 0) {
3011 CHECK(isc_timer_reset(server->interface_timer,
3012 isc_timertype_inactive,
3013 NULL, NULL, ISC_TRUE));
3014 } else if (server->interface_interval != interface_interval) {
3015 isc_interval_set(&interval, interface_interval, 0);
3016 CHECK(isc_timer_reset(server->interface_timer,
3017 isc_timertype_ticker,
3018 NULL, &interval, ISC_FALSE));
3020 server->interface_interval = interface_interval;
3023 * Configure the dialup heartbeat timer.
3025 obj = NULL;
3026 result = ns_config_get(maps, "heartbeat-interval", &obj);
3027 INSIST(result == ISC_R_SUCCESS);
3028 heartbeat_interval = cfg_obj_asuint32(obj) * 60;
3029 if (heartbeat_interval == 0) {
3030 CHECK(isc_timer_reset(server->heartbeat_timer,
3031 isc_timertype_inactive,
3032 NULL, NULL, ISC_TRUE));
3033 } else if (server->heartbeat_interval != heartbeat_interval) {
3034 isc_interval_set(&interval, heartbeat_interval, 0);
3035 CHECK(isc_timer_reset(server->heartbeat_timer,
3036 isc_timertype_ticker,
3037 NULL, &interval, ISC_FALSE));
3039 server->heartbeat_interval = heartbeat_interval;
3041 isc_interval_set(&interval, 1200, 0);
3042 CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
3043 &interval, ISC_FALSE));
3046 * Configure and freeze all explicit views. Explicit
3047 * views that have zones were already created at parsing
3048 * time, but views with no zones must be created here.
3050 views = NULL;
3051 (void)cfg_map_get(config, "view", &views);
3052 for (element = cfg_list_first(views);
3053 element != NULL;
3054 element = cfg_list_next(element))
3056 const cfg_obj_t *vconfig = cfg_listelt_value(element);
3057 view = NULL;
3059 CHECK(create_view(vconfig, &viewlist, &view));
3060 INSIST(view != NULL);
3061 CHECK(configure_view(view, config, vconfig,
3062 ns_g_mctx, &aclconfctx, ISC_TRUE));
3063 dns_view_freeze(view);
3064 dns_view_detach(&view);
3068 * Make sure we have a default view if and only if there
3069 * were no explicit views.
3071 if (views == NULL) {
3073 * No explicit views; there ought to be a default view.
3074 * There may already be one created as a side effect
3075 * of zone statements, or we may have to create one.
3076 * In either case, we need to configure and freeze it.
3078 CHECK(create_view(NULL, &viewlist, &view));
3079 CHECK(configure_view(view, config, NULL, ns_g_mctx,
3080 &aclconfctx, ISC_TRUE));
3081 dns_view_freeze(view);
3082 dns_view_detach(&view);
3086 * Create (or recreate) the built-in views. Currently
3087 * there is only one, the _bind view.
3089 builtin_views = NULL;
3090 RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
3091 &builtin_views) == ISC_R_SUCCESS);
3092 for (element = cfg_list_first(builtin_views);
3093 element != NULL;
3094 element = cfg_list_next(element))
3096 const cfg_obj_t *vconfig = cfg_listelt_value(element);
3097 CHECK(create_view(vconfig, &viewlist, &view));
3098 CHECK(configure_view(view, config, vconfig, ns_g_mctx,
3099 &aclconfctx, ISC_FALSE));
3100 dns_view_freeze(view);
3101 dns_view_detach(&view);
3102 view = NULL;
3106 * Swap our new view list with the production one.
3108 tmpviewlist = server->viewlist;
3109 server->viewlist = viewlist;
3110 viewlist = tmpviewlist;
3113 * Load the TKEY information from the configuration.
3115 if (options != NULL) {
3116 dns_tkeyctx_t *t = NULL;
3117 CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
3118 &t),
3119 "configuring TKEY");
3120 if (server->tkeyctx != NULL)
3121 dns_tkeyctx_destroy(&server->tkeyctx);
3122 server->tkeyctx = t;
3126 * Bind the control port(s).
3128 CHECKM(ns_controls_configure(ns_g_server->controls, config,
3129 &aclconfctx),
3130 "binding control channel(s)");
3133 * Bind the lwresd port(s).
3135 CHECKM(ns_lwresd_configure(ns_g_mctx, config),
3136 "binding lightweight resolver ports");
3139 * Open the source of entropy.
3141 if (first_time) {
3142 obj = NULL;
3143 result = ns_config_get(maps, "random-device", &obj);
3144 if (result != ISC_R_SUCCESS) {
3145 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3146 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3147 "no source of entropy found");
3148 } else {
3149 const char *randomdev = cfg_obj_asstring(obj);
3150 result = isc_entropy_createfilesource(ns_g_entropy,
3151 randomdev);
3152 if (result != ISC_R_SUCCESS)
3153 isc_log_write(ns_g_lctx,
3154 NS_LOGCATEGORY_GENERAL,
3155 NS_LOGMODULE_SERVER,
3156 ISC_LOG_INFO,
3157 "could not open entropy source "
3158 "%s: %s",
3159 randomdev,
3160 isc_result_totext(result));
3161 #ifdef PATH_RANDOMDEV
3162 if (ns_g_fallbackentropy != NULL) {
3163 if (result != ISC_R_SUCCESS) {
3164 isc_log_write(ns_g_lctx,
3165 NS_LOGCATEGORY_GENERAL,
3166 NS_LOGMODULE_SERVER,
3167 ISC_LOG_INFO,
3168 "using pre-chroot entropy source "
3169 "%s",
3170 PATH_RANDOMDEV);
3171 isc_entropy_detach(&ns_g_entropy);
3172 isc_entropy_attach(ns_g_fallbackentropy,
3173 &ns_g_entropy);
3175 isc_entropy_detach(&ns_g_fallbackentropy);
3177 #endif
3182 * Relinquish root privileges.
3184 if (first_time)
3185 ns_os_changeuser();
3188 * Configure the logging system.
3190 * Do this after changing UID to make sure that any log
3191 * files specified in named.conf get created by the
3192 * unprivileged user, not root.
3194 if (ns_g_logstderr) {
3195 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3196 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3197 "ignoring config file logging "
3198 "statement due to -g option");
3199 } else {
3200 const cfg_obj_t *logobj = NULL;
3201 isc_logconfig_t *logc = NULL;
3203 CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
3204 "creating new logging configuration");
3206 logobj = NULL;
3207 (void)cfg_map_get(config, "logging", &logobj);
3208 if (logobj != NULL) {
3209 CHECKM(ns_log_configure(logc, logobj),
3210 "configuring logging");
3211 } else {
3212 CHECKM(ns_log_setdefaultchannels(logc),
3213 "setting up default logging channels");
3214 CHECKM(ns_log_setunmatchedcategory(logc),
3215 "setting up default 'category unmatched'");
3216 CHECKM(ns_log_setdefaultcategory(logc),
3217 "setting up default 'category default'");
3220 result = isc_logconfig_use(ns_g_lctx, logc);
3221 if (result != ISC_R_SUCCESS) {
3222 isc_logconfig_destroy(&logc);
3223 CHECKM(result, "installing logging configuration");
3226 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3227 NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
3228 "now using logging configuration from "
3229 "config file");
3233 * Set the default value of the query logging flag depending
3234 * whether a "queries" category has been defined. This is
3235 * a disgusting hack, but we need to do this for BIND 8
3236 * compatibility.
3238 if (first_time) {
3239 const cfg_obj_t *logobj = NULL;
3240 const cfg_obj_t *categories = NULL;
3242 obj = NULL;
3243 if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
3244 server->log_queries = cfg_obj_asboolean(obj);
3245 } else {
3247 (void)cfg_map_get(config, "logging", &logobj);
3248 if (logobj != NULL)
3249 (void)cfg_map_get(logobj, "category",
3250 &categories);
3251 if (categories != NULL) {
3252 const cfg_listelt_t *element;
3253 for (element = cfg_list_first(categories);
3254 element != NULL;
3255 element = cfg_list_next(element))
3257 const cfg_obj_t *catobj;
3258 const char *str;
3260 obj = cfg_listelt_value(element);
3261 catobj = cfg_tuple_get(obj, "name");
3262 str = cfg_obj_asstring(catobj);
3263 if (strcasecmp(str, "queries") == 0)
3264 server->log_queries = ISC_TRUE;
3270 obj = NULL;
3271 if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
3272 if (cfg_obj_isvoid(obj))
3273 ns_os_writepidfile(NULL, first_time);
3274 else
3275 ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
3276 else if (ns_g_lwresdonly)
3277 ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
3278 else
3279 ns_os_writepidfile(ns_g_defaultpidfile, first_time);
3281 obj = NULL;
3282 if (options != NULL &&
3283 cfg_map_get(options, "memstatistics-file", &obj) == ISC_R_SUCCESS)
3284 ns_main_setmemstats(cfg_obj_asstring(obj));
3285 else
3286 ns_main_setmemstats(NULL);
3288 obj = NULL;
3289 result = ns_config_get(maps, "statistics-file", &obj);
3290 INSIST(result == ISC_R_SUCCESS);
3291 CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
3292 "strdup");
3294 obj = NULL;
3295 result = ns_config_get(maps, "dump-file", &obj);
3296 INSIST(result == ISC_R_SUCCESS);
3297 CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
3298 "strdup");
3300 obj = NULL;
3301 result = ns_config_get(maps, "recursing-file", &obj);
3302 INSIST(result == ISC_R_SUCCESS);
3303 CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
3304 "strdup");
3306 obj = NULL;
3307 result = ns_config_get(maps, "version", &obj);
3308 if (result == ISC_R_SUCCESS) {
3309 CHECKM(setoptstring(server, &server->version, obj), "strdup");
3310 server->version_set = ISC_TRUE;
3311 } else {
3312 server->version_set = ISC_FALSE;
3315 obj = NULL;
3316 result = ns_config_get(maps, "hostname", &obj);
3317 if (result == ISC_R_SUCCESS) {
3318 CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
3319 server->hostname_set = ISC_TRUE;
3320 } else {
3321 server->hostname_set = ISC_FALSE;
3324 obj = NULL;
3325 result = ns_config_get(maps, "server-id", &obj);
3326 server->server_usehostname = ISC_FALSE;
3327 if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
3328 server->server_usehostname = ISC_TRUE;
3329 } else if (result == ISC_R_SUCCESS) {
3330 CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
3331 } else {
3332 result = setstring(server, &server->server_id, NULL);
3333 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3336 obj = NULL;
3337 result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
3338 if (result == ISC_R_SUCCESS) {
3339 server->flushonshutdown = cfg_obj_asboolean(obj);
3340 } else {
3341 server->flushonshutdown = ISC_FALSE;
3344 result = ISC_R_SUCCESS;
3346 cleanup:
3347 cfg_aclconfctx_destroy(&aclconfctx);
3349 if (parser != NULL) {
3350 if (config != NULL)
3351 cfg_obj_destroy(parser, &config);
3352 cfg_parser_destroy(&parser);
3355 if (view != NULL)
3356 dns_view_detach(&view);
3359 * This cleans up either the old production view list
3360 * or our temporary list depending on whether they
3361 * were swapped above or not.
3363 for (view = ISC_LIST_HEAD(viewlist);
3364 view != NULL;
3365 view = view_next) {
3366 view_next = ISC_LIST_NEXT(view, link);
3367 ISC_LIST_UNLINK(viewlist, view, link);
3368 if (result == ISC_R_SUCCESS &&
3369 strcmp(view->name, "_bind") != 0)
3370 (void)dns_zt_apply(view->zonetable, ISC_FALSE,
3371 removed, view);
3372 dns_view_detach(&view);
3376 * Adjust the listening interfaces in accordance with the source
3377 * addresses specified in views and zones.
3379 if (isc_net_probeipv6() == ISC_R_SUCCESS)
3380 adjust_interfaces(server, ns_g_mctx);
3382 /* Relinquish exclusive access to configuration data. */
3383 isc_task_endexclusive(server->task);
3385 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3386 ISC_LOG_DEBUG(1), "load_configuration: %s",
3387 isc_result_totext(result));
3389 return (result);
3392 static isc_result_t
3393 load_zones(ns_server_t *server, isc_boolean_t stop) {
3394 isc_result_t result;
3395 dns_view_t *view;
3397 result = isc_task_beginexclusive(server->task);
3398 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3401 * Load zone data from disk.
3403 for (view = ISC_LIST_HEAD(server->viewlist);
3404 view != NULL;
3405 view = ISC_LIST_NEXT(view, link))
3407 CHECK(dns_view_load(view, stop));
3411 * Force zone maintenance. Do this after loading
3412 * so that we know when we need to force AXFR of
3413 * slave zones whose master files are missing.
3415 CHECK(dns_zonemgr_forcemaint(server->zonemgr));
3416 cleanup:
3417 isc_task_endexclusive(server->task);
3418 return (result);
3421 static isc_result_t
3422 load_new_zones(ns_server_t *server, isc_boolean_t stop) {
3423 isc_result_t result;
3424 dns_view_t *view;
3426 result = isc_task_beginexclusive(server->task);
3427 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3430 * Load zone data from disk.
3432 for (view = ISC_LIST_HEAD(server->viewlist);
3433 view != NULL;
3434 view = ISC_LIST_NEXT(view, link))
3436 CHECK(dns_view_loadnew(view, stop));
3439 * Force zone maintenance. Do this after loading
3440 * so that we know when we need to force AXFR of
3441 * slave zones whose master files are missing.
3443 dns_zonemgr_resumexfrs(server->zonemgr);
3444 cleanup:
3445 isc_task_endexclusive(server->task);
3446 return (result);
3449 static void
3450 run_server(isc_task_t *task, isc_event_t *event) {
3451 isc_result_t result;
3452 ns_server_t *server = (ns_server_t *)event->ev_arg;
3454 INSIST(task == server->task);
3456 isc_event_free(&event);
3458 CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
3459 &ns_g_dispatchmgr),
3460 "creating dispatch manager");
3462 CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
3463 ns_g_socketmgr, ns_g_dispatchmgr,
3464 &server->interfacemgr),
3465 "creating interface manager");
3467 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
3468 NULL, NULL, server->task,
3469 interface_timer_tick,
3470 server, &server->interface_timer),
3471 "creating interface timer");
3473 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
3474 NULL, NULL, server->task,
3475 heartbeat_timer_tick,
3476 server, &server->heartbeat_timer),
3477 "creating heartbeat timer");
3479 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
3480 NULL, NULL, server->task, pps_timer_tick,
3481 server, &server->pps_timer),
3482 "creating pps timer");
3484 CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
3485 "creating default configuration parser");
3487 if (ns_g_lwresdonly)
3488 CHECKFATAL(load_configuration(lwresd_g_conffile, server,
3489 ISC_TRUE),
3490 "loading configuration");
3491 else
3492 CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
3493 "loading configuration");
3495 isc_hash_init();
3497 CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones");
3499 ns_os_started();
3500 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3501 ISC_LOG_NOTICE, "running");
3504 void
3505 ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
3507 REQUIRE(NS_SERVER_VALID(server));
3509 server->flushonshutdown = flush;
3512 static void
3513 shutdown_server(isc_task_t *task, isc_event_t *event) {
3514 isc_result_t result;
3515 dns_view_t *view, *view_next;
3516 ns_server_t *server = (ns_server_t *)event->ev_arg;
3517 isc_boolean_t flush = server->flushonshutdown;
3519 UNUSED(task);
3520 INSIST(task == server->task);
3522 result = isc_task_beginexclusive(server->task);
3523 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3525 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3526 ISC_LOG_INFO, "shutting down%s",
3527 flush ? ": flushing changes" : "");
3529 ns_controls_shutdown(server->controls);
3530 end_reserved_dispatches(server, ISC_TRUE);
3532 cfg_obj_destroy(ns_g_parser, &ns_g_config);
3533 cfg_parser_destroy(&ns_g_parser);
3535 for (view = ISC_LIST_HEAD(server->viewlist);
3536 view != NULL;
3537 view = view_next) {
3538 view_next = ISC_LIST_NEXT(view, link);
3539 ISC_LIST_UNLINK(server->viewlist, view, link);
3540 if (flush)
3541 dns_view_flushanddetach(&view);
3542 else
3543 dns_view_detach(&view);
3546 isc_timer_detach(&server->interface_timer);
3547 isc_timer_detach(&server->heartbeat_timer);
3548 isc_timer_detach(&server->pps_timer);
3550 ns_interfacemgr_shutdown(server->interfacemgr);
3551 ns_interfacemgr_detach(&server->interfacemgr);
3553 dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
3555 dns_zonemgr_shutdown(server->zonemgr);
3557 if (server->blackholeacl != NULL)
3558 dns_acl_detach(&server->blackholeacl);
3560 dns_db_detach(&server->in_roothints);
3562 isc_task_endexclusive(server->task);
3564 isc_task_detach(&server->task);
3566 isc_event_free(&event);
3569 void
3570 ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
3571 isc_result_t result;
3573 ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
3574 if (server == NULL)
3575 fatal("allocating server object", ISC_R_NOMEMORY);
3577 server->mctx = mctx;
3578 server->task = NULL;
3580 /* Initialize configuration data with default values. */
3582 result = isc_quota_init(&server->xfroutquota, 10);
3583 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3584 result = isc_quota_init(&server->tcpquota, 10);
3585 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3586 result = isc_quota_init(&server->recursionquota, 100);
3587 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3589 result = dns_aclenv_init(mctx, &server->aclenv);
3590 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3592 /* Initialize server data structures. */
3593 server->zonemgr = NULL;
3594 server->interfacemgr = NULL;
3595 ISC_LIST_INIT(server->viewlist);
3596 server->in_roothints = NULL;
3597 server->blackholeacl = NULL;
3599 CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
3600 &server->in_roothints),
3601 "setting up root hints");
3603 CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
3604 "initializing reload event lock");
3605 server->reload_event =
3606 isc_event_allocate(ns_g_mctx, server,
3607 NS_EVENT_RELOAD,
3608 ns_server_reload,
3609 server,
3610 sizeof(isc_event_t));
3611 CHECKFATAL(server->reload_event == NULL ?
3612 ISC_R_NOMEMORY : ISC_R_SUCCESS,
3613 "allocating reload event");
3615 CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY),
3616 "initializing DST");
3618 server->tkeyctx = NULL;
3619 CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
3620 &server->tkeyctx),
3621 "creating TKEY context");
3624 * Setup the server task, which is responsible for coordinating
3625 * startup and shutdown of the server.
3627 CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
3628 "creating server task");
3629 isc_task_setname(server->task, "server", server);
3630 CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
3631 "isc_task_onshutdown");
3632 CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
3633 "isc_app_onrun");
3635 server->interface_timer = NULL;
3636 server->heartbeat_timer = NULL;
3637 server->pps_timer = NULL;
3639 server->interface_interval = 0;
3640 server->heartbeat_interval = 0;
3642 CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
3643 ns_g_socketmgr, &server->zonemgr),
3644 "dns_zonemgr_create");
3646 server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
3647 CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3648 "isc_mem_strdup");
3649 server->querystats = NULL;
3651 server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
3652 CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3653 "isc_mem_strdup");
3655 server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
3656 CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3657 "isc_mem_strdup");
3659 server->hostname_set = ISC_FALSE;
3660 server->hostname = NULL;
3661 server->version_set = ISC_FALSE;
3662 server->version = NULL;
3663 server->server_usehostname = ISC_FALSE;
3664 server->server_id = NULL;
3666 CHECKFATAL(dns_stats_alloccounters(ns_g_mctx, &server->querystats),
3667 "dns_stats_alloccounters");
3669 server->flushonshutdown = ISC_FALSE;
3670 server->log_queries = ISC_FALSE;
3672 server->controls = NULL;
3673 CHECKFATAL(ns_controls_create(server, &server->controls),
3674 "ns_controls_create");
3675 server->dispatchgen = 0;
3676 ISC_LIST_INIT(server->dispatches);
3678 server->magic = NS_SERVER_MAGIC;
3679 *serverp = server;
3682 void
3683 ns_server_destroy(ns_server_t **serverp) {
3684 ns_server_t *server = *serverp;
3685 REQUIRE(NS_SERVER_VALID(server));
3687 ns_controls_destroy(&server->controls);
3689 dns_stats_freecounters(server->mctx, &server->querystats);
3691 isc_mem_free(server->mctx, server->statsfile);
3692 isc_mem_free(server->mctx, server->dumpfile);
3693 isc_mem_free(server->mctx, server->recfile);
3695 if (server->version != NULL)
3696 isc_mem_free(server->mctx, server->version);
3697 if (server->hostname != NULL)
3698 isc_mem_free(server->mctx, server->hostname);
3699 if (server->server_id != NULL)
3700 isc_mem_free(server->mctx, server->server_id);
3702 dns_zonemgr_detach(&server->zonemgr);
3704 if (server->tkeyctx != NULL)
3705 dns_tkeyctx_destroy(&server->tkeyctx);
3707 dst_lib_destroy();
3709 isc_event_free(&server->reload_event);
3711 INSIST(ISC_LIST_EMPTY(server->viewlist));
3713 dns_aclenv_destroy(&server->aclenv);
3715 isc_quota_destroy(&server->recursionquota);
3716 isc_quota_destroy(&server->tcpquota);
3717 isc_quota_destroy(&server->xfroutquota);
3719 server->magic = 0;
3720 isc_mem_put(server->mctx, server, sizeof(*server));
3721 *serverp = NULL;
3724 static void
3725 fatal(const char *msg, isc_result_t result) {
3726 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3727 ISC_LOG_CRITICAL, "%s: %s", msg,
3728 isc_result_totext(result));
3729 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3730 ISC_LOG_CRITICAL, "exiting (due to fatal error)");
3731 exit(1);
3734 static void
3735 start_reserved_dispatches(ns_server_t *server) {
3737 REQUIRE(NS_SERVER_VALID(server));
3739 server->dispatchgen++;
3742 static void
3743 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
3744 ns_dispatch_t *dispatch, *nextdispatch;
3746 REQUIRE(NS_SERVER_VALID(server));
3748 for (dispatch = ISC_LIST_HEAD(server->dispatches);
3749 dispatch != NULL;
3750 dispatch = nextdispatch) {
3751 nextdispatch = ISC_LIST_NEXT(dispatch, link);
3752 if (!all && server->dispatchgen == dispatch-> dispatchgen)
3753 continue;
3754 ISC_LIST_UNLINK(server->dispatches, dispatch, link);
3755 dns_dispatch_detach(&dispatch->dispatch);
3756 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
3760 void
3761 ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) {
3762 ns_dispatch_t *dispatch;
3763 in_port_t port;
3764 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
3765 isc_result_t result;
3766 unsigned int attrs, attrmask;
3768 REQUIRE(NS_SERVER_VALID(server));
3770 port = isc_sockaddr_getport(addr);
3771 if (port == 0 || port >= 1024)
3772 return;
3774 for (dispatch = ISC_LIST_HEAD(server->dispatches);
3775 dispatch != NULL;
3776 dispatch = ISC_LIST_NEXT(dispatch, link)) {
3777 if (isc_sockaddr_equal(&dispatch->addr, addr))
3778 break;
3780 if (dispatch != NULL) {
3781 dispatch->dispatchgen = server->dispatchgen;
3782 return;
3785 dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
3786 if (dispatch == NULL) {
3787 result = ISC_R_NOMEMORY;
3788 goto cleanup;
3791 dispatch->addr = *addr;
3792 dispatch->dispatchgen = server->dispatchgen;
3793 dispatch->dispatch = NULL;
3795 attrs = 0;
3796 attrs |= DNS_DISPATCHATTR_UDP;
3797 switch (isc_sockaddr_pf(addr)) {
3798 case AF_INET:
3799 attrs |= DNS_DISPATCHATTR_IPV4;
3800 break;
3801 case AF_INET6:
3802 attrs |= DNS_DISPATCHATTR_IPV6;
3803 break;
3804 default:
3805 result = ISC_R_NOTIMPLEMENTED;
3806 goto cleanup;
3808 attrmask = 0;
3809 attrmask |= DNS_DISPATCHATTR_UDP;
3810 attrmask |= DNS_DISPATCHATTR_TCP;
3811 attrmask |= DNS_DISPATCHATTR_IPV4;
3812 attrmask |= DNS_DISPATCHATTR_IPV6;
3814 result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
3815 ns_g_taskmgr, &dispatch->addr, 4096,
3816 1000, 32768, 16411, 16433,
3817 attrs, attrmask, &dispatch->dispatch);
3818 if (result != ISC_R_SUCCESS)
3819 goto cleanup;
3821 ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
3823 return;
3825 cleanup:
3826 if (dispatch != NULL)
3827 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
3828 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
3829 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3830 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3831 "unable to create dispatch for reserved port %s: %s",
3832 addrbuf, isc_result_totext(result));
3836 static isc_result_t
3837 loadconfig(ns_server_t *server) {
3838 isc_result_t result;
3839 start_reserved_dispatches(server);
3840 result = load_configuration(ns_g_lwresdonly ?
3841 lwresd_g_conffile : ns_g_conffile,
3842 server, ISC_FALSE);
3843 if (result == ISC_R_SUCCESS)
3844 end_reserved_dispatches(server, ISC_FALSE);
3845 else
3846 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3847 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3848 "reloading configuration failed: %s",
3849 isc_result_totext(result));
3850 return (result);
3853 static isc_result_t
3854 reload(ns_server_t *server) {
3855 isc_result_t result;
3856 CHECK(loadconfig(server));
3858 result = load_zones(server, ISC_FALSE);
3859 if (result != ISC_R_SUCCESS) {
3860 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3861 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3862 "reloading zones failed: %s",
3863 isc_result_totext(result));
3865 cleanup:
3866 return (result);
3869 static void
3870 reconfig(ns_server_t *server) {
3871 isc_result_t result;
3872 CHECK(loadconfig(server));
3874 result = load_new_zones(server, ISC_FALSE);
3875 if (result != ISC_R_SUCCESS) {
3876 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3877 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3878 "loading new zones failed: %s",
3879 isc_result_totext(result));
3881 cleanup: ;
3885 * Handle a reload event (from SIGHUP).
3887 static void
3888 ns_server_reload(isc_task_t *task, isc_event_t *event) {
3889 ns_server_t *server = (ns_server_t *)event->ev_arg;
3891 INSIST(task = server->task);
3892 UNUSED(task);
3894 (void)reload(server);
3896 LOCK(&server->reload_event_lock);
3897 INSIST(server->reload_event == NULL);
3898 server->reload_event = event;
3899 UNLOCK(&server->reload_event_lock);
3902 void
3903 ns_server_reloadwanted(ns_server_t *server) {
3904 LOCK(&server->reload_event_lock);
3905 if (server->reload_event != NULL)
3906 isc_task_send(server->task, &server->reload_event);
3907 UNLOCK(&server->reload_event_lock);
3910 static char *
3911 next_token(char **stringp, const char *delim) {
3912 char *res;
3914 do {
3915 res = strsep(stringp, delim);
3916 if (res == NULL)
3917 break;
3918 } while (*res == '\0');
3919 return (res);
3923 * Find the zone specified in the control channel command 'args',
3924 * if any. If a zone is specified, point '*zonep' at it, otherwise
3925 * set '*zonep' to NULL.
3927 static isc_result_t
3928 zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) {
3929 char *input, *ptr;
3930 const char *zonetxt;
3931 char *classtxt;
3932 const char *viewtxt = NULL;
3933 dns_fixedname_t name;
3934 isc_result_t result;
3935 isc_buffer_t buf;
3936 dns_view_t *view = NULL;
3937 dns_rdataclass_t rdclass;
3939 REQUIRE(zonep != NULL && *zonep == NULL);
3941 input = args;
3943 /* Skip the command name. */
3944 ptr = next_token(&input, " \t");
3945 if (ptr == NULL)
3946 return (ISC_R_UNEXPECTEDEND);
3948 /* Look for the zone name. */
3949 zonetxt = next_token(&input, " \t");
3950 if (zonetxt == NULL)
3951 return (ISC_R_SUCCESS);
3953 /* Look for the optional class name. */
3954 classtxt = next_token(&input, " \t");
3955 if (classtxt != NULL) {
3956 /* Look for the optional view name. */
3957 viewtxt = next_token(&input, " \t");
3960 isc_buffer_init(&buf, zonetxt, strlen(zonetxt));
3961 isc_buffer_add(&buf, strlen(zonetxt));
3962 dns_fixedname_init(&name);
3963 result = dns_name_fromtext(dns_fixedname_name(&name),
3964 &buf, dns_rootname, ISC_FALSE, NULL);
3965 if (result != ISC_R_SUCCESS)
3966 goto fail1;
3968 if (classtxt != NULL) {
3969 isc_textregion_t r;
3970 r.base = classtxt;
3971 r.length = strlen(classtxt);
3972 result = dns_rdataclass_fromtext(&rdclass, &r);
3973 if (result != ISC_R_SUCCESS)
3974 goto fail1;
3975 } else {
3976 rdclass = dns_rdataclass_in;
3979 if (viewtxt == NULL)
3980 viewtxt = "_default";
3981 result = dns_viewlist_find(&server->viewlist, viewtxt,
3982 rdclass, &view);
3983 if (result != ISC_R_SUCCESS)
3984 goto fail1;
3986 result = dns_zt_find(view->zonetable, dns_fixedname_name(&name),
3987 0, NULL, zonep);
3988 /* Partial match? */
3989 if (result != ISC_R_SUCCESS && *zonep != NULL)
3990 dns_zone_detach(zonep);
3991 dns_view_detach(&view);
3992 fail1:
3993 return (result);
3997 * Act on a "retransfer" command from the command channel.
3999 isc_result_t
4000 ns_server_retransfercommand(ns_server_t *server, char *args) {
4001 isc_result_t result;
4002 dns_zone_t *zone = NULL;
4003 dns_zonetype_t type;
4005 result = zone_from_args(server, args, &zone);
4006 if (result != ISC_R_SUCCESS)
4007 return (result);
4008 if (zone == NULL)
4009 return (ISC_R_UNEXPECTEDEND);
4010 type = dns_zone_gettype(zone);
4011 if (type == dns_zone_slave || type == dns_zone_stub)
4012 dns_zone_forcereload(zone);
4013 else
4014 result = ISC_R_NOTFOUND;
4015 dns_zone_detach(&zone);
4016 return (result);
4020 * Act on a "reload" command from the command channel.
4022 isc_result_t
4023 ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
4024 isc_result_t result;
4025 dns_zone_t *zone = NULL;
4026 dns_zonetype_t type;
4027 const char *msg = NULL;
4029 result = zone_from_args(server, args, &zone);
4030 if (result != ISC_R_SUCCESS)
4031 return (result);
4032 if (zone == NULL) {
4033 result = reload(server);
4034 if (result == ISC_R_SUCCESS)
4035 msg = "server reload successful";
4036 } else {
4037 type = dns_zone_gettype(zone);
4038 if (type == dns_zone_slave || type == dns_zone_stub) {
4039 dns_zone_refresh(zone);
4040 dns_zone_detach(&zone);
4041 msg = "zone refresh queued";
4042 } else {
4043 result = dns_zone_load(zone);
4044 dns_zone_detach(&zone);
4045 switch (result) {
4046 case ISC_R_SUCCESS:
4047 msg = "zone reload successful";
4048 break;
4049 case DNS_R_CONTINUE:
4050 msg = "zone reload queued";
4051 result = ISC_R_SUCCESS;
4052 break;
4053 case DNS_R_UPTODATE:
4054 msg = "zone reload up-to-date";
4055 result = ISC_R_SUCCESS;
4056 break;
4057 default:
4058 /* failure message will be generated by rndc */
4059 break;
4063 if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
4064 isc_buffer_putmem(text, (const unsigned char *)msg,
4065 strlen(msg) + 1);
4066 return (result);
4070 * Act on a "reconfig" command from the command channel.
4072 isc_result_t
4073 ns_server_reconfigcommand(ns_server_t *server, char *args) {
4074 UNUSED(args);
4076 reconfig(server);
4077 return (ISC_R_SUCCESS);
4081 * Act on a "notify" command from the command channel.
4083 isc_result_t
4084 ns_server_notifycommand(ns_server_t *server, char *args, isc_buffer_t *text) {
4085 isc_result_t result;
4086 dns_zone_t *zone = NULL;
4087 const unsigned char msg[] = "zone notify queued";
4089 result = zone_from_args(server, args, &zone);
4090 if (result != ISC_R_SUCCESS)
4091 return (result);
4092 if (zone == NULL)
4093 return (ISC_R_UNEXPECTEDEND);
4095 dns_zone_notify(zone);
4096 dns_zone_detach(&zone);
4097 if (sizeof(msg) <= isc_buffer_availablelength(text))
4098 isc_buffer_putmem(text, msg, sizeof(msg));
4100 return (ISC_R_SUCCESS);
4104 * Act on a "refresh" command from the command channel.
4106 isc_result_t
4107 ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
4108 isc_result_t result;
4109 dns_zone_t *zone = NULL;
4110 const unsigned char msg1[] = "zone refresh queued";
4111 const unsigned char msg2[] = "not a slave or stub zone";
4112 dns_zonetype_t type;
4114 result = zone_from_args(server, args, &zone);
4115 if (result != ISC_R_SUCCESS)
4116 return (result);
4117 if (zone == NULL)
4118 return (ISC_R_UNEXPECTEDEND);
4120 type = dns_zone_gettype(zone);
4121 if (type == dns_zone_slave || type == dns_zone_stub) {
4122 dns_zone_refresh(zone);
4123 dns_zone_detach(&zone);
4124 if (sizeof(msg1) <= isc_buffer_availablelength(text))
4125 isc_buffer_putmem(text, msg1, sizeof(msg1));
4126 return (ISC_R_SUCCESS);
4129 dns_zone_detach(&zone);
4130 if (sizeof(msg2) <= isc_buffer_availablelength(text))
4131 isc_buffer_putmem(text, msg2, sizeof(msg2));
4132 return (ISC_R_FAILURE);
4135 isc_result_t
4136 ns_server_togglequerylog(ns_server_t *server) {
4137 server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE;
4139 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4140 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4141 "query logging is now %s",
4142 server->log_queries ? "on" : "off");
4143 return (ISC_R_SUCCESS);
4146 static isc_result_t
4147 ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
4148 cfg_aclconfctx_t *actx,
4149 isc_mem_t *mctx, ns_listenlist_t **target)
4151 isc_result_t result;
4152 const cfg_listelt_t *element;
4153 ns_listenlist_t *dlist = NULL;
4155 REQUIRE(target != NULL && *target == NULL);
4157 result = ns_listenlist_create(mctx, &dlist);
4158 if (result != ISC_R_SUCCESS)
4159 return (result);
4161 for (element = cfg_list_first(listenlist);
4162 element != NULL;
4163 element = cfg_list_next(element))
4165 ns_listenelt_t *delt = NULL;
4166 const cfg_obj_t *listener = cfg_listelt_value(element);
4167 result = ns_listenelt_fromconfig(listener, config, actx,
4168 mctx, &delt);
4169 if (result != ISC_R_SUCCESS)
4170 goto cleanup;
4171 ISC_LIST_APPEND(dlist->elts, delt, link);
4173 *target = dlist;
4174 return (ISC_R_SUCCESS);
4176 cleanup:
4177 ns_listenlist_detach(&dlist);
4178 return (result);
4182 * Create a listen list from the corresponding configuration
4183 * data structure.
4185 static isc_result_t
4186 ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
4187 cfg_aclconfctx_t *actx,
4188 isc_mem_t *mctx, ns_listenelt_t **target)
4190 isc_result_t result;
4191 const cfg_obj_t *portobj;
4192 in_port_t port;
4193 ns_listenelt_t *delt = NULL;
4194 REQUIRE(target != NULL && *target == NULL);
4196 portobj = cfg_tuple_get(listener, "port");
4197 if (!cfg_obj_isuint32(portobj)) {
4198 if (ns_g_port != 0) {
4199 port = ns_g_port;
4200 } else {
4201 result = ns_config_getport(config, &port);
4202 if (result != ISC_R_SUCCESS)
4203 return (result);
4205 } else {
4206 if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
4207 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
4208 "port value '%u' is out of range",
4209 cfg_obj_asuint32(portobj));
4210 return (ISC_R_RANGE);
4212 port = (in_port_t)cfg_obj_asuint32(portobj);
4215 result = ns_listenelt_create(mctx, port, NULL, &delt);
4216 if (result != ISC_R_SUCCESS)
4217 return (result);
4219 result = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"),
4220 config, ns_g_lctx, actx, mctx, &delt->acl);
4221 if (result != ISC_R_SUCCESS) {
4222 ns_listenelt_destroy(delt);
4223 return (result);
4225 *target = delt;
4226 return (ISC_R_SUCCESS);
4229 isc_result_t
4230 ns_server_dumpstats(ns_server_t *server) {
4231 isc_result_t result;
4232 dns_zone_t *zone, *next;
4233 isc_stdtime_t now;
4234 FILE *fp = NULL;
4235 int i;
4236 int ncounters;
4238 isc_stdtime_get(&now);
4240 CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
4241 "could not open statistics dump file", server->statsfile);
4243 ncounters = DNS_STATS_NCOUNTERS;
4244 fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);
4246 for (i = 0; i < ncounters; i++)
4247 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT "u\n",
4248 dns_statscounter_names[i],
4249 server->querystats[i]);
4251 zone = NULL;
4252 for (result = dns_zone_first(server->zonemgr, &zone);
4253 result == ISC_R_SUCCESS;
4254 next = NULL, result = dns_zone_next(zone, &next), zone = next)
4256 isc_uint64_t *zonestats = dns_zone_getstatscounters(zone);
4257 if (zonestats != NULL) {
4258 char zonename[DNS_NAME_FORMATSIZE];
4259 dns_view_t *view;
4260 char *viewname;
4262 dns_name_format(dns_zone_getorigin(zone),
4263 zonename, sizeof(zonename));
4264 view = dns_zone_getview(zone);
4265 viewname = view->name;
4266 for (i = 0; i < ncounters; i++) {
4267 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT
4268 "u %s",
4269 dns_statscounter_names[i],
4270 zonestats[i],
4271 zonename);
4272 if (strcmp(viewname, "_default") != 0)
4273 fprintf(fp, " %s", viewname);
4274 fprintf(fp, "\n");
4278 if (result == ISC_R_NOMORE)
4279 result = ISC_R_SUCCESS;
4280 CHECK(result);
4282 fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);
4284 cleanup:
4285 if (fp != NULL)
4286 (void)isc_stdio_close(fp);
4287 return (result);
4290 static isc_result_t
4291 add_zone_tolist(dns_zone_t *zone, void *uap) {
4292 struct dumpcontext *dctx = uap;
4293 struct zonelistentry *zle;
4295 zle = isc_mem_get(dctx->mctx, sizeof *zle);
4296 if (zle == NULL)
4297 return (ISC_R_NOMEMORY);
4298 zle->zone = NULL;
4299 dns_zone_attach(zone, &zle->zone);
4300 ISC_LINK_INIT(zle, link);
4301 ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
4302 return (ISC_R_SUCCESS);
4305 static isc_result_t
4306 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
4307 struct viewlistentry *vle;
4308 isc_result_t result = ISC_R_SUCCESS;
4311 * Prevent duplicate views.
4313 for (vle = ISC_LIST_HEAD(dctx->viewlist);
4314 vle != NULL;
4315 vle = ISC_LIST_NEXT(vle, link))
4316 if (vle->view == view)
4317 return (ISC_R_SUCCESS);
4319 vle = isc_mem_get(dctx->mctx, sizeof *vle);
4320 if (vle == NULL)
4321 return (ISC_R_NOMEMORY);
4322 vle->view = NULL;
4323 dns_view_attach(view, &vle->view);
4324 ISC_LINK_INIT(vle, link);
4325 ISC_LIST_INIT(vle->zonelist);
4326 ISC_LIST_APPEND(dctx->viewlist, vle, link);
4327 if (dctx->dumpzones)
4328 result = dns_zt_apply(view->zonetable, ISC_TRUE,
4329 add_zone_tolist, dctx);
4330 return (result);
4333 static void
4334 dumpcontext_destroy(struct dumpcontext *dctx) {
4335 struct viewlistentry *vle;
4336 struct zonelistentry *zle;
4338 vle = ISC_LIST_HEAD(dctx->viewlist);
4339 while (vle != NULL) {
4340 ISC_LIST_UNLINK(dctx->viewlist, vle, link);
4341 zle = ISC_LIST_HEAD(vle->zonelist);
4342 while (zle != NULL) {
4343 ISC_LIST_UNLINK(vle->zonelist, zle, link);
4344 dns_zone_detach(&zle->zone);
4345 isc_mem_put(dctx->mctx, zle, sizeof *zle);
4346 zle = ISC_LIST_HEAD(vle->zonelist);
4348 dns_view_detach(&vle->view);
4349 isc_mem_put(dctx->mctx, vle, sizeof *vle);
4350 vle = ISC_LIST_HEAD(dctx->viewlist);
4352 if (dctx->version != NULL)
4353 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
4354 if (dctx->db != NULL)
4355 dns_db_detach(&dctx->db);
4356 if (dctx->cache != NULL)
4357 dns_db_detach(&dctx->cache);
4358 if (dctx->task != NULL)
4359 isc_task_detach(&dctx->task);
4360 if (dctx->fp != NULL)
4361 (void)isc_stdio_close(dctx->fp);
4362 if (dctx->mdctx != NULL)
4363 dns_dumpctx_detach(&dctx->mdctx);
4364 isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
4367 static void
4368 dumpdone(void *arg, isc_result_t result) {
4369 struct dumpcontext *dctx = arg;
4370 char buf[1024+32];
4371 const dns_master_style_t *style;
4373 if (result != ISC_R_SUCCESS)
4374 goto cleanup;
4375 if (dctx->mdctx != NULL)
4376 dns_dumpctx_detach(&dctx->mdctx);
4377 if (dctx->view == NULL) {
4378 dctx->view = ISC_LIST_HEAD(dctx->viewlist);
4379 if (dctx->view == NULL)
4380 goto done;
4381 INSIST(dctx->zone == NULL);
4382 } else
4383 goto resume;
4384 nextview:
4385 fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
4386 resume:
4387 if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) {
4388 style = &dns_master_style_cache;
4389 /* start cache dump */
4390 if (dctx->view->view->cachedb != NULL)
4391 dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
4392 if (dctx->cache != NULL) {
4394 fprintf(dctx->fp, ";\n; Cache dump of view '%s'\n;\n",
4395 dctx->view->view->name);
4396 result = dns_master_dumptostreaminc(dctx->mctx,
4397 dctx->cache, NULL,
4398 style, dctx->fp,
4399 dctx->task,
4400 dumpdone, dctx,
4401 &dctx->mdctx);
4402 if (result == DNS_R_CONTINUE)
4403 return;
4404 if (result == ISC_R_NOTIMPLEMENTED)
4405 fprintf(dctx->fp, "; %s\n",
4406 dns_result_totext(result));
4407 else if (result != ISC_R_SUCCESS)
4408 goto cleanup;
4411 if (dctx->cache != NULL) {
4412 dns_adb_dump(dctx->view->view->adb, dctx->fp);
4413 dns_db_detach(&dctx->cache);
4415 if (dctx->dumpzones) {
4416 style = &dns_master_style_full;
4417 nextzone:
4418 if (dctx->version != NULL)
4419 dns_db_closeversion(dctx->db, &dctx->version,
4420 ISC_FALSE);
4421 if (dctx->db != NULL)
4422 dns_db_detach(&dctx->db);
4423 if (dctx->zone == NULL)
4424 dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
4425 else
4426 dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
4427 if (dctx->zone != NULL) {
4428 /* start zone dump */
4429 dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
4430 fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
4431 result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
4432 if (result != ISC_R_SUCCESS) {
4433 fprintf(dctx->fp, "; %s\n",
4434 dns_result_totext(result));
4435 goto nextzone;
4437 dns_db_currentversion(dctx->db, &dctx->version);
4438 result = dns_master_dumptostreaminc(dctx->mctx,
4439 dctx->db,
4440 dctx->version,
4441 style, dctx->fp,
4442 dctx->task,
4443 dumpdone, dctx,
4444 &dctx->mdctx);
4445 if (result == DNS_R_CONTINUE)
4446 return;
4447 if (result == ISC_R_NOTIMPLEMENTED) {
4448 fprintf(dctx->fp, "; %s\n",
4449 dns_result_totext(result));
4450 result = ISC_R_SUCCESS;
4451 goto nextzone;
4453 if (result != ISC_R_SUCCESS)
4454 goto cleanup;
4457 if (dctx->view != NULL)
4458 dctx->view = ISC_LIST_NEXT(dctx->view, link);
4459 if (dctx->view != NULL)
4460 goto nextview;
4461 done:
4462 fprintf(dctx->fp, "; Dump complete\n");
4463 result = isc_stdio_flush(dctx->fp);
4464 if (result == ISC_R_SUCCESS)
4465 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4466 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4467 "dumpdb complete");
4468 cleanup:
4469 if (result != ISC_R_SUCCESS)
4470 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4471 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4472 "dumpdb failed: %s", dns_result_totext(result));
4473 dumpcontext_destroy(dctx);
4476 isc_result_t
4477 ns_server_dumpdb(ns_server_t *server, char *args) {
4478 struct dumpcontext *dctx = NULL;
4479 dns_view_t *view;
4480 isc_result_t result;
4481 char *ptr;
4482 const char *sep;
4484 /* Skip the command name. */
4485 ptr = next_token(&args, " \t");
4486 if (ptr == NULL)
4487 return (ISC_R_UNEXPECTEDEND);
4489 dctx = isc_mem_get(server->mctx, sizeof(*dctx));
4490 if (dctx == NULL)
4491 return (ISC_R_NOMEMORY);
4493 dctx->mctx = server->mctx;
4494 dctx->dumpcache = ISC_TRUE;
4495 dctx->dumpzones = ISC_FALSE;
4496 dctx->fp = NULL;
4497 ISC_LIST_INIT(dctx->viewlist);
4498 dctx->view = NULL;
4499 dctx->zone = NULL;
4500 dctx->cache = NULL;
4501 dctx->mdctx = NULL;
4502 dctx->db = NULL;
4503 dctx->cache = NULL;
4504 dctx->task = NULL;
4505 dctx->version = NULL;
4506 isc_task_attach(server->task, &dctx->task);
4508 CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
4509 "could not open dump file", server->dumpfile);
4511 sep = (args == NULL) ? "" : ": ";
4512 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4513 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4514 "dumpdb started%s%s", sep, (args != NULL) ? args : "");
4516 ptr = next_token(&args, " \t");
4517 if (ptr != NULL && strcmp(ptr, "-all") == 0) {
4518 dctx->dumpzones = ISC_TRUE;
4519 dctx->dumpcache = ISC_TRUE;
4520 ptr = next_token(&args, " \t");
4521 } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
4522 dctx->dumpzones = ISC_FALSE;
4523 dctx->dumpcache = ISC_TRUE;
4524 ptr = next_token(&args, " \t");
4525 } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
4526 dctx->dumpzones = ISC_TRUE;
4527 dctx->dumpcache = ISC_FALSE;
4528 ptr = next_token(&args, " \t");
4531 nextview:
4532 for (view = ISC_LIST_HEAD(server->viewlist);
4533 view != NULL;
4534 view = ISC_LIST_NEXT(view, link))
4536 if (ptr != NULL && strcmp(view->name, ptr) != 0)
4537 continue;
4538 CHECK(add_view_tolist(dctx, view));
4540 if (ptr != NULL) {
4541 ptr = next_token(&args, " \t");
4542 if (ptr != NULL)
4543 goto nextview;
4545 dumpdone(dctx, ISC_R_SUCCESS);
4546 return (ISC_R_SUCCESS);
4548 cleanup:
4549 if (dctx != NULL)
4550 dumpcontext_destroy(dctx);
4551 return (result);
4554 isc_result_t
4555 ns_server_dumprecursing(ns_server_t *server) {
4556 FILE *fp = NULL;
4557 isc_result_t result;
4559 CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
4560 "could not open dump file", server->recfile);
4561 fprintf(fp,";\n; Recursing Queries\n;\n");
4562 ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
4563 fprintf(fp, "; Dump complete\n");
4565 cleanup:
4566 if (fp != NULL)
4567 result = isc_stdio_close(fp);
4568 return (result);
4571 isc_result_t
4572 ns_server_setdebuglevel(ns_server_t *server, char *args) {
4573 char *ptr;
4574 char *levelstr;
4575 char *endp;
4576 long newlevel;
4578 UNUSED(server);
4580 /* Skip the command name. */
4581 ptr = next_token(&args, " \t");
4582 if (ptr == NULL)
4583 return (ISC_R_UNEXPECTEDEND);
4585 /* Look for the new level name. */
4586 levelstr = next_token(&args, " \t");
4587 if (levelstr == NULL) {
4588 if (ns_g_debuglevel < 99)
4589 ns_g_debuglevel++;
4590 } else {
4591 newlevel = strtol(levelstr, &endp, 10);
4592 if (*endp != '\0' || newlevel < 0 || newlevel > 99)
4593 return (ISC_R_RANGE);
4594 ns_g_debuglevel = (unsigned int)newlevel;
4596 isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
4597 return (ISC_R_SUCCESS);
4600 isc_result_t
4601 ns_server_validation(ns_server_t *server, char *args) {
4602 char *ptr, *viewname;
4603 dns_view_t *view;
4604 isc_boolean_t changed = ISC_FALSE;
4605 isc_result_t result;
4606 isc_boolean_t enable;
4608 /* Skip the command name. */
4609 ptr = next_token(&args, " \t");
4610 if (ptr == NULL)
4611 return (ISC_R_UNEXPECTEDEND);
4613 /* Find out what we are to do. */
4614 ptr = next_token(&args, " \t");
4615 if (ptr == NULL)
4616 return (ISC_R_UNEXPECTEDEND);
4618 if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
4619 !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
4620 enable = ISC_TRUE;
4621 else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
4622 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
4623 enable = ISC_FALSE;
4624 else
4625 return (DNS_R_SYNTAX);
4627 /* Look for the view name. */
4628 viewname = next_token(&args, " \t");
4630 result = isc_task_beginexclusive(server->task);
4631 RUNTIME_CHECK(result == ISC_R_SUCCESS);
4632 for (view = ISC_LIST_HEAD(server->viewlist);
4633 view != NULL;
4634 view = ISC_LIST_NEXT(view, link))
4636 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
4637 continue;
4638 result = dns_view_flushcache(view);
4639 if (result != ISC_R_SUCCESS)
4640 goto out;
4641 view->enablevalidation = enable;
4642 changed = ISC_TRUE;
4644 if (changed)
4645 result = ISC_R_SUCCESS;
4646 else
4647 result = ISC_R_FAILURE;
4648 out:
4649 isc_task_endexclusive(server->task);
4650 return (result);
4653 isc_result_t
4654 ns_server_flushcache(ns_server_t *server, char *args) {
4655 char *ptr, *viewname;
4656 dns_view_t *view;
4657 isc_boolean_t flushed;
4658 isc_boolean_t found;
4659 isc_result_t result;
4661 /* Skip the command name. */
4662 ptr = next_token(&args, " \t");
4663 if (ptr == NULL)
4664 return (ISC_R_UNEXPECTEDEND);
4666 /* Look for the view name. */
4667 viewname = next_token(&args, " \t");
4669 result = isc_task_beginexclusive(server->task);
4670 RUNTIME_CHECK(result == ISC_R_SUCCESS);
4671 flushed = ISC_TRUE;
4672 found = ISC_FALSE;
4673 for (view = ISC_LIST_HEAD(server->viewlist);
4674 view != NULL;
4675 view = ISC_LIST_NEXT(view, link))
4677 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
4678 continue;
4679 found = ISC_TRUE;
4680 result = dns_view_flushcache(view);
4681 if (result != ISC_R_SUCCESS)
4682 flushed = ISC_FALSE;
4684 if (flushed && found) {
4685 result = ISC_R_SUCCESS;
4686 } else {
4687 if (!found)
4688 result = ISC_R_NOTFOUND;
4689 else
4690 result = ISC_R_FAILURE;
4692 isc_task_endexclusive(server->task);
4693 return (result);
4696 isc_result_t
4697 ns_server_flushname(ns_server_t *server, char *args) {
4698 char *ptr, *target, *viewname;
4699 dns_view_t *view;
4700 isc_boolean_t flushed;
4701 isc_boolean_t found;
4702 isc_result_t result;
4703 isc_buffer_t b;
4704 dns_fixedname_t fixed;
4705 dns_name_t *name;
4707 /* Skip the command name. */
4708 ptr = next_token(&args, " \t");
4709 if (ptr == NULL)
4710 return (ISC_R_UNEXPECTEDEND);
4712 /* Find the domain name to flush. */
4713 target = next_token(&args, " \t");
4714 if (target == NULL)
4715 return (ISC_R_UNEXPECTEDEND);
4717 isc_buffer_init(&b, target, strlen(target));
4718 isc_buffer_add(&b, strlen(target));
4719 dns_fixedname_init(&fixed);
4720 name = dns_fixedname_name(&fixed);
4721 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
4722 if (result != ISC_R_SUCCESS)
4723 return (result);
4725 /* Look for the view name. */
4726 viewname = next_token(&args, " \t");
4728 result = isc_task_beginexclusive(server->task);
4729 RUNTIME_CHECK(result == ISC_R_SUCCESS);
4730 flushed = ISC_TRUE;
4731 found = ISC_FALSE;
4732 for (view = ISC_LIST_HEAD(server->viewlist);
4733 view != NULL;
4734 view = ISC_LIST_NEXT(view, link))
4736 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
4737 continue;
4738 found = ISC_TRUE;
4739 result = dns_view_flushname(view, name);
4740 if (result != ISC_R_SUCCESS)
4741 flushed = ISC_FALSE;
4743 if (flushed && found)
4744 result = ISC_R_SUCCESS;
4745 else if (!found)
4746 result = ISC_R_NOTFOUND;
4747 else
4748 result = ISC_R_FAILURE;
4749 isc_task_endexclusive(server->task);
4750 return (result);
4753 isc_result_t
4754 ns_server_status(ns_server_t *server, isc_buffer_t *text) {
4755 int zonecount, xferrunning, xferdeferred, soaqueries;
4756 unsigned int n;
4758 zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
4759 xferrunning = dns_zonemgr_getcount(server->zonemgr,
4760 DNS_ZONESTATE_XFERRUNNING);
4761 xferdeferred = dns_zonemgr_getcount(server->zonemgr,
4762 DNS_ZONESTATE_XFERDEFERRED);
4763 soaqueries = dns_zonemgr_getcount(server->zonemgr,
4764 DNS_ZONESTATE_SOAQUERY);
4765 n = snprintf((char *)isc_buffer_used(text),
4766 isc_buffer_availablelength(text),
4767 "number of zones: %u\n"
4768 "debug level: %d\n"
4769 "xfers running: %u\n"
4770 "xfers deferred: %u\n"
4771 "soa queries in progress: %u\n"
4772 "query logging is %s\n"
4773 "recursive clients: %d/%d/%d\n"
4774 "tcp clients: %d/%d\n"
4775 "server is up and running",
4776 zonecount, ns_g_debuglevel, xferrunning, xferdeferred,
4777 soaqueries, server->log_queries ? "ON" : "OFF",
4778 server->recursionquota.used, server->recursionquota.soft,
4779 server->recursionquota.max,
4780 server->tcpquota.used, server->tcpquota.max);
4781 if (n >= isc_buffer_availablelength(text))
4782 return (ISC_R_NOSPACE);
4783 isc_buffer_add(text, n);
4784 return (ISC_R_SUCCESS);
4788 * Act on a "freeze" or "thaw" command from the command channel.
4790 isc_result_t
4791 ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) {
4792 isc_result_t result, tresult;
4793 dns_zone_t *zone = NULL;
4794 dns_zonetype_t type;
4795 char classstr[DNS_RDATACLASS_FORMATSIZE];
4796 char zonename[DNS_NAME_FORMATSIZE];
4797 dns_view_t *view;
4798 char *journal;
4799 const char *vname, *sep;
4800 isc_boolean_t frozen;
4802 result = zone_from_args(server, args, &zone);
4803 if (result != ISC_R_SUCCESS)
4804 return (result);
4805 if (zone == NULL) {
4806 result = isc_task_beginexclusive(server->task);
4807 RUNTIME_CHECK(result == ISC_R_SUCCESS);
4808 tresult = ISC_R_SUCCESS;
4809 for (view = ISC_LIST_HEAD(server->viewlist);
4810 view != NULL;
4811 view = ISC_LIST_NEXT(view, link)) {
4812 result = dns_view_freezezones(view, freeze);
4813 if (result != ISC_R_SUCCESS &&
4814 tresult == ISC_R_SUCCESS)
4815 tresult = result;
4817 isc_task_endexclusive(server->task);
4818 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4819 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4820 "%s all zones: %s",
4821 freeze ? "freezing" : "thawing",
4822 isc_result_totext(tresult));
4823 return (tresult);
4825 type = dns_zone_gettype(zone);
4826 if (type != dns_zone_master) {
4827 dns_zone_detach(&zone);
4828 return (ISC_R_NOTFOUND);
4831 frozen = dns_zone_getupdatedisabled(zone);
4832 if (freeze) {
4833 if (frozen)
4834 result = DNS_R_FROZEN;
4835 if (result == ISC_R_SUCCESS)
4836 result = dns_zone_flush(zone);
4837 if (result == ISC_R_SUCCESS) {
4838 journal = dns_zone_getjournal(zone);
4839 if (journal != NULL)
4840 (void)isc_file_remove(journal);
4842 } else {
4843 if (frozen) {
4844 result = dns_zone_load(zone);
4845 if (result == DNS_R_CONTINUE ||
4846 result == DNS_R_UPTODATE)
4847 result = ISC_R_SUCCESS;
4850 if (result == ISC_R_SUCCESS)
4851 dns_zone_setupdatedisabled(zone, freeze);
4853 view = dns_zone_getview(zone);
4854 if (strcmp(view->name, "_bind") == 0 ||
4855 strcmp(view->name, "_default") == 0)
4857 vname = "";
4858 sep = "";
4859 } else {
4860 vname = view->name;
4861 sep = " ";
4863 dns_rdataclass_format(dns_zone_getclass(zone), classstr,
4864 sizeof(classstr));
4865 dns_name_format(dns_zone_getorigin(zone),
4866 zonename, sizeof(zonename));
4867 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4868 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4869 "%s zone '%s/%s'%s%s: %s",
4870 freeze ? "freezing" : "thawing",
4871 zonename, classstr, sep, vname,
4872 isc_result_totext(result));
4873 dns_zone_detach(&zone);
4874 return (result);
4877 #ifdef HAVE_LIBSCF
4879 * This function adds a message for rndc to echo if named
4880 * is managed by smf and is also running chroot.
4882 isc_result_t
4883 ns_smf_add_message(isc_buffer_t *text) {
4884 unsigned int n;
4886 n = snprintf((char *)isc_buffer_used(text),
4887 isc_buffer_availablelength(text),
4888 "use svcadm(1M) to manage named");
4889 if (n >= isc_buffer_availablelength(text))
4890 return (ISC_R_NOSPACE);
4891 isc_buffer_add(text, n);
4892 return (ISC_R_SUCCESS);
4894 #endif /* HAVE_LIBSCF */