Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / bin / named / server.c
blob0afa93a4fe69f9385a2e1d737c879fd28cf19e11
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.339.2.29 2004/05/14 01:04:46 marka Exp $ */
20 #include <config.h>
22 #include <stdlib.h>
24 #include <isc/app.h>
25 #include <isc/base64.h>
26 #include <isc/dir.h>
27 #include <isc/entropy.h>
28 #include <isc/file.h>
29 #include <isc/hash.h>
30 #include <isc/lex.h>
31 #include <isc/print.h>
32 #include <isc/resource.h>
33 #include <isc/stdio.h>
34 #include <isc/string.h>
35 #include <isc/task.h>
36 #include <isc/timer.h>
37 #include <isc/util.h>
39 #include <isccfg/cfg.h>
40 #include <isccfg/check.h>
42 #include <dns/cache.h>
43 #include <dns/db.h>
44 #include <dns/dispatch.h>
45 #include <dns/forward.h>
46 #include <dns/journal.h>
47 #include <dns/keytable.h>
48 #include <dns/master.h>
49 #include <dns/peer.h>
50 #include <dns/rdataclass.h>
51 #include <dns/rdatastruct.h>
52 #include <dns/resolver.h>
53 #include <dns/rootns.h>
54 #include <dns/stats.h>
55 #include <dns/tkey.h>
56 #include <dns/view.h>
57 #include <dns/zone.h>
58 #include <dns/zt.h>
60 #include <dst/dst.h>
61 #include <dst/result.h>
63 #include <named/client.h>
64 #include <named/config.h>
65 #include <named/control.h>
66 #include <named/interfacemgr.h>
67 #include <named/log.h>
68 #include <named/logconf.h>
69 #include <named/lwresd.h>
70 #include <named/os.h>
71 #include <named/server.h>
72 #include <named/tkeyconf.h>
73 #include <named/tsigconf.h>
74 #include <named/zoneconf.h>
77 * Check an operation for failure. Assumes that the function
78 * using it has a 'result' variable and a 'cleanup' label.
80 #define CHECK(op) \
81 do { result = (op); \
82 if (result != ISC_R_SUCCESS) goto cleanup; \
83 } while (0)
85 #define CHECKM(op, msg) \
86 do { result = (op); \
87 if (result != ISC_R_SUCCESS) { \
88 isc_log_write(ns_g_lctx, \
89 NS_LOGCATEGORY_GENERAL, \
90 NS_LOGMODULE_SERVER, \
91 ISC_LOG_ERROR, \
92 "%s: %s", msg, \
93 isc_result_totext(result)); \
94 goto cleanup; \
95 } \
96 } while (0) \
98 #define CHECKFATAL(op, msg) \
99 do { result = (op); \
100 if (result != ISC_R_SUCCESS) \
101 fatal(msg, result); \
102 } while (0) \
104 struct ns_dispatch {
105 isc_sockaddr_t addr;
106 unsigned int dispatchgen;
107 dns_dispatch_t *dispatch;
108 ISC_LINK(struct ns_dispatch) link;
111 static void
112 fatal(const char *msg, isc_result_t result);
114 static void
115 ns_server_reload(isc_task_t *task, isc_event_t *event);
117 static isc_result_t
118 ns_listenelt_fromconfig(cfg_obj_t *listener, cfg_obj_t *config,
119 ns_aclconfctx_t *actx,
120 isc_mem_t *mctx, ns_listenelt_t **target);
121 static isc_result_t
122 ns_listenlist_fromconfig(cfg_obj_t *listenlist, cfg_obj_t *config,
123 ns_aclconfctx_t *actx,
124 isc_mem_t *mctx, ns_listenlist_t **target);
126 static isc_result_t
127 configure_forward(cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
128 cfg_obj_t *forwarders, cfg_obj_t *forwardtype);
130 static isc_result_t
131 configure_zone(cfg_obj_t *config, cfg_obj_t *zconfig, cfg_obj_t *vconfig,
132 isc_mem_t *mctx, dns_view_t *view,
133 ns_aclconfctx_t *aclconf);
135 static void
136 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
139 * Configure a single view ACL at '*aclp'. Get its configuration by
140 * calling 'getvcacl' (for per-view configuration) and maybe 'getscacl'
141 * (for a global default).
143 static isc_result_t
144 configure_view_acl(cfg_obj_t *vconfig, cfg_obj_t *config,
145 const char *aclname, ns_aclconfctx_t *actx,
146 isc_mem_t *mctx, dns_acl_t **aclp)
148 isc_result_t result;
149 cfg_obj_t *maps[3];
150 cfg_obj_t *aclobj = NULL;
151 int i = 0;
153 if (*aclp != NULL)
154 dns_acl_detach(aclp);
155 if (vconfig != NULL)
156 maps[i++] = cfg_tuple_get(vconfig, "options");
157 if (config != NULL) {
158 cfg_obj_t *options = NULL;
159 cfg_map_get(config, "options", &options);
160 if (options != NULL)
161 maps[i++] = options;
163 maps[i] = NULL;
165 result = ns_config_get(maps, aclname, &aclobj);
166 if (aclobj == NULL)
168 * No value available. *aclp == NULL.
170 return (ISC_R_SUCCESS);
172 result = ns_acl_fromconfig(aclobj, config, actx, mctx, aclp);
174 return (result);
177 #ifdef ISC_RFC2535
178 static isc_result_t
179 configure_view_dnsseckey(cfg_obj_t *vconfig, cfg_obj_t *key,
180 dns_keytable_t *keytable, isc_mem_t *mctx)
182 dns_rdataclass_t viewclass;
183 dns_rdata_key_t keystruct;
184 isc_uint32_t flags, proto, alg;
185 char *keystr, *keynamestr;
186 unsigned char keydata[4096];
187 isc_buffer_t keydatabuf;
188 unsigned char rrdata[4096];
189 isc_buffer_t rrdatabuf;
190 isc_region_t r;
191 dns_fixedname_t fkeyname;
192 dns_name_t *keyname;
193 isc_buffer_t namebuf;
194 isc_result_t result;
195 dst_key_t *dstkey = NULL;
197 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
198 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
199 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
200 keyname = dns_fixedname_name(&fkeyname);
201 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
203 if (vconfig == NULL)
204 viewclass = dns_rdataclass_in;
205 else {
206 cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
207 CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
208 &viewclass));
210 keystruct.common.rdclass = viewclass;
211 keystruct.common.rdtype = dns_rdatatype_key;
213 * The key data in keystruct is not dynamically allocated.
215 keystruct.mctx = NULL;
217 ISC_LINK_INIT(&keystruct.common, link);
219 if (flags > 0xffff)
220 CHECKM(ISC_R_RANGE, "key flags");
221 if (proto > 0xff)
222 CHECKM(ISC_R_RANGE, "key protocol");
223 if (alg > 0xff)
224 CHECKM(ISC_R_RANGE, "key algorithm");
225 keystruct.flags = (isc_uint16_t)flags;
226 keystruct.protocol = (isc_uint8_t)proto;
227 keystruct.algorithm = (isc_uint8_t)alg;
229 isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
230 isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
232 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
233 CHECK(isc_base64_decodestring(keystr, &keydatabuf));
234 isc_buffer_usedregion(&keydatabuf, &r);
235 keystruct.datalen = r.length;
236 keystruct.data = r.base;
238 CHECK(dns_rdata_fromstruct(NULL,
239 keystruct.common.rdclass,
240 keystruct.common.rdtype,
241 &keystruct, &rrdatabuf));
242 dns_fixedname_init(&fkeyname);
243 isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr));
244 isc_buffer_add(&namebuf, strlen(keynamestr));
245 CHECK(dns_name_fromtext(keyname, &namebuf,
246 dns_rootname, ISC_FALSE,
247 NULL));
248 CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
249 mctx, &dstkey));
251 CHECK(dns_keytable_add(keytable, &dstkey));
252 INSIST(dstkey == NULL);
253 return (ISC_R_SUCCESS);
255 cleanup:
256 if (result == DST_R_NOCRYPTO) {
257 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
258 "ignoring trusted key for '%s': no crypto support",
259 keynamestr);
260 result = ISC_R_SUCCESS;
261 } else {
262 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
263 "configuring trusted key for '%s': %s",
264 keynamestr, isc_result_totext(result));
265 result = ISC_R_FAILURE;
268 if (dstkey != NULL)
269 dst_key_free(&dstkey);
271 return (result);
273 #endif
276 * Configure DNSSEC keys for a view. Currently used only for
277 * the security roots.
279 * The per-view configuration values and the server-global defaults are read
280 * from 'vconfig' and 'config'. The variable to be configured is '*target'.
282 static isc_result_t
283 configure_view_dnsseckeys(cfg_obj_t *vconfig, cfg_obj_t *config,
284 isc_mem_t *mctx, dns_keytable_t **target)
286 isc_result_t result;
287 #ifdef ISC_RFC2535
288 cfg_obj_t *keys = NULL;
289 cfg_obj_t *voptions = NULL;
290 cfg_listelt_t *element, *element2;
291 cfg_obj_t *keylist;
292 cfg_obj_t *key;
293 #endif
294 dns_keytable_t *keytable = NULL;
296 CHECK(dns_keytable_create(mctx, &keytable));
298 #ifndef ISC_RFC2535
299 UNUSED(vconfig);
300 UNUSED(config);
301 #else
302 if (vconfig != NULL)
303 voptions = cfg_tuple_get(vconfig, "options");
305 keys = NULL;
306 if (voptions != NULL)
307 (void)cfg_map_get(voptions, "trusted-keys", &keys);
308 if (keys == NULL)
309 (void)cfg_map_get(config, "trusted-keys", &keys);
311 for (element = cfg_list_first(keys);
312 element != NULL;
313 element = cfg_list_next(element))
315 keylist = cfg_listelt_value(element);
316 for (element2 = cfg_list_first(keylist);
317 element2 != NULL;
318 element2 = cfg_list_next(element2))
320 key = cfg_listelt_value(element2);
321 CHECK(configure_view_dnsseckey(vconfig, key,
322 keytable, mctx));
325 #endif
326 dns_keytable_detach(target);
327 *target = keytable; /* Transfer ownership. */
328 keytable = NULL;
329 result = ISC_R_SUCCESS;
331 cleanup:
332 return (result);
337 * Get a dispatch appropriate for the resolver of a given view.
339 static isc_result_t
340 get_view_querysource_dispatch(cfg_obj_t **maps,
341 int af, dns_dispatch_t **dispatchp)
343 isc_result_t result;
344 dns_dispatch_t *disp;
345 isc_sockaddr_t sa;
346 unsigned int attrs, attrmask;
347 cfg_obj_t *obj = NULL;
350 * Make compiler happy.
352 result = ISC_R_FAILURE;
354 switch (af) {
355 case AF_INET:
356 result = ns_config_get(maps, "query-source", &obj);
357 INSIST(result == ISC_R_SUCCESS);
359 break;
360 case AF_INET6:
361 result = ns_config_get(maps, "query-source-v6", &obj);
362 INSIST(result == ISC_R_SUCCESS);
363 break;
364 default:
365 INSIST(0);
368 sa = *(cfg_obj_assockaddr(obj));
369 INSIST(isc_sockaddr_pf(&sa) == af);
372 * If we don't support this address family, we're done!
374 switch (af) {
375 case AF_INET:
376 result = isc_net_probeipv4();
377 break;
378 case AF_INET6:
379 result = isc_net_probeipv6();
380 break;
381 default:
382 INSIST(0);
384 if (result != ISC_R_SUCCESS)
385 return (ISC_R_SUCCESS);
388 * Try to find a dispatcher that we can share.
390 attrs = 0;
391 attrs |= DNS_DISPATCHATTR_UDP;
392 switch (af) {
393 case AF_INET:
394 attrs |= DNS_DISPATCHATTR_IPV4;
395 break;
396 case AF_INET6:
397 attrs |= DNS_DISPATCHATTR_IPV6;
398 break;
400 attrmask = 0;
401 attrmask |= DNS_DISPATCHATTR_UDP;
402 attrmask |= DNS_DISPATCHATTR_TCP;
403 attrmask |= DNS_DISPATCHATTR_IPV4;
404 attrmask |= DNS_DISPATCHATTR_IPV6;
406 disp = NULL;
407 result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
408 ns_g_taskmgr, &sa, 4096,
409 1000, 32768, 16411, 16433,
410 attrs, attrmask, &disp);
411 if (result != ISC_R_SUCCESS) {
412 isc_sockaddr_t any;
413 char buf[ISC_SOCKADDR_FORMATSIZE];
415 switch (af) {
416 case AF_INET:
417 isc_sockaddr_any(&any);
418 break;
419 case AF_INET6:
420 isc_sockaddr_any6(&any);
421 break;
423 if (isc_sockaddr_equal(&sa, &any))
424 return (ISC_R_SUCCESS);
425 isc_sockaddr_format(&sa, buf, sizeof(buf));
426 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
427 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
428 "could not get query source dispatcher (%s)",
429 buf);
430 return (result);
433 *dispatchp = disp;
435 return (ISC_R_SUCCESS);
438 static isc_result_t
439 configure_peer(cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
440 isc_sockaddr_t *sa;
441 isc_netaddr_t na;
442 dns_peer_t *peer;
443 cfg_obj_t *obj;
444 char *str;
445 isc_result_t result;
447 sa = cfg_obj_assockaddr(cfg_map_getname(cpeer));
448 isc_netaddr_fromsockaddr(&na, sa);
450 peer = NULL;
451 result = dns_peer_new(mctx, &na, &peer);
452 if (result != ISC_R_SUCCESS)
453 return (result);
455 obj = NULL;
456 (void)cfg_map_get(cpeer, "bogus", &obj);
457 if (obj != NULL)
458 dns_peer_setbogus(peer, cfg_obj_asboolean(obj));
460 obj = NULL;
461 (void)cfg_map_get(cpeer, "provide-ixfr", &obj);
462 if (obj != NULL)
463 dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj));
465 obj = NULL;
466 (void)cfg_map_get(cpeer, "request-ixfr", &obj);
467 if (obj != NULL)
468 dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj));
470 obj = NULL;
471 (void)cfg_map_get(cpeer, "edns", &obj);
472 if (obj != NULL)
473 dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj));
475 obj = NULL;
476 (void)cfg_map_get(cpeer, "transfers", &obj);
477 if (obj != NULL)
478 dns_peer_settransfers(peer, cfg_obj_asuint32(obj));
480 obj = NULL;
481 (void)cfg_map_get(cpeer, "transfer-format", &obj);
482 if (obj != NULL) {
483 str = cfg_obj_asstring(obj);
484 if (strcasecmp(str, "many-answers") == 0)
485 dns_peer_settransferformat(peer, dns_many_answers);
486 else if (strcasecmp(str, "one-answer") == 0)
487 dns_peer_settransferformat(peer, dns_one_answer);
488 else
489 INSIST(0);
492 obj = NULL;
493 (void)cfg_map_get(cpeer, "keys", &obj);
494 if (obj != NULL) {
495 result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
496 if (result != ISC_R_SUCCESS)
497 goto cleanup;
499 *peerp = peer;
500 return (ISC_R_SUCCESS);
502 cleanup:
503 dns_peer_detach(&peer);
504 return (result);
508 * Configure 'view' according to 'vconfig', taking defaults from 'config'
509 * where values are missing in 'vconfig'.
511 * When configuring the default view, 'vconfig' will be NULL and the
512 * global defaults in 'config' used exclusively.
514 static isc_result_t
515 configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
516 isc_mem_t *mctx, ns_aclconfctx_t *actx)
518 cfg_obj_t *maps[4];
519 cfg_obj_t *cfgmaps[3];
520 cfg_obj_t *options = NULL;
521 cfg_obj_t *voptions = NULL;
522 cfg_obj_t *forwardtype;
523 cfg_obj_t *forwarders;
524 cfg_obj_t *zonelist;
525 cfg_obj_t *obj;
526 cfg_listelt_t *element;
527 in_port_t port;
528 dns_cache_t *cache = NULL;
529 isc_result_t result;
530 isc_uint32_t max_cache_size;
531 isc_uint32_t lame_ttl;
532 dns_tsig_keyring_t *ring;
533 dns_view_t *pview = NULL; /* Production view */
534 isc_mem_t *cmctx;
535 dns_dispatch_t *dispatch4 = NULL;
536 dns_dispatch_t *dispatch6 = NULL;
537 isc_boolean_t reused_cache = ISC_FALSE;
538 int i;
539 char *str;
541 REQUIRE(DNS_VIEW_VALID(view));
543 cmctx = NULL;
545 if (config != NULL)
546 cfg_map_get(config, "options", &options);
548 i = 0;
549 if (vconfig != NULL) {
550 voptions = cfg_tuple_get(vconfig, "options");
551 maps[i++] = voptions;
553 if (options != NULL)
554 maps[i++] = options;
555 maps[i++] = ns_g_defaults;
556 maps[i] = NULL;
558 i = 0;
559 if (voptions != NULL)
560 cfgmaps[i++] = voptions;
561 if (config != NULL)
562 cfgmaps[i++] = config;
563 cfgmaps[i] = NULL;
567 * Set the view's port number for outgoing queries.
569 CHECKM(ns_config_getport(config, &port), "port");
570 dns_view_setdstport(view, port);
573 * Configure the zones.
575 zonelist = NULL;
576 if (voptions != NULL)
577 (void)cfg_map_get(voptions, "zone", &zonelist);
578 else
579 (void)cfg_map_get(config, "zone", &zonelist);
580 for (element = cfg_list_first(zonelist);
581 element != NULL;
582 element = cfg_list_next(element))
584 cfg_obj_t *zconfig = cfg_listelt_value(element);
585 CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
586 actx));
590 * Configure the view's cache. Try to reuse an existing
591 * cache if possible, otherwise create a new cache.
592 * Note that the ADB is not preserved in either case.
594 * XXX Determining when it is safe to reuse a cache is
595 * tricky. When the view's configuration changes, the cached
596 * data may become invalid because it reflects our old
597 * view of the world. As more view attributes become
598 * configurable, we will have to add code here to check
599 * whether they have changed in ways that could
600 * invalidate the cache.
602 result = dns_viewlist_find(&ns_g_server->viewlist,
603 view->name, view->rdclass,
604 &pview);
605 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
606 goto cleanup;
607 if (pview != NULL) {
608 INSIST(pview->cache != NULL);
609 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
610 NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3),
611 "reusing existing cache");
612 reused_cache = ISC_TRUE;
613 dns_cache_attach(pview->cache, &cache);
614 dns_view_detach(&pview);
615 } else {
616 CHECK(isc_mem_create(0, 0, &cmctx));
617 CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr,
618 view->rdclass, "rbt", 0, NULL, &cache));
620 dns_view_setcache(view, cache);
623 * cache-file cannot be inherited if views are present, but this
624 * should be caught by the configuration checking stage.
626 obj = NULL;
627 result = ns_config_get(maps, "cache-file", &obj);
628 if (result == ISC_R_SUCCESS) {
629 dns_cache_setfilename(cache, cfg_obj_asstring(obj));
630 if (!reused_cache)
631 CHECK(dns_cache_load(cache));
634 obj = NULL;
635 result = ns_config_get(maps, "cleaning-interval", &obj);
636 INSIST(result == ISC_R_SUCCESS);
637 dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60);
639 obj = NULL;
640 result = ns_config_get(maps, "max-cache-size", &obj);
641 INSIST(result == ISC_R_SUCCESS);
642 if (cfg_obj_isstring(obj)) {
643 str = cfg_obj_asstring(obj);
644 INSIST(strcasecmp(str, "unlimited") == 0);
645 max_cache_size = ISC_UINT32_MAX;
646 } else {
647 isc_resourcevalue_t value;
648 value = cfg_obj_asuint64(obj);
649 if (value > ISC_UINT32_MAX) {
650 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
651 "'max-cache-size "
652 "%" ISC_PRINT_QUADFORMAT "d' is too large",
653 value);
654 result = ISC_R_RANGE;
655 goto cleanup;
657 max_cache_size = (isc_uint32_t)value;
659 dns_cache_setcachesize(cache, max_cache_size);
661 dns_cache_detach(&cache);
664 * Resolver.
666 * XXXRTH Hardwired number of tasks.
668 CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4));
669 CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6));
670 if (dispatch4 == NULL && dispatch6 == NULL) {
671 UNEXPECTED_ERROR(__FILE__, __LINE__,
672 "unable to obtain neither an IPv4 nor"
673 " an IPv6 dispatch");
674 result = ISC_R_UNEXPECTED;
675 goto cleanup;
677 CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31,
678 ns_g_socketmgr, ns_g_timermgr,
679 0, ns_g_dispatchmgr,
680 dispatch4, dispatch6));
683 * Set resolver's lame-ttl.
685 obj = NULL;
686 result = ns_config_get(maps, "lame-ttl", &obj);
687 INSIST(result == ISC_R_SUCCESS);
688 lame_ttl = cfg_obj_asuint32(obj);
689 if (lame_ttl > 1800)
690 lame_ttl = 1800;
691 dns_resolver_setlamettl(view->resolver, lame_ttl);
694 * A global or view "forwarders" option, if present,
695 * creates an entry for "." in the forwarding table.
697 forwardtype = NULL;
698 forwarders = NULL;
699 (void)ns_config_get(maps, "forward", &forwardtype);
700 (void)ns_config_get(maps, "forwarders", &forwarders);
701 if (forwarders != NULL)
702 CHECK(configure_forward(config, view, dns_rootname,
703 forwarders, forwardtype));
706 * We have default hints for class IN if we need them.
708 if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
709 dns_view_sethints(view, ns_g_server->in_roothints);
712 * If we still have no hints, this is a non-IN view with no
713 * "hints zone" configured. Issue a warning, except if this
714 * is a root server. Root servers never need to consult
715 * their hints, so it's no point requireing users to configure
716 * them.
718 if (view->hints == NULL) {
719 dns_zone_t *rootzone = NULL;
720 dns_view_findzone(view, dns_rootname, &rootzone);
721 if (rootzone != NULL) {
722 dns_zone_detach(&rootzone);
723 } else {
724 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
725 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
726 "no root hints for view '%s'",
727 view->name);
732 * Configure the view's TSIG keys.
734 ring = NULL;
735 CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
736 dns_view_setkeyring(view, ring);
739 * Configure the view's peer list.
742 cfg_obj_t *peers = NULL;
743 cfg_listelt_t *element;
744 dns_peerlist_t *newpeers = NULL;
746 (void)ns_config_get(cfgmaps, "server", &peers);
747 CHECK(dns_peerlist_new(mctx, &newpeers));
748 for (element = cfg_list_first(peers);
749 element != NULL;
750 element = cfg_list_next(element))
752 cfg_obj_t *cpeer = cfg_listelt_value(element);
753 dns_peer_t *peer;
755 CHECK(configure_peer(cpeer, mctx, &peer));
756 dns_peerlist_addpeer(newpeers, peer);
757 dns_peer_detach(&peer);
759 dns_peerlist_detach(&view->peers);
760 view->peers = newpeers; /* Transfer ownership. */
764 * Copy the aclenv object.
766 dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv);
769 * Configure the "match-clients" and "match-destinations" ACL.
771 CHECK(configure_view_acl(vconfig, config, "match-clients", actx,
772 ns_g_mctx, &view->matchclients));
773 CHECK(configure_view_acl(vconfig, config, "match-destinations", actx,
774 ns_g_mctx, &view->matchdestinations));
777 * Configure the "match-recursive-only" option.
779 obj = NULL;
780 (void) ns_config_get(maps, "match-recursive-only", &obj);
781 if (obj != NULL && cfg_obj_asboolean(obj))
782 view->matchrecursiveonly = ISC_TRUE;
783 else
784 view->matchrecursiveonly = ISC_FALSE;
787 * Configure other configurable data.
789 obj = NULL;
790 result = ns_config_get(maps, "recursion", &obj);
791 INSIST(result == ISC_R_SUCCESS);
792 view->recursion = cfg_obj_asboolean(obj);
794 obj = NULL;
795 result = ns_config_get(maps, "auth-nxdomain", &obj);
796 INSIST(result == ISC_R_SUCCESS);
797 view->auth_nxdomain = cfg_obj_asboolean(obj);
799 obj = NULL;
800 result = ns_config_get(maps, "minimal-responses", &obj);
801 INSIST(result == ISC_R_SUCCESS);
802 view->minimalresponses = cfg_obj_asboolean(obj);
804 obj = NULL;
805 result = ns_config_get(maps, "transfer-format", &obj);
806 INSIST(result == ISC_R_SUCCESS);
807 str = cfg_obj_asstring(obj);
808 if (strcasecmp(str, "many-answers") == 0)
809 view->transfer_format = dns_many_answers;
810 else if (strcasecmp(str, "one-answer") == 0)
811 view->transfer_format = dns_one_answer;
812 else
813 INSIST(0);
816 * Set sources where additional data and CNAME/DNAME
817 * targets for authoritative answers may be found.
819 obj = NULL;
820 result = ns_config_get(maps, "additional-from-auth", &obj);
821 INSIST(result == ISC_R_SUCCESS);
822 view->additionalfromauth = cfg_obj_asboolean(obj);
823 if (view->recursion && ! view->additionalfromauth) {
824 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
825 "'additional-from-auth no' is only supported "
826 "with 'recursion no'");
827 view->additionalfromauth = ISC_TRUE;
830 obj = NULL;
831 result = ns_config_get(maps, "additional-from-cache", &obj);
832 INSIST(result == ISC_R_SUCCESS);
833 view->additionalfromcache = cfg_obj_asboolean(obj);
834 if (view->recursion && ! view->additionalfromcache) {
835 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
836 "'additional-from-cache no' is only supported "
837 "with 'recursion no'");
838 view->additionalfromcache = ISC_TRUE;
841 CHECK(configure_view_acl(vconfig, config, "allow-query",
842 actx, ns_g_mctx, &view->queryacl));
844 if (strcmp(view->name, "_bind") != 0)
845 CHECK(configure_view_acl(vconfig, config, "allow-recursion",
846 actx, ns_g_mctx, &view->recursionacl));
848 CHECK(configure_view_acl(vconfig, config, "allow-v6-synthesis",
849 actx, ns_g_mctx, &view->v6synthesisacl));
852 * Warning if both "recursion no;" and allow-recursion are active
853 * except for "allow-recursion { none; };".
855 if (!view->recursion && view->recursionacl != NULL &&
856 (view->recursionacl->length != 1 ||
857 view->recursionacl->elements[0].type != dns_aclelementtype_any ||
858 view->recursionacl->elements[0].negative != ISC_TRUE)) {
859 const char *forview = " for view ";
860 const char *viewname = view->name;
862 if (!strcmp(view->name, "_bind") ||
863 !strcmp(view->name, "_default")) {
864 forview = "";
865 viewname = "";
867 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
868 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
869 "both \"recursion no;\" and \"allow-recursion\" "
870 "active%s%s", forview, viewname);
873 CHECK(configure_view_acl(vconfig, config, "sortlist",
874 actx, ns_g_mctx, &view->sortlist));
876 obj = NULL;
877 result = ns_config_get(maps, "request-ixfr", &obj);
878 INSIST(result == ISC_R_SUCCESS);
879 view->requestixfr = cfg_obj_asboolean(obj);
881 obj = NULL;
882 result = ns_config_get(maps, "provide-ixfr", &obj);
883 INSIST(result == ISC_R_SUCCESS);
884 view->provideixfr = cfg_obj_asboolean(obj);
887 * For now, there is only one kind of trusted keys, the
888 * "security roots".
890 CHECK(configure_view_dnsseckeys(vconfig, config, mctx,
891 &view->secroots));
893 obj = NULL;
894 result = ns_config_get(maps, "max-cache-ttl", &obj);
895 INSIST(result == ISC_R_SUCCESS);
896 view->maxcachettl = cfg_obj_asuint32(obj);
898 obj = NULL;
899 result = ns_config_get(maps, "max-ncache-ttl", &obj);
900 INSIST(result == ISC_R_SUCCESS);
901 view->maxncachettl = cfg_obj_asuint32(obj);
902 if (view->maxncachettl > 7 * 24 * 3600)
903 view->maxncachettl = 7 * 24 * 3600;
905 obj = NULL;
906 result = ns_config_get(maps, "root-delegation-only", &obj);
907 if (result == ISC_R_SUCCESS) {
908 dns_view_setrootdelonly(view, ISC_TRUE);
909 if (!cfg_obj_isvoid(obj)) {
910 dns_fixedname_t fixed;
911 dns_name_t *name;
912 isc_buffer_t b;
913 char *str;
914 cfg_obj_t *exclude;
916 dns_fixedname_init(&fixed);
917 name = dns_fixedname_name(&fixed);
918 for (element = cfg_list_first(obj);
919 element != NULL;
920 element = cfg_list_next(element)) {
921 exclude = cfg_listelt_value(element);
922 str = cfg_obj_asstring(exclude);
923 isc_buffer_init(&b, str, strlen(str));
924 isc_buffer_add(&b, strlen(str));
925 CHECK(dns_name_fromtext(name, &b, dns_rootname,
926 ISC_FALSE, NULL));
927 CHECK(dns_view_excludedelegationonly(view,
928 name));
931 } else
932 dns_view_setrootdelonly(view, ISC_FALSE);
934 result = ISC_R_SUCCESS;
936 cleanup:
937 if (dispatch4 != NULL)
938 dns_dispatch_detach(&dispatch4);
939 if (dispatch6 != NULL)
940 dns_dispatch_detach(&dispatch6);
941 if (cmctx != NULL)
942 isc_mem_detach(&cmctx);
944 if (cache != NULL)
945 dns_cache_detach(&cache);
947 return (result);
951 * Create the special view that handles queries under "bind. CH".
953 static isc_result_t
954 create_bind_view(dns_view_t **viewp) {
955 isc_result_t result;
956 dns_view_t *view = NULL;
958 REQUIRE(viewp != NULL && *viewp == NULL);
960 CHECK(dns_view_create(ns_g_mctx, dns_rdataclass_ch, "_bind", &view));
962 /* Transfer ownership. */
963 *viewp = view;
964 view = NULL;
966 result = ISC_R_SUCCESS;
968 cleanup:
969 if (view != NULL)
970 dns_view_detach(&view);
972 return (result);
976 * Create the zone that handles queries for "version.bind. CH". The
977 * version string is returned either from the "version" configuration
978 * option or the global defaults.
980 static isc_result_t
981 create_version_zone(cfg_obj_t **maps, dns_zonemgr_t *zmgr, dns_view_t *view) {
982 isc_result_t result;
983 dns_db_t *db = NULL;
984 dns_zone_t *zone = NULL;
985 dns_dbversion_t *dbver = NULL;
986 dns_difftuple_t *tuple = NULL;
987 dns_diff_t diff;
988 char *versiontext;
989 unsigned char buf[256];
990 isc_region_t r;
991 size_t len;
992 dns_rdata_t rdata = DNS_RDATA_INIT;
993 static unsigned char origindata[] = "\007version\004bind";
994 dns_name_t origin;
995 cfg_obj_t *obj = NULL;
996 dns_acl_t *acl = NULL;
998 dns_diff_init(ns_g_mctx, &diff);
1000 dns_name_init(&origin, NULL);
1001 r.base = origindata;
1002 r.length = sizeof(origindata);
1003 dns_name_fromregion(&origin, &r);
1005 result = ns_config_get(maps, "version", &obj);
1006 INSIST(result == ISC_R_SUCCESS);
1007 versiontext = cfg_obj_asstring(obj);
1008 len = strlen(versiontext);
1009 if (len > 255U)
1010 len = 255; /* Silently truncate. */
1011 buf[0] = len;
1012 memcpy(buf + 1, versiontext, len);
1014 r.base = buf;
1015 r.length = 1 + len;
1016 dns_rdata_fromregion(&rdata, dns_rdataclass_ch, dns_rdatatype_txt, &r);
1018 CHECK(dns_zone_create(&zone, ns_g_mctx));
1019 CHECK(dns_zone_setorigin(zone, &origin));
1020 dns_zone_settype(zone, dns_zone_master);
1021 dns_zone_setclass(zone, dns_rdataclass_ch);
1022 /* Transfers don't work so deny them. */
1023 CHECK(dns_acl_none(ns_g_mctx, &acl));
1024 dns_zone_setxfracl(zone, acl);
1025 dns_acl_detach(&acl);
1026 dns_zone_setview(zone, view);
1028 CHECK(dns_zonemgr_managezone(zmgr, zone));
1030 CHECK(dns_db_create(ns_g_mctx, "rbt", &origin, dns_dbtype_zone,
1031 dns_rdataclass_ch, 0, NULL, &db));
1033 CHECK(dns_db_newversion(db, &dbver));
1035 CHECK(dns_difftuple_create(ns_g_mctx, DNS_DIFFOP_ADD, &origin,
1036 0, &rdata, &tuple));
1037 dns_diff_append(&diff, &tuple);
1038 CHECK(dns_diff_apply(&diff, db, dbver));
1040 dns_db_closeversion(db, &dbver, ISC_TRUE);
1042 CHECK(dns_zone_replacedb(zone, db, ISC_FALSE));
1044 CHECK(dns_view_addzone(view, zone));
1046 result = ISC_R_SUCCESS;
1048 cleanup:
1049 if (zone != NULL)
1050 dns_zone_detach(&zone);
1051 if (dbver != NULL)
1052 dns_db_closeversion(db, &dbver, ISC_FALSE);
1053 if (db != NULL)
1054 dns_db_detach(&db);
1055 dns_diff_clear(&diff);
1057 return (result);
1061 * Create the special zone that handles queries for "authors.bind. CH".
1062 * The strings returned list the BIND 9 authors.
1064 static isc_result_t
1065 create_authors_zone(cfg_obj_t *options, dns_zonemgr_t *zmgr, dns_view_t *view)
1067 isc_result_t result;
1068 dns_db_t *db = NULL;
1069 dns_zone_t *zone = NULL;
1070 dns_dbversion_t *dbver = NULL;
1071 dns_difftuple_t *tuple;
1072 dns_diff_t diff;
1073 isc_region_t r;
1074 isc_region_t cr;
1075 dns_rdata_t rdata = DNS_RDATA_INIT;
1076 static const char origindata[] = "\007authors\004bind";
1077 dns_name_t origin;
1078 int i;
1079 static const char *authors[] = {
1080 "\014Mark Andrews",
1081 "\015James Brister",
1082 "\014Ben Cottrell",
1083 "\015Michael Graff",
1084 "\022Andreas Gustafsson",
1085 "\012Bob Halley",
1086 "\016David Lawrence",
1087 "\013Danny Mayer",
1088 "\013Damien Neil",
1089 "\013Matt Nelson",
1090 "\016Michael Sawyer",
1091 "\020Brian Wellington",
1092 NULL,
1094 cfg_obj_t *obj = NULL;
1095 dns_acl_t *acl = NULL;
1098 * If a version string is specified, disable the authors.bind zone.
1100 if (options != NULL &&
1101 cfg_map_get(options, "version", &obj) == ISC_R_SUCCESS)
1102 return (ISC_R_SUCCESS);
1104 dns_diff_init(ns_g_mctx, &diff);
1106 dns_name_init(&origin, NULL);
1107 DE_CONST(origindata, r.base);
1108 r.length = sizeof(origindata);
1109 dns_name_fromregion(&origin, &r);
1111 CHECK(dns_zone_create(&zone, ns_g_mctx));
1112 CHECK(dns_zone_setorigin(zone, &origin));
1113 dns_zone_settype(zone, dns_zone_master);
1114 dns_zone_setclass(zone, dns_rdataclass_ch);
1115 /* Transfers don't work so deny them. */
1116 CHECK(dns_acl_none(ns_g_mctx, &acl));
1117 dns_zone_setxfracl(zone, acl);
1118 dns_acl_detach(&acl);
1119 dns_zone_setview(zone, view);
1121 CHECK(dns_zonemgr_managezone(zmgr, zone));
1123 CHECK(dns_db_create(ns_g_mctx, "rbt", &origin, dns_dbtype_zone,
1124 dns_rdataclass_ch, 0, NULL, &db));
1126 CHECK(dns_db_newversion(db, &dbver));
1128 for (i = 0; authors[i] != NULL; i++) {
1129 DE_CONST(authors[i], cr.base);
1130 cr.length = strlen(authors[i]);
1131 INSIST(cr.length == ((const unsigned char *)cr.base)[0] + 1U);
1132 dns_rdata_fromregion(&rdata, dns_rdataclass_ch,
1133 dns_rdatatype_txt, &cr);
1134 tuple = NULL;
1135 CHECK(dns_difftuple_create(ns_g_mctx, DNS_DIFFOP_ADD, &origin,
1136 0, &rdata, &tuple));
1137 dns_diff_append(&diff, &tuple);
1138 dns_rdata_reset(&rdata);
1141 CHECK(dns_diff_apply(&diff, db, dbver));
1143 dns_db_closeversion(db, &dbver, ISC_TRUE);
1145 CHECK(dns_zone_replacedb(zone, db, ISC_FALSE));
1147 CHECK(dns_view_addzone(view, zone));
1149 result = ISC_R_SUCCESS;
1151 cleanup:
1152 if (zone != NULL)
1153 dns_zone_detach(&zone);
1154 if (dbver != NULL)
1155 dns_db_closeversion(db, &dbver, ISC_FALSE);
1156 if (db != NULL)
1157 dns_db_detach(&db);
1158 dns_diff_clear(&diff);
1160 return (result);
1163 static isc_result_t
1164 configure_hints(dns_view_t *view, const char *filename) {
1165 isc_result_t result;
1166 dns_db_t *db;
1168 db = NULL;
1169 result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
1170 if (result == ISC_R_SUCCESS) {
1171 dns_view_sethints(view, db);
1172 dns_db_detach(&db);
1175 return (result);
1178 static isc_result_t
1179 configure_forward(cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
1180 cfg_obj_t *forwarders, cfg_obj_t *forwardtype)
1182 cfg_obj_t *portobj;
1183 cfg_obj_t *faddresses;
1184 cfg_listelt_t *element;
1185 dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
1186 isc_sockaddrlist_t addresses;
1187 isc_sockaddr_t *sa;
1188 isc_result_t result;
1189 in_port_t port;
1192 * Determine which port to send forwarded requests to.
1194 if (ns_g_lwresdonly && ns_g_port != 0)
1195 port = ns_g_port;
1196 else
1197 CHECKM(ns_config_getport(config, &port), "port");
1199 if (forwarders != NULL) {
1200 portobj = cfg_tuple_get(forwarders, "port");
1201 if (cfg_obj_isuint32(portobj)) {
1202 isc_uint32_t val = cfg_obj_asuint32(portobj);
1203 if (val > ISC_UINT16_MAX) {
1204 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
1205 "port '%u' out of range", val);
1206 return (ISC_R_RANGE);
1208 port = (in_port_t) val;
1212 faddresses = NULL;
1213 if (forwarders != NULL)
1214 faddresses = cfg_tuple_get(forwarders, "addresses");
1216 ISC_LIST_INIT(addresses);
1218 for (element = cfg_list_first(faddresses);
1219 element != NULL;
1220 element = cfg_list_next(element))
1222 cfg_obj_t *forwarder = cfg_listelt_value(element);
1223 sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t));
1224 if (sa == NULL) {
1225 result = ISC_R_NOMEMORY;
1226 goto cleanup;
1228 *sa = *cfg_obj_assockaddr(forwarder);
1229 if (isc_sockaddr_getport(sa) == 0)
1230 isc_sockaddr_setport(sa, port);
1231 ISC_LINK_INIT(sa, link);
1232 ISC_LIST_APPEND(addresses, sa, link);
1235 if (ISC_LIST_EMPTY(addresses)) {
1236 if (forwardtype != NULL)
1237 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
1238 "no forwarders seen; disabling "
1239 "forwarding");
1240 fwdpolicy = dns_fwdpolicy_none;
1241 } else {
1242 if (forwardtype == NULL)
1243 fwdpolicy = dns_fwdpolicy_first;
1244 else {
1245 char *forwardstr = cfg_obj_asstring(forwardtype);
1246 if (strcasecmp(forwardstr, "first") == 0)
1247 fwdpolicy = dns_fwdpolicy_first;
1248 else if (strcasecmp(forwardstr, "only") == 0)
1249 fwdpolicy = dns_fwdpolicy_only;
1250 else
1251 INSIST(0);
1255 result = dns_fwdtable_add(view->fwdtable, origin, &addresses,
1256 fwdpolicy);
1257 if (result != ISC_R_SUCCESS) {
1258 char namebuf[DNS_NAME_FORMATSIZE];
1259 dns_name_format(origin, namebuf, sizeof(namebuf));
1260 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
1261 "could not set up forwarding for domain '%s': %s",
1262 namebuf, isc_result_totext(result));
1263 goto cleanup;
1266 result = ISC_R_SUCCESS;
1268 cleanup:
1270 while (!ISC_LIST_EMPTY(addresses)) {
1271 sa = ISC_LIST_HEAD(addresses);
1272 ISC_LIST_UNLINK(addresses, sa, link);
1273 isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t));
1276 return (result);
1280 * Create a new view and add it to the list.
1282 * If 'vconfig' is NULL, create the default view.
1284 * The view created is attached to '*viewp'.
1286 static isc_result_t
1287 create_view(cfg_obj_t *vconfig, dns_viewlist_t *viewlist, dns_view_t **viewp) {
1288 isc_result_t result;
1289 const char *viewname;
1290 dns_rdataclass_t viewclass;
1291 dns_view_t *view = NULL;
1293 if (vconfig != NULL) {
1294 cfg_obj_t *classobj = NULL;
1296 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
1297 classobj = cfg_tuple_get(vconfig, "class");
1298 result = ns_config_getclass(classobj, dns_rdataclass_in,
1299 &viewclass);
1300 } else {
1301 viewname = "_default";
1302 viewclass = dns_rdataclass_in;
1304 result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
1305 if (result == ISC_R_SUCCESS)
1306 return (ISC_R_EXISTS);
1307 if (result != ISC_R_NOTFOUND)
1308 return (result);
1309 INSIST(view == NULL);
1311 result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
1312 if (result != ISC_R_SUCCESS)
1313 return (result);
1315 ISC_LIST_APPEND(*viewlist, view, link);
1316 dns_view_attach(view, viewp);
1317 return (ISC_R_SUCCESS);
1321 * Configure or reconfigure a zone.
1323 static isc_result_t
1324 configure_zone(cfg_obj_t *config, cfg_obj_t *zconfig, cfg_obj_t *vconfig,
1325 isc_mem_t *mctx, dns_view_t *view,
1326 ns_aclconfctx_t *aclconf)
1328 dns_view_t *pview = NULL; /* Production view */
1329 dns_zone_t *zone = NULL; /* New or reused zone */
1330 dns_zone_t *dupzone = NULL;
1331 cfg_obj_t *options = NULL;
1332 cfg_obj_t *zoptions = NULL;
1333 cfg_obj_t *typeobj = NULL;
1334 cfg_obj_t *forwarders = NULL;
1335 cfg_obj_t *forwardtype = NULL;
1336 cfg_obj_t *only = NULL;
1337 isc_result_t result;
1338 isc_result_t tresult;
1339 isc_buffer_t buffer;
1340 dns_fixedname_t fixorigin;
1341 dns_name_t *origin;
1342 const char *zname;
1343 dns_rdataclass_t zclass;
1344 const char *ztypestr;
1346 options = NULL;
1347 (void)cfg_map_get(config, "options", &options);
1349 zoptions = cfg_tuple_get(zconfig, "options");
1352 * Get the zone origin as a dns_name_t.
1354 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1355 isc_buffer_init(&buffer, zname, strlen(zname));
1356 isc_buffer_add(&buffer, strlen(zname));
1357 dns_fixedname_init(&fixorigin);
1358 CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
1359 &buffer, dns_rootname, ISC_FALSE, NULL));
1360 origin = dns_fixedname_name(&fixorigin);
1362 CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
1363 view->rdclass, &zclass));
1364 if (zclass != view->rdclass) {
1365 const char *vname = NULL;
1366 if (vconfig != NULL)
1367 vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
1368 "name"));
1369 else
1370 vname = "<default view>";
1372 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1373 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1374 "zone '%s': wrong class for view '%s'",
1375 zname, vname);
1376 result = ISC_R_FAILURE;
1377 goto cleanup;
1380 (void)cfg_map_get(zoptions, "type", &typeobj);
1381 if (typeobj == NULL) {
1382 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
1383 "zone '%s' 'type' not specified", zname);
1384 return (ISC_R_FAILURE);
1386 ztypestr = cfg_obj_asstring(typeobj);
1389 * "hints zones" aren't zones. If we've got one,
1390 * configure it and return.
1392 if (strcasecmp(ztypestr, "hint") == 0) {
1393 cfg_obj_t *fileobj = NULL;
1394 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
1395 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1396 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1397 "zone '%s': 'file' not specified",
1398 zname);
1399 result = ISC_R_FAILURE;
1400 goto cleanup;
1402 if (dns_name_equal(origin, dns_rootname)) {
1403 char *hintsfile = cfg_obj_asstring(fileobj);
1405 result = configure_hints(view, hintsfile);
1406 if (result != ISC_R_SUCCESS) {
1407 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1408 NS_LOGMODULE_SERVER,
1409 ISC_LOG_ERROR,
1410 "could not configure root hints "
1411 "from '%s': %s", hintsfile,
1412 isc_result_totext(result));
1413 goto cleanup;
1416 * Hint zones may also refer to delegation only points.
1418 only = NULL;
1419 tresult = cfg_map_get(zoptions, "delegation-only",
1420 &only);
1421 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
1422 CHECK(dns_view_adddelegationonly(view, origin));
1423 } else {
1424 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1425 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1426 "ignoring non-root hint zone '%s'",
1427 zname);
1428 result = ISC_R_SUCCESS;
1430 /* Skip ordinary zone processing. */
1431 goto cleanup;
1435 * "forward zones" aren't zones either. Translate this syntax into
1436 * the appropriate selective forwarding configuration and return.
1438 if (strcasecmp(ztypestr, "forward") == 0) {
1439 forwardtype = NULL;
1440 forwarders = NULL;
1442 (void)cfg_map_get(zoptions, "forward", &forwardtype);
1443 (void)cfg_map_get(zoptions, "forwarders", &forwarders);
1444 result = configure_forward(config, view, origin, forwarders,
1445 forwardtype);
1446 goto cleanup;
1450 * "delegation-only zones" aren't zones either.
1452 if (strcasecmp(ztypestr, "delegation-only") == 0) {
1453 result = dns_view_adddelegationonly(view, origin);
1454 goto cleanup;
1458 * Check for duplicates in the new zone table.
1460 result = dns_view_findzone(view, origin, &dupzone);
1461 if (result == ISC_R_SUCCESS) {
1463 * We already have this zone!
1465 dns_zone_detach(&dupzone);
1466 result = ISC_R_EXISTS;
1467 goto cleanup;
1469 INSIST(dupzone == NULL);
1472 * See if we can reuse an existing zone. This is
1473 * only possible if all of these are true:
1474 * - The zone's view exists
1475 * - A zone with the right name exists in the view
1476 * - The zone is compatible with the config
1477 * options (e.g., an existing master zone cannot
1478 * be reused if the options specify a slave zone)
1480 result = dns_viewlist_find(&ns_g_server->viewlist,
1481 view->name, view->rdclass,
1482 &pview);
1483 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
1484 goto cleanup;
1485 if (pview != NULL)
1486 result = dns_view_findzone(pview, origin, &zone);
1487 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
1488 goto cleanup;
1489 if (zone != NULL) {
1490 if (! ns_zone_reusable(zone, zconfig))
1491 dns_zone_detach(&zone);
1494 if (zone != NULL) {
1496 * We found a reusable zone. Make it use the
1497 * new view.
1499 dns_zone_setview(zone, view);
1500 } else {
1502 * We cannot reuse an existing zone, we have
1503 * to create a new one.
1505 CHECK(dns_zone_create(&zone, mctx));
1506 CHECK(dns_zone_setorigin(zone, origin));
1507 dns_zone_setview(zone, view);
1508 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
1512 * If the zone contains a 'forwarders' statement, configure
1513 * selective forwarding.
1515 forwarders = NULL;
1516 if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
1518 forwardtype = NULL;
1519 cfg_map_get(zoptions, "forward", &forwardtype);
1520 CHECK(configure_forward(config, view, origin, forwarders,
1521 forwardtype));
1525 * Stub and forward zones may also refer to delegation only points.
1527 only = NULL;
1528 if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
1530 if (cfg_obj_asboolean(only))
1531 CHECK(dns_view_adddelegationonly(view, origin));
1535 * Configure the zone.
1537 CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone));
1540 * Add the zone to its view in the new view list.
1542 CHECK(dns_view_addzone(view, zone));
1544 cleanup:
1545 if (zone != NULL)
1546 dns_zone_detach(&zone);
1547 if (pview != NULL)
1548 dns_view_detach(&pview);
1550 return (result);
1554 * Configure a single server quota.
1556 static void
1557 configure_server_quota(cfg_obj_t **maps, const char *name, isc_quota_t *quota)
1559 cfg_obj_t *obj = NULL;
1560 isc_result_t result;
1562 result = ns_config_get(maps, name, &obj);
1563 INSIST(result == ISC_R_SUCCESS);
1564 quota->max = cfg_obj_asuint32(obj);
1568 * This function is called as soon as the 'directory' statement has been
1569 * parsed. This can be extended to support other options if necessary.
1571 static isc_result_t
1572 directory_callback(const char *clausename, cfg_obj_t *obj, void *arg) {
1573 isc_result_t result;
1574 char *directory;
1576 REQUIRE(strcasecmp("directory", clausename) == 0);
1578 UNUSED(arg);
1579 UNUSED(clausename);
1582 * Change directory.
1584 directory = cfg_obj_asstring(obj);
1586 if (! isc_file_ischdiridempotent(directory))
1587 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
1588 "option 'directory' contains relative path '%s'",
1589 directory);
1591 result = isc_dir_chdir(directory);
1592 if (result != ISC_R_SUCCESS) {
1593 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1594 "change directory to '%s' failed: %s",
1595 directory, isc_result_totext(result));
1596 return (result);
1599 return (ISC_R_SUCCESS);
1602 static void
1603 scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
1604 isc_boolean_t match_mapped = server->aclenv.match_mapped;
1606 ns_interfacemgr_scan(server->interfacemgr, verbose);
1608 * Update the "localhost" and "localnets" ACLs to match the
1609 * current set of network interfaces.
1611 dns_aclenv_copy(&server->aclenv,
1612 ns_interfacemgr_getaclenv(server->interfacemgr));
1614 server->aclenv.match_mapped = match_mapped;
1618 * This event callback is invoked to do periodic network
1619 * interface scanning.
1621 static void
1622 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
1623 isc_result_t result;
1624 ns_server_t *server = (ns_server_t *) event->ev_arg;
1625 INSIST(task == server->task);
1626 UNUSED(task);
1627 isc_event_free(&event);
1629 * XXX should scan interfaces unlocked and get exclusive access
1630 * only to replace ACLs.
1632 result = isc_task_beginexclusive(server->task);
1633 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1634 scan_interfaces(server, ISC_FALSE);
1635 isc_task_endexclusive(server->task);
1638 static void
1639 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
1640 ns_server_t *server = (ns_server_t *) event->ev_arg;
1641 dns_view_t *view;
1643 UNUSED(task);
1644 isc_event_free(&event);
1645 view = ISC_LIST_HEAD(server->viewlist);
1646 while (view != NULL) {
1647 dns_view_dialup(view);
1648 view = ISC_LIST_NEXT(view, link);
1652 static isc_result_t
1653 setstatsfile(ns_server_t *server, const char *name) {
1654 char *p;
1656 REQUIRE(name != NULL);
1658 p = isc_mem_strdup(server->mctx, name);
1659 if (p == NULL)
1660 return (ISC_R_NOMEMORY);
1661 if (server->statsfile != NULL)
1662 isc_mem_free(server->mctx, server->statsfile);
1663 server->statsfile = p;
1664 return (ISC_R_SUCCESS);
1667 static isc_result_t
1668 setdumpfile(ns_server_t *server, const char *name) {
1669 char *p;
1671 REQUIRE(name != NULL);
1673 p = isc_mem_strdup(server->mctx, name);
1674 if (p == NULL)
1675 return (ISC_R_NOMEMORY);
1676 if (server->dumpfile != NULL)
1677 isc_mem_free(server->mctx, server->dumpfile);
1678 server->dumpfile = p;
1679 return (ISC_R_SUCCESS);
1682 static void
1683 set_limit(cfg_obj_t **maps, const char *configname, const char *description,
1684 isc_resource_t resourceid, isc_resourcevalue_t defaultvalue)
1686 cfg_obj_t *obj = NULL;
1687 char *resource;
1688 isc_resourcevalue_t value;
1689 isc_result_t result;
1691 if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
1692 return;
1694 if (cfg_obj_isstring(obj)) {
1695 resource = cfg_obj_asstring(obj);
1696 if (strcasecmp(resource, "unlimited") == 0)
1697 value = ISC_RESOURCE_UNLIMITED;
1698 else {
1699 INSIST(strcasecmp(resource, "default") == 0);
1700 value = defaultvalue;
1702 } else
1703 value = cfg_obj_asuint64(obj);
1705 result = isc_resource_setlimit(resourceid, value);
1706 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
1707 result == ISC_R_SUCCESS ?
1708 ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
1709 "set maximum %s to %" ISC_PRINT_QUADFORMAT "d: %s",
1710 description, value, isc_result_totext(result));
1713 #define SETLIMIT(cfgvar, resource, description) \
1714 set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
1715 ns_g_init ## resource)
1717 static void
1718 set_limits(cfg_obj_t **maps) {
1719 SETLIMIT("stacksize", stacksize, "stack size");
1720 SETLIMIT("datasize", datasize, "data size");
1721 SETLIMIT("coresize", coresize, "core size");
1722 SETLIMIT("files", openfiles, "open files");
1725 static isc_result_t
1726 load_configuration(const char *filename, ns_server_t *server,
1727 isc_boolean_t first_time)
1729 isc_result_t result;
1730 cfg_parser_t *parser = NULL;
1731 cfg_obj_t *config;
1732 cfg_obj_t *options;
1733 cfg_obj_t *views;
1734 cfg_obj_t *obj;
1735 cfg_obj_t *maps[3];
1736 cfg_listelt_t *element;
1737 dns_view_t *view = NULL;
1738 dns_view_t *view_next;
1739 dns_viewlist_t viewlist;
1740 dns_viewlist_t tmpviewlist;
1741 ns_aclconfctx_t aclconfctx;
1742 isc_uint32_t interface_interval;
1743 isc_uint32_t heartbeat_interval;
1744 in_port_t listen_port;
1745 int i;
1747 ns_aclconfctx_init(&aclconfctx);
1748 ISC_LIST_INIT(viewlist);
1750 /* Ensure exclusive access to configuration data. */
1751 result = isc_task_beginexclusive(server->task);
1752 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1755 * Parse the global default pseudo-config file.
1757 if (first_time) {
1758 CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
1759 RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
1760 &ns_g_defaults) ==
1761 ISC_R_SUCCESS);
1765 * Parse the configuration file using the new config code.
1767 result = ISC_R_FAILURE;
1768 config = NULL;
1771 * Unless this is lwresd with the -C option, parse the config file.
1773 if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
1774 isc_log_write(ns_g_lctx,
1775 NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
1776 ISC_LOG_INFO, "loading configuration from '%s'",
1777 filename);
1778 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
1779 cfg_parser_setcallback(parser, directory_callback, NULL);
1780 result = cfg_parse_file(parser, filename, &cfg_type_namedconf,
1781 &config);
1785 * If this is lwresd with the -C option, or lwresd with no -C or -c
1786 * option where the above parsing failed, parse resolv.conf.
1788 if (ns_g_lwresdonly &&
1789 (lwresd_g_useresolvconf ||
1790 (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
1792 isc_log_write(ns_g_lctx,
1793 NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
1794 ISC_LOG_INFO, "loading configuration from '%s'",
1795 lwresd_g_resolvconffile);
1796 if (parser != NULL)
1797 cfg_parser_destroy(&parser);
1798 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
1799 result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser,
1800 &config);
1802 CHECK(result);
1805 * Check the validity of the configuration.
1807 CHECK(cfg_check_namedconf(config, ns_g_lctx, ns_g_mctx));
1810 * Fill in the maps array, used for resolving defaults.
1812 i = 0;
1813 options = NULL;
1814 result = cfg_map_get(config, "options", &options);
1815 if (result == ISC_R_SUCCESS)
1816 maps[i++] = options;
1817 maps[i++] = ns_g_defaults;
1818 maps[i++] = NULL;
1821 * Set process limits, which (usually) needs to be done as root.
1823 set_limits(maps);
1826 * Configure various server options.
1828 configure_server_quota(maps, "transfers-out", &server->xfroutquota);
1829 configure_server_quota(maps, "tcp-clients", &server->tcpquota);
1830 configure_server_quota(maps, "recursive-clients",
1831 &server->recursionquota);
1833 CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx,
1834 ns_g_mctx, &server->blackholeacl));
1835 if (server->blackholeacl != NULL)
1836 dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
1837 server->blackholeacl);
1839 obj = NULL;
1840 result = ns_config_get(maps, "match-mapped-addresses", &obj);
1841 INSIST(result == ISC_R_SUCCESS);
1842 server->aclenv.match_mapped = cfg_obj_asboolean(obj);
1845 * Configure the zone manager.
1847 obj = NULL;
1848 result = ns_config_get(maps, "transfers-in", &obj);
1849 INSIST(result == ISC_R_SUCCESS);
1850 dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
1852 obj = NULL;
1853 result = ns_config_get(maps, "transfers-per-ns", &obj);
1854 INSIST(result == ISC_R_SUCCESS);
1855 dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
1857 obj = NULL;
1858 result = ns_config_get(maps, "serial-query-rate", &obj);
1859 INSIST(result == ISC_R_SUCCESS);
1860 dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
1863 * Determine which port to use for listening for incoming connections.
1865 if (ns_g_port != 0)
1866 listen_port = ns_g_port;
1867 else
1868 CHECKM(ns_config_getport(config, &listen_port), "port");
1871 * Configure the interface manager according to the "listen-on"
1872 * statement.
1875 cfg_obj_t *clistenon = NULL;
1876 ns_listenlist_t *listenon = NULL;
1878 clistenon = NULL;
1880 * Even though listen-on is present in the default
1881 * configuration, we can't use it here, since it isn't
1882 * used if we're in lwresd mode. This way is easier.
1884 if (options != NULL)
1885 (void)cfg_map_get(options, "listen-on", &clistenon);
1886 if (clistenon != NULL) {
1887 result = ns_listenlist_fromconfig(clistenon,
1888 config,
1889 &aclconfctx,
1890 ns_g_mctx,
1891 &listenon);
1892 } else if (!ns_g_lwresdonly) {
1894 * Not specified, use default.
1896 CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
1897 ISC_TRUE, &listenon));
1899 if (listenon != NULL) {
1900 ns_interfacemgr_setlistenon4(server->interfacemgr,
1901 listenon);
1902 ns_listenlist_detach(&listenon);
1906 * Ditto for IPv6.
1909 cfg_obj_t *clistenon = NULL;
1910 ns_listenlist_t *listenon = NULL;
1912 if (options != NULL)
1913 (void)cfg_map_get(options, "listen-on-v6", &clistenon);
1914 if (clistenon != NULL) {
1915 result = ns_listenlist_fromconfig(clistenon,
1916 config,
1917 &aclconfctx,
1918 ns_g_mctx,
1919 &listenon);
1920 } else if (!ns_g_lwresdonly) {
1922 * Not specified, use default.
1924 CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
1925 ISC_FALSE, &listenon));
1927 if (listenon != NULL) {
1928 ns_interfacemgr_setlistenon6(server->interfacemgr,
1929 listenon);
1930 ns_listenlist_detach(&listenon);
1935 * Rescan the interface list to pick up changes in the
1936 * listen-on option. It's important that we do this before we try
1937 * to configure the query source, since the dispatcher we use might
1938 * be shared with an interface.
1940 scan_interfaces(server, ISC_TRUE);
1943 * Arrange for further interface scanning to occur periodically
1944 * as specified by the "interface-interval" option.
1946 obj = NULL;
1947 result = ns_config_get(maps, "interface-interval", &obj);
1948 INSIST(result == ISC_R_SUCCESS);
1949 interface_interval = cfg_obj_asuint32(obj) * 60;
1950 if (interface_interval == 0) {
1951 isc_timer_reset(server->interface_timer,
1952 isc_timertype_inactive,
1953 NULL, NULL, ISC_TRUE);
1954 } else if (server->interface_interval != interface_interval) {
1955 isc_interval_t interval;
1956 isc_interval_set(&interval, interface_interval, 0);
1957 isc_timer_reset(server->interface_timer, isc_timertype_ticker,
1958 NULL, &interval, ISC_FALSE);
1960 server->interface_interval = interface_interval;
1963 * Configure the dialup heartbeat timer.
1965 obj = NULL;
1966 result = ns_config_get(maps, "heartbeat-interval", &obj);
1967 INSIST(result == ISC_R_SUCCESS);
1968 heartbeat_interval = cfg_obj_asuint32(obj) * 60;
1969 if (heartbeat_interval == 0) {
1970 isc_timer_reset(server->heartbeat_timer,
1971 isc_timertype_inactive,
1972 NULL, NULL, ISC_TRUE);
1973 } else if (server->heartbeat_interval != heartbeat_interval) {
1974 isc_interval_t interval;
1975 isc_interval_set(&interval, heartbeat_interval, 0);
1976 isc_timer_reset(server->heartbeat_timer, isc_timertype_ticker,
1977 NULL, &interval, ISC_FALSE);
1979 server->heartbeat_interval = heartbeat_interval;
1982 * Configure and freeze all explicit views. Explicit
1983 * views that have zones were already created at parsing
1984 * time, but views with no zones must be created here.
1986 views = NULL;
1987 (void)cfg_map_get(config, "view", &views);
1988 for (element = cfg_list_first(views);
1989 element != NULL;
1990 element = cfg_list_next(element))
1992 cfg_obj_t *vconfig;
1994 view = NULL;
1995 vconfig = cfg_listelt_value(element);
1996 CHECK(create_view(vconfig, &viewlist, &view));
1997 INSIST(view != NULL);
1998 CHECK(configure_view(view, config, vconfig,
1999 ns_g_mctx, &aclconfctx));
2000 dns_view_freeze(view);
2001 dns_view_detach(&view);
2005 * Make sure we have a default view if and only if there
2006 * were no explicit views.
2008 if (views == NULL) {
2010 * No explicit views; there ought to be a default view.
2011 * There may already be one created as a side effect
2012 * of zone statements, or we may have to create one.
2013 * In either case, we need to configure and freeze it.
2015 CHECK(create_view(NULL, &viewlist, &view));
2016 CHECK(configure_view(view, config, NULL, ns_g_mctx,
2017 &aclconfctx));
2018 dns_view_freeze(view);
2019 dns_view_detach(&view);
2023 * Create (or recreate) the internal _bind view.
2025 CHECK(create_bind_view(&view));
2026 CHECK(configure_view_acl(NULL, config, "allow-query",
2027 &aclconfctx, ns_g_mctx, &view->queryacl));
2028 ISC_LIST_APPEND(viewlist, view, link);
2029 CHECK(create_version_zone(maps, server->zonemgr, view));
2030 CHECK(create_authors_zone(options, server->zonemgr, view));
2031 dns_view_freeze(view);
2032 view = NULL;
2035 * Swap our new view list with the production one.
2037 tmpviewlist = server->viewlist;
2038 server->viewlist = viewlist;
2039 viewlist = tmpviewlist;
2042 * Load the TKEY information from the configuration.
2044 if (options != NULL) {
2045 dns_tkeyctx_t *t = NULL;
2046 CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
2047 &t),
2048 "configuring TKEY");
2049 if (server->tkeyctx != NULL)
2050 dns_tkeyctx_destroy(&server->tkeyctx);
2051 server->tkeyctx = t;
2055 * Bind the control port(s).
2057 CHECKM(ns_controls_configure(ns_g_server->controls, config,
2058 &aclconfctx),
2059 "binding control channel(s)");
2062 * Bind the lwresd port(s).
2064 CHECKM(ns_lwresd_configure(ns_g_mctx, config),
2065 "binding lightweight resolver ports");
2068 * Open the source of entropy.
2070 if (first_time) {
2071 obj = NULL;
2072 result = ns_config_get(maps, "random-device", &obj);
2073 if (result != ISC_R_SUCCESS) {
2074 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2075 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
2076 "no source of entropy found");
2077 } else {
2078 const char *randomdev = cfg_obj_asstring(obj);
2079 result = isc_entropy_createfilesource(ns_g_entropy,
2080 randomdev);
2081 if (result != ISC_R_SUCCESS)
2082 isc_log_write(ns_g_lctx,
2083 NS_LOGCATEGORY_GENERAL,
2084 NS_LOGMODULE_SERVER,
2085 ISC_LOG_INFO,
2086 "could not open entropy source "
2087 "%s: %s",
2088 randomdev,
2089 isc_result_totext(result));
2094 * Relinquish root privileges.
2096 if (first_time)
2097 ns_os_changeuser();
2100 * Configure the logging system.
2102 * Do this after changing UID to make sure that any log
2103 * files specified in named.conf get created by the
2104 * unprivileged user, not root.
2106 if (ns_g_logstderr) {
2107 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2108 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
2109 "ignoring config file logging "
2110 "statement due to -g option");
2111 } else {
2112 cfg_obj_t *logobj = NULL;
2113 isc_logconfig_t *logc = NULL;
2115 CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
2116 "creating new logging configuration");
2118 logobj = NULL;
2119 (void)cfg_map_get(config, "logging", &logobj);
2120 if (logobj != NULL) {
2121 CHECKM(ns_log_configure(logc, logobj),
2122 "configuring logging");
2123 } else {
2124 CHECKM(ns_log_setdefaultchannels(logc),
2125 "setting up default logging channels");
2126 CHECKM(ns_log_setunmatchedcategory(logc),
2127 "setting up default 'category unmatched'");
2128 CHECKM(ns_log_setdefaultcategory(logc),
2129 "setting up default 'category default'");
2132 result = isc_logconfig_use(ns_g_lctx, logc);
2133 if (result != ISC_R_SUCCESS) {
2134 isc_logconfig_destroy(&logc);
2135 CHECKM(result, "installing logging configuration");
2138 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2139 NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
2140 "now using logging configuration from "
2141 "config file");
2145 * Set the default value of the query logging flag depending
2146 * whether a "queries" category has been defined. This is
2147 * a disgusting hack, but we need to do this for BIND 8
2148 * compatibility.
2150 if (first_time) {
2151 cfg_obj_t *logobj = NULL;
2152 cfg_obj_t *categories = NULL;
2153 (void)cfg_map_get(config, "logging", &logobj);
2154 if (logobj != NULL)
2155 (void)cfg_map_get(logobj, "category", &categories);
2156 if (categories != NULL) {
2157 cfg_listelt_t *element;
2158 for (element = cfg_list_first(categories);
2159 element != NULL;
2160 element = cfg_list_next(element))
2162 cfg_obj_t *catobj;
2163 char *str;
2165 obj = cfg_listelt_value(element);
2166 catobj = cfg_tuple_get(obj, "name");
2167 str = cfg_obj_asstring(catobj);
2168 if (strcasecmp(str, "queries") == 0)
2169 server->log_queries = ISC_TRUE;
2174 obj = NULL;
2175 if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
2176 ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
2177 else if (ns_g_lwresdonly)
2178 ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
2179 else
2180 ns_os_writepidfile(ns_g_defaultpidfile, first_time);
2182 obj = NULL;
2183 result = ns_config_get(maps, "statistics-file", &obj);
2184 INSIST(result == ISC_R_SUCCESS);
2185 CHECKM(setstatsfile(server, cfg_obj_asstring(obj)), "strdup");
2187 obj = NULL;
2188 result = ns_config_get(maps, "dump-file", &obj);
2189 INSIST(result == ISC_R_SUCCESS);
2190 CHECKM(setdumpfile(server, cfg_obj_asstring(obj)), "strdup");
2192 cleanup:
2193 ns_aclconfctx_destroy(&aclconfctx);
2195 if (parser != NULL) {
2196 if (config != NULL)
2197 cfg_obj_destroy(parser, &config);
2198 cfg_parser_destroy(&parser);
2201 if (view != NULL)
2202 dns_view_detach(&view);
2205 * This cleans up either the old production view list
2206 * or our temporary list depending on whether they
2207 * were swapped above or not.
2209 for (view = ISC_LIST_HEAD(viewlist);
2210 view != NULL;
2211 view = view_next) {
2212 view_next = ISC_LIST_NEXT(view, link);
2213 ISC_LIST_UNLINK(viewlist, view, link);
2214 dns_view_detach(&view);
2218 /* Relinquish exclusive access to configuration data. */
2219 isc_task_endexclusive(server->task);
2221 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2222 ISC_LOG_DEBUG(1), "load_configuration: %s",
2223 isc_result_totext(result));
2225 return (result);
2228 static isc_result_t
2229 load_zones(ns_server_t *server, isc_boolean_t stop) {
2230 isc_result_t result;
2231 dns_view_t *view;
2233 result = isc_task_beginexclusive(server->task);
2234 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2237 * Load zone data from disk.
2239 for (view = ISC_LIST_HEAD(server->viewlist);
2240 view != NULL;
2241 view = ISC_LIST_NEXT(view, link))
2243 CHECK(dns_view_load(view, stop));
2247 * Force zone maintenance. Do this after loading
2248 * so that we know when we need to force AXFR of
2249 * slave zones whose master files are missing.
2251 CHECK(dns_zonemgr_forcemaint(server->zonemgr));
2252 cleanup:
2253 isc_task_endexclusive(server->task);
2254 return (result);
2257 static isc_result_t
2258 load_new_zones(ns_server_t *server, isc_boolean_t stop) {
2259 isc_result_t result;
2260 dns_view_t *view;
2262 result = isc_task_beginexclusive(server->task);
2263 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2266 * Load zone data from disk.
2268 for (view = ISC_LIST_HEAD(server->viewlist);
2269 view != NULL;
2270 view = ISC_LIST_NEXT(view, link))
2272 CHECK(dns_view_loadnew(view, stop));
2275 * Force zone maintenance. Do this after loading
2276 * so that we know when we need to force AXFR of
2277 * slave zones whose master files are missing.
2279 CHECK(dns_zonemgr_forcemaint(server->zonemgr));
2280 cleanup:
2281 isc_task_endexclusive(server->task);
2282 return (result);
2285 static void
2286 run_server(isc_task_t *task, isc_event_t *event) {
2287 isc_result_t result;
2288 ns_server_t *server = (ns_server_t *)event->ev_arg;
2290 UNUSED(task);
2292 isc_event_free(&event);
2294 CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
2295 &ns_g_dispatchmgr),
2296 "creating dispatch manager");
2298 CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
2299 ns_g_socketmgr, ns_g_dispatchmgr,
2300 &server->interfacemgr),
2301 "creating interface manager");
2303 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
2304 NULL, NULL, server->task,
2305 interface_timer_tick,
2306 server, &server->interface_timer),
2307 "creating interface timer");
2309 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
2310 NULL, NULL, server->task,
2311 heartbeat_timer_tick,
2312 server, &server->heartbeat_timer),
2313 "creating heartbeat timer");
2315 CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
2316 "creating default configuration parser");
2318 if (ns_g_lwresdonly)
2319 CHECKFATAL(load_configuration(lwresd_g_conffile, server,
2320 ISC_TRUE),
2321 "loading configuration");
2322 else
2323 CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
2324 "loading configuration");
2326 isc_hash_init();
2328 CHECKFATAL(load_zones(server, ISC_FALSE),
2329 "loading zones");
2331 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2332 ISC_LOG_INFO, "running");
2335 void
2336 ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
2338 REQUIRE(NS_SERVER_VALID(server));
2340 server->flushonshutdown = flush;
2343 static void
2344 shutdown_server(isc_task_t *task, isc_event_t *event) {
2345 isc_result_t result;
2346 dns_view_t *view, *view_next;
2347 ns_server_t *server = (ns_server_t *)event->ev_arg;
2348 isc_boolean_t flush = server->flushonshutdown;
2350 UNUSED(task);
2351 INSIST(task == server->task);
2353 result = isc_task_beginexclusive(server->task);
2354 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2356 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2357 ISC_LOG_INFO, "shutting down%s",
2358 flush ? ": flushing changes" : "");
2360 ns_controls_shutdown(server->controls);
2361 end_reserved_dispatches(server, ISC_TRUE);
2363 cfg_obj_destroy(ns_g_parser, &ns_g_config);
2364 cfg_parser_destroy(&ns_g_parser);
2366 for (view = ISC_LIST_HEAD(server->viewlist);
2367 view != NULL;
2368 view = view_next) {
2369 view_next = ISC_LIST_NEXT(view, link);
2370 ISC_LIST_UNLINK(server->viewlist, view, link);
2371 if (flush)
2372 dns_view_flushanddetach(&view);
2373 else
2374 dns_view_detach(&view);
2377 isc_timer_detach(&server->interface_timer);
2378 isc_timer_detach(&server->heartbeat_timer);
2380 ns_interfacemgr_shutdown(server->interfacemgr);
2381 ns_interfacemgr_detach(&server->interfacemgr);
2383 dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
2385 dns_zonemgr_shutdown(server->zonemgr);
2387 if (server->blackholeacl != NULL)
2388 dns_acl_detach(&server->blackholeacl);
2390 dns_db_detach(&server->in_roothints);
2392 isc_task_endexclusive(server->task);
2394 isc_task_detach(&server->task);
2396 isc_event_free(&event);
2399 void
2400 ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
2401 isc_result_t result;
2403 ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
2404 if (server == NULL)
2405 fatal("allocating server object", ISC_R_NOMEMORY);
2407 server->mctx = mctx;
2408 server->task = NULL;
2410 /* Initialize configuration data with default values. */
2412 result = isc_quota_init(&server->xfroutquota, 10);
2413 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2414 result = isc_quota_init(&server->tcpquota, 10);
2415 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2416 result = isc_quota_init(&server->recursionquota, 100);
2417 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2419 result = dns_aclenv_init(mctx, &server->aclenv);
2420 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2422 /* Initialize server data structures. */
2423 server->zonemgr = NULL;
2424 server->interfacemgr = NULL;
2425 ISC_LIST_INIT(server->viewlist);
2426 server->in_roothints = NULL;
2427 server->blackholeacl = NULL;
2429 CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
2430 &server->in_roothints),
2431 "setting up root hints");
2433 CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
2434 "initializing reload event lock");
2435 server->reload_event =
2436 isc_event_allocate(ns_g_mctx, server,
2437 NS_EVENT_RELOAD,
2438 ns_server_reload,
2439 server,
2440 sizeof(isc_event_t));
2441 CHECKFATAL(server->reload_event == NULL ?
2442 ISC_R_NOMEMORY : ISC_R_SUCCESS,
2443 "allocating reload event");
2445 CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY),
2446 "initializing DST");
2448 server->tkeyctx = NULL;
2449 CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
2450 &server->tkeyctx),
2451 "creating TKEY context");
2454 * Setup the server task, which is responsible for coordinating
2455 * startup and shutdown of the server.
2457 CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
2458 "creating server task");
2459 isc_task_setname(server->task, "server", server);
2460 CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
2461 "isc_task_onshutdown");
2462 CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
2463 "isc_app_onrun");
2465 server->interface_timer = NULL;
2466 server->heartbeat_timer = NULL;
2468 server->interface_interval = 0;
2469 server->heartbeat_interval = 0;
2471 CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
2472 ns_g_socketmgr, &server->zonemgr),
2473 "dns_zonemgr_create");
2475 server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
2476 CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
2477 "isc_mem_strdup");
2478 server->querystats = NULL;
2479 CHECKFATAL(dns_stats_alloccounters(ns_g_mctx, &server->querystats),
2480 "dns_stats_alloccounters");
2482 server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
2483 CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
2484 "isc_mem_strdup");
2486 server->flushonshutdown = ISC_FALSE;
2487 server->log_queries = ISC_FALSE;
2489 server->controls = NULL;
2490 CHECKFATAL(ns_controls_create(server, &server->controls),
2491 "ns_controls_create");
2492 server->dispatchgen = 0;
2493 ISC_LIST_INIT(server->dispatches);
2495 server->magic = NS_SERVER_MAGIC;
2496 *serverp = server;
2499 void
2500 ns_server_destroy(ns_server_t **serverp) {
2501 ns_server_t *server = *serverp;
2502 REQUIRE(NS_SERVER_VALID(server));
2504 ns_controls_destroy(&server->controls);
2506 dns_stats_freecounters(server->mctx, &server->querystats);
2507 isc_mem_free(server->mctx, server->statsfile);
2509 isc_mem_free(server->mctx, server->dumpfile);
2511 dns_zonemgr_detach(&server->zonemgr);
2513 if (server->tkeyctx != NULL)
2514 dns_tkeyctx_destroy(&server->tkeyctx);
2516 dst_lib_destroy();
2518 isc_event_free(&server->reload_event);
2520 INSIST(ISC_LIST_EMPTY(server->viewlist));
2522 dns_aclenv_destroy(&server->aclenv);
2524 isc_quota_destroy(&server->recursionquota);
2525 isc_quota_destroy(&server->tcpquota);
2526 isc_quota_destroy(&server->xfroutquota);
2528 server->magic = 0;
2529 isc_mem_put(server->mctx, server, sizeof(*server));
2530 *serverp = NULL;
2533 static void
2534 fatal(const char *msg, isc_result_t result) {
2535 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2536 ISC_LOG_CRITICAL, "%s: %s", msg,
2537 isc_result_totext(result));
2538 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2539 ISC_LOG_CRITICAL, "exiting (due to fatal error)");
2540 exit(1);
2543 static void
2544 start_reserved_dispatches(ns_server_t *server) {
2546 REQUIRE(NS_SERVER_VALID(server));
2548 server->dispatchgen++;
2551 static void
2552 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
2553 ns_dispatch_t *dispatch, *nextdispatch;
2555 REQUIRE(NS_SERVER_VALID(server));
2557 for (dispatch = ISC_LIST_HEAD(server->dispatches);
2558 dispatch != NULL;
2559 dispatch = nextdispatch) {
2560 nextdispatch = ISC_LIST_NEXT(dispatch, link);
2561 if (!all && server->dispatchgen == dispatch-> dispatchgen)
2562 continue;
2563 ISC_LIST_UNLINK(server->dispatches, dispatch, link);
2564 dns_dispatch_detach(&dispatch->dispatch);
2565 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
2569 void
2570 ns_add_reserved_dispatch(ns_server_t *server, isc_sockaddr_t *addr) {
2571 ns_dispatch_t *dispatch;
2572 in_port_t port;
2573 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
2574 isc_result_t result;
2575 unsigned int attrs, attrmask;
2577 REQUIRE(NS_SERVER_VALID(server));
2579 port = isc_sockaddr_getport(addr);
2580 if (port == 0 || port >= 1024)
2581 return;
2583 for (dispatch = ISC_LIST_HEAD(server->dispatches);
2584 dispatch != NULL;
2585 dispatch = ISC_LIST_NEXT(dispatch, link)) {
2586 if (isc_sockaddr_equal(&dispatch->addr, addr))
2587 break;
2589 if (dispatch != NULL) {
2590 dispatch->dispatchgen = server->dispatchgen;
2591 return;
2594 dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
2595 if (dispatch == NULL) {
2596 result = ISC_R_NOMEMORY;
2597 goto cleanup;
2600 dispatch->addr = *addr;
2601 dispatch->dispatchgen = server->dispatchgen;
2602 dispatch->dispatch = NULL;
2604 attrs = 0;
2605 attrs |= DNS_DISPATCHATTR_UDP;
2606 switch (isc_sockaddr_pf(addr)) {
2607 case AF_INET:
2608 attrs |= DNS_DISPATCHATTR_IPV4;
2609 break;
2610 case AF_INET6:
2611 attrs |= DNS_DISPATCHATTR_IPV6;
2612 break;
2613 default:
2614 result = ISC_R_NOTIMPLEMENTED;
2615 goto cleanup;
2617 attrmask = 0;
2618 attrmask |= DNS_DISPATCHATTR_UDP;
2619 attrmask |= DNS_DISPATCHATTR_TCP;
2620 attrmask |= DNS_DISPATCHATTR_IPV4;
2621 attrmask |= DNS_DISPATCHATTR_IPV6;
2623 result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
2624 ns_g_taskmgr, &dispatch->addr, 4096,
2625 1000, 32768, 16411, 16433,
2626 attrs, attrmask, &dispatch->dispatch);
2627 if (result != ISC_R_SUCCESS)
2628 goto cleanup;
2630 ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
2632 return;
2634 cleanup:
2635 if (dispatch != NULL)
2636 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
2637 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
2638 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2639 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
2640 "unable to create dispatch for reserved port %s: %s",
2641 addrbuf, isc_result_totext(result));
2645 static isc_result_t
2646 loadconfig(ns_server_t *server) {
2647 isc_result_t result;
2648 start_reserved_dispatches(server);
2649 result = load_configuration(ns_g_lwresdonly ?
2650 lwresd_g_conffile : ns_g_conffile,
2651 server,
2652 ISC_FALSE);
2653 if (result == ISC_R_SUCCESS)
2654 end_reserved_dispatches(server, ISC_FALSE);
2655 else
2656 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2657 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
2658 "reloading configuration failed: %s",
2659 isc_result_totext(result));
2660 return (result);
2663 static void
2664 reload(ns_server_t *server) {
2665 isc_result_t result;
2666 CHECK(loadconfig(server));
2668 result = load_zones(server, ISC_FALSE);
2669 if (result != ISC_R_SUCCESS) {
2670 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2671 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
2672 "reloading zones failed: %s",
2673 isc_result_totext(result));
2675 cleanup: ;
2678 static void
2679 reconfig(ns_server_t *server) {
2680 isc_result_t result;
2681 CHECK(loadconfig(server));
2683 result = load_new_zones(server, ISC_FALSE);
2684 if (result != ISC_R_SUCCESS) {
2685 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2686 NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
2687 "loading new zones failed: %s",
2688 isc_result_totext(result));
2690 cleanup: ;
2694 * Handle a reload event (from SIGHUP).
2696 static void
2697 ns_server_reload(isc_task_t *task, isc_event_t *event) {
2698 ns_server_t *server = (ns_server_t *)event->ev_arg;
2700 INSIST(task = server->task);
2701 UNUSED(task);
2703 reload(server);
2705 LOCK(&server->reload_event_lock);
2706 INSIST(server->reload_event == NULL);
2707 server->reload_event = event;
2708 UNLOCK(&server->reload_event_lock);
2711 void
2712 ns_server_reloadwanted(ns_server_t *server) {
2713 LOCK(&server->reload_event_lock);
2714 if (server->reload_event != NULL)
2715 isc_task_send(server->task, &server->reload_event);
2716 UNLOCK(&server->reload_event_lock);
2719 static char *
2720 next_token(char **stringp, const char *delim) {
2721 char *res;
2723 do {
2724 res = strsep(stringp, delim);
2725 if (res == NULL)
2726 break;
2727 } while (*res == '\0');
2728 return (res);
2732 * Find the zone specified in the control channel command 'args',
2733 * if any. If a zone is specified, point '*zonep' at it, otherwise
2734 * set '*zonep' to NULL.
2736 static isc_result_t
2737 zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) {
2738 char *input, *ptr;
2739 const char *zonetxt;
2740 char *classtxt;
2741 const char *viewtxt = NULL;
2742 dns_fixedname_t name;
2743 isc_result_t result;
2744 isc_buffer_t buf;
2745 dns_view_t *view = NULL;
2746 dns_rdataclass_t rdclass;
2748 REQUIRE(zonep != NULL && *zonep == NULL);
2750 input = args;
2752 /* Skip the command name. */
2753 ptr = next_token(&input, " \t");
2754 if (ptr == NULL)
2755 return (ISC_R_UNEXPECTEDEND);
2757 /* Look for the zone name. */
2758 zonetxt = next_token(&input, " \t");
2759 if (zonetxt == NULL)
2760 return (ISC_R_SUCCESS);
2762 /* Look for the optional class name. */
2763 classtxt = next_token(&input, " \t");
2764 if (classtxt != NULL) {
2765 /* Look for the optional view name. */
2766 viewtxt = next_token(&input, " \t");
2769 isc_buffer_init(&buf, zonetxt, strlen(zonetxt));
2770 isc_buffer_add(&buf, strlen(zonetxt));
2771 dns_fixedname_init(&name);
2772 result = dns_name_fromtext(dns_fixedname_name(&name),
2773 &buf, dns_rootname, ISC_FALSE, NULL);
2774 if (result != ISC_R_SUCCESS)
2775 goto fail1;
2777 if (classtxt != NULL) {
2778 isc_textregion_t r;
2779 r.base = classtxt;
2780 r.length = strlen(classtxt);
2781 result = dns_rdataclass_fromtext(&rdclass, &r);
2782 if (result != ISC_R_SUCCESS)
2783 goto fail1;
2784 } else {
2785 rdclass = dns_rdataclass_in;
2788 if (viewtxt == NULL)
2789 viewtxt = "_default";
2790 result = dns_viewlist_find(&server->viewlist, viewtxt,
2791 rdclass, &view);
2792 if (result != ISC_R_SUCCESS)
2793 goto fail1;
2795 result = dns_zt_find(view->zonetable, dns_fixedname_name(&name),
2796 0, NULL, zonep);
2797 /* Partial match? */
2798 if (result != ISC_R_SUCCESS && *zonep != NULL)
2799 dns_zone_detach(zonep);
2800 dns_view_detach(&view);
2801 fail1:
2802 return (result);
2806 * Act on a "reload" command from the command channel.
2808 isc_result_t
2809 ns_server_reloadcommand(ns_server_t *server, char *args) {
2810 isc_result_t result;
2811 dns_zone_t *zone = NULL;
2812 dns_zonetype_t type;
2814 result = zone_from_args(server, args, &zone);
2815 if (result != ISC_R_SUCCESS)
2816 return (result);
2817 if (zone == NULL) {
2818 reload(server);
2819 } else {
2820 type = dns_zone_gettype(zone);
2821 if (type == dns_zone_slave || type == dns_zone_stub)
2822 dns_zone_refresh(zone);
2823 else
2824 dns_zone_load(zone);
2825 dns_zone_detach(&zone);
2827 return (ISC_R_SUCCESS);
2831 * Act on a "reconfig" command from the command channel.
2833 isc_result_t
2834 ns_server_reconfigcommand(ns_server_t *server, char *args) {
2835 UNUSED(args);
2837 reconfig(server);
2838 return (ISC_R_SUCCESS);
2842 * Act on a "refresh" command from the command channel.
2844 isc_result_t
2845 ns_server_refreshcommand(ns_server_t *server, char *args) {
2846 isc_result_t result;
2847 dns_zone_t *zone = NULL;
2849 result = zone_from_args(server, args, &zone);
2850 if (result != ISC_R_SUCCESS)
2851 return (result);
2852 if (zone == NULL)
2853 return (ISC_R_UNEXPECTEDEND);
2855 dns_zone_refresh(zone);
2856 dns_zone_detach(&zone);
2858 return (ISC_R_SUCCESS);
2861 isc_result_t
2862 ns_server_togglequerylog(ns_server_t *server) {
2863 server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE;
2865 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2866 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
2867 "query logging is now %s",
2868 server->log_queries ? "on" : "off");
2869 return (ISC_R_SUCCESS);
2872 static isc_result_t
2873 ns_listenlist_fromconfig(cfg_obj_t *listenlist, cfg_obj_t *config,
2874 ns_aclconfctx_t *actx,
2875 isc_mem_t *mctx, ns_listenlist_t **target)
2877 isc_result_t result;
2878 cfg_listelt_t *element;
2879 ns_listenlist_t *dlist = NULL;
2881 REQUIRE(target != NULL && *target == NULL);
2883 result = ns_listenlist_create(mctx, &dlist);
2884 if (result != ISC_R_SUCCESS)
2885 return (result);
2887 for (element = cfg_list_first(listenlist);
2888 element != NULL;
2889 element = cfg_list_next(element))
2891 ns_listenelt_t *delt = NULL;
2892 cfg_obj_t *listener = cfg_listelt_value(element);
2893 result = ns_listenelt_fromconfig(listener, config, actx,
2894 mctx, &delt);
2895 if (result != ISC_R_SUCCESS)
2896 goto cleanup;
2897 ISC_LIST_APPEND(dlist->elts, delt, link);
2899 *target = dlist;
2900 return (ISC_R_SUCCESS);
2902 cleanup:
2903 ns_listenlist_detach(&dlist);
2904 return (result);
2908 * Create a listen list from the corresponding configuration
2909 * data structure.
2911 static isc_result_t
2912 ns_listenelt_fromconfig(cfg_obj_t *listener, cfg_obj_t *config,
2913 ns_aclconfctx_t *actx,
2914 isc_mem_t *mctx, ns_listenelt_t **target)
2916 isc_result_t result;
2917 cfg_obj_t *portobj;
2918 in_port_t port;
2919 ns_listenelt_t *delt = NULL;
2920 REQUIRE(target != NULL && *target == NULL);
2922 portobj = cfg_tuple_get(listener, "port");
2923 if (!cfg_obj_isuint32(portobj)) {
2924 if (ns_g_port != 0) {
2925 port = ns_g_port;
2926 } else {
2927 result = ns_config_getport(config, &port);
2928 if (result != ISC_R_SUCCESS)
2929 return (result);
2931 } else {
2932 if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
2933 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
2934 "port value '%u' is out of range",
2935 cfg_obj_asuint32(portobj));
2936 return (ISC_R_RANGE);
2938 port = (in_port_t)cfg_obj_asuint32(portobj);
2941 result = ns_listenelt_create(mctx, port, NULL, &delt);
2942 if (result != ISC_R_SUCCESS)
2943 return (result);
2945 result = ns_acl_fromconfig(cfg_tuple_get(listener, "acl"),
2946 config, actx, mctx, &delt->acl);
2947 if (result != ISC_R_SUCCESS) {
2948 ns_listenelt_destroy(delt);
2949 return (result);
2951 *target = delt;
2952 return (ISC_R_SUCCESS);
2955 isc_result_t
2956 ns_server_dumpstats(ns_server_t *server) {
2957 isc_result_t result;
2958 dns_zone_t *zone, *next;
2959 isc_stdtime_t now;
2960 FILE *fp = NULL;
2961 int i;
2962 int ncounters;
2964 isc_stdtime_get(&now);
2966 CHECKM(isc_stdio_open(server->statsfile, "a", &fp),
2967 "could not open statistics dump file");
2969 ncounters = DNS_STATS_NCOUNTERS;
2970 fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);
2972 for (i = 0; i < ncounters; i++)
2973 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT "u\n",
2974 dns_statscounter_names[i],
2975 server->querystats[i]);
2977 zone = NULL;
2978 for (result = dns_zone_first(server->zonemgr, &zone);
2979 result == ISC_R_SUCCESS;
2980 next = NULL, result = dns_zone_next(zone, &next), zone = next)
2982 isc_uint64_t *zonestats = dns_zone_getstatscounters(zone);
2983 if (zonestats != NULL) {
2984 char zonename[DNS_NAME_FORMATSIZE];
2985 dns_view_t *view;
2986 char *viewname;
2988 dns_name_format(dns_zone_getorigin(zone),
2989 zonename, sizeof(zonename));
2990 view = dns_zone_getview(zone);
2991 viewname = view->name;
2992 for (i = 0; i < ncounters; i++) {
2993 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT
2994 "u %s",
2995 dns_statscounter_names[i],
2996 zonestats[i],
2997 zonename);
2998 if (strcmp(viewname, "_default") != 0)
2999 fprintf(fp, " %s", viewname);
3000 fprintf(fp, "\n");
3004 if (result == ISC_R_NOMORE)
3005 result = ISC_R_SUCCESS;
3006 CHECK(result);
3008 fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);
3010 cleanup:
3011 if (fp != NULL)
3012 (void)isc_stdio_close(fp);
3013 return (result);
3016 isc_result_t
3017 ns_server_dumpdb(ns_server_t *server) {
3018 FILE *fp = NULL;
3019 dns_view_t *view;
3020 isc_result_t result;
3022 CHECKM(isc_stdio_open(server->dumpfile, "w", &fp),
3023 "could not open dump file");
3025 for (view = ISC_LIST_HEAD(server->viewlist);
3026 view != NULL;
3027 view = ISC_LIST_NEXT(view, link))
3029 if (view->cachedb != NULL)
3030 CHECKM(dns_view_dumpdbtostream(view, fp),
3031 "could not dump view databases");
3033 cleanup:
3034 if (fp != NULL)
3035 (void)isc_stdio_close(fp);
3036 return (result);
3039 isc_result_t
3040 ns_server_setdebuglevel(ns_server_t *server, char *args) {
3041 char *ptr;
3042 char *levelstr;
3043 char *endp;
3044 long newlevel;
3046 UNUSED(server);
3048 /* Skip the command name. */
3049 ptr = next_token(&args, " \t");
3050 if (ptr == NULL)
3051 return (ISC_R_UNEXPECTEDEND);
3053 /* Look for the new level name. */
3054 levelstr = next_token(&args, " \t");
3055 if (levelstr == NULL) {
3056 if (ns_g_debuglevel < 99)
3057 ns_g_debuglevel++;
3058 } else {
3059 newlevel = strtol(levelstr, &endp, 10);
3060 if (*endp != '\0' || newlevel < 0 || newlevel > 99)
3061 return (ISC_R_RANGE);
3062 ns_g_debuglevel = (unsigned int)newlevel;
3064 isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
3065 return (ISC_R_SUCCESS);
3068 isc_result_t
3069 ns_server_flushcache(ns_server_t *server, char *args) {
3070 char *ptr, *viewname;
3071 dns_view_t *view;
3072 isc_boolean_t flushed = ISC_FALSE;
3073 isc_result_t result;
3075 /* Skip the command name. */
3076 ptr = next_token(&args, " \t");
3077 if (ptr == NULL)
3078 return (ISC_R_UNEXPECTEDEND);
3080 /* Look for the view name. */
3081 viewname = next_token(&args, " \t");
3083 result = isc_task_beginexclusive(server->task);
3084 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3085 for (view = ISC_LIST_HEAD(server->viewlist);
3086 view != NULL;
3087 view = ISC_LIST_NEXT(view, link))
3089 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
3090 continue;
3091 result = dns_view_flushcache(view);
3092 if (result != ISC_R_SUCCESS)
3093 goto out;
3094 flushed = ISC_TRUE;
3096 if (flushed)
3097 result = ISC_R_SUCCESS;
3098 else
3099 result = ISC_R_FAILURE;
3100 out:
3101 isc_task_endexclusive(server->task);
3102 return (result);
3105 isc_result_t
3106 ns_server_status(ns_server_t *server, isc_buffer_t *text) {
3107 int zonecount, xferrunning, xferdeferred, soaqueries;
3108 unsigned int n;
3110 zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
3111 xferrunning = dns_zonemgr_getcount(server->zonemgr,
3112 DNS_ZONESTATE_XFERRUNNING);
3113 xferdeferred = dns_zonemgr_getcount(server->zonemgr,
3114 DNS_ZONESTATE_XFERDEFERRED);
3115 soaqueries = dns_zonemgr_getcount(server->zonemgr,
3116 DNS_ZONESTATE_SOAQUERY);
3117 n = snprintf((char *)isc_buffer_used(text),
3118 isc_buffer_availablelength(text),
3119 "number of zones: %u\n"
3120 "debug level: %d\n"
3121 "xfers running: %u\n"
3122 "xfers deferred: %u\n"
3123 "soa queries in progress: %u\n"
3124 "query logging is %s\n"
3125 "server is up and running",
3126 zonecount, ns_g_debuglevel, xferrunning, xferdeferred,
3127 soaqueries, server->log_queries ? "ON" : "OFF");
3128 if (n >= isc_buffer_availablelength(text))
3129 return (ISC_R_NOSPACE);
3130 isc_buffer_add(text, n);
3131 return (ISC_R_SUCCESS);