Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / contrib / bind-9.2.4rc7 / bin / named / server.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: server.c,v 1.339.2.29 2004/05/14 01:04:46 marka Exp $ */
19
20 #include <config.h>
21
22 #include <stdlib.h>
23
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>
38
39 #include <isccfg/cfg.h>
40 #include <isccfg/check.h>
41
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>
59
60 #include <dst/dst.h>
61 #include <dst/result.h>
62
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>
75
76 /*
77  * Check an operation for failure.  Assumes that the function
78  * using it has a 'result' variable and a 'cleanup' label.
79  */
80 #define CHECK(op) \
81         do { result = (op);                                      \
82                if (result != ISC_R_SUCCESS) goto cleanup;        \
83         } while (0)
84
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)                                               \
97
98 #define CHECKFATAL(op, msg) \
99         do { result = (op);                                       \
100                if (result != ISC_R_SUCCESS)                       \
101                         fatal(msg, result);                       \
102         } while (0)                                               \
103
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;
109 };
110
111 static void
112 fatal(const char *msg, isc_result_t result);
113
114 static void
115 ns_server_reload(isc_task_t *task, isc_event_t *event);
116
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);
125
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);
129
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);
134
135 static void
136 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
137
138 /*
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).
142  */
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)
147 {
148         isc_result_t result;
149         cfg_obj_t *maps[3];
150         cfg_obj_t *aclobj = NULL;
151         int i = 0;
152
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;
162         }
163         maps[i] = NULL;
164
165         result = ns_config_get(maps, aclname, &aclobj);
166         if (aclobj == NULL)
167                 /*
168                  * No value available.  *aclp == NULL.
169                  */
170                 return (ISC_R_SUCCESS);
171
172         result = ns_acl_fromconfig(aclobj, config, actx, mctx, aclp);
173
174         return (result);
175 }
176
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)
181 {
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;
196
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"));
202
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));
209         }
210         keystruct.common.rdclass = viewclass;
211         keystruct.common.rdtype = dns_rdatatype_key;
212         /*
213          * The key data in keystruct is not dynamically allocated.
214          */
215         keystruct.mctx = NULL;
216
217         ISC_LINK_INIT(&keystruct.common, link);
218
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;
228
229         isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
230         isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
231
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;
237
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));
250
251         CHECK(dns_keytable_add(keytable, &dstkey));
252         INSIST(dstkey == NULL);
253         return (ISC_R_SUCCESS);
254
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;
266         }
267
268         if (dstkey != NULL)
269                 dst_key_free(&dstkey);
270
271         return (result);
272 }
273 #endif
274
275 /*
276  * Configure DNSSEC keys for a view.  Currently used only for
277  * the security roots.
278  *
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'.
281  */
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)
285 {
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;
295
296         CHECK(dns_keytable_create(mctx, &keytable));
297
298 #ifndef ISC_RFC2535
299         UNUSED(vconfig);
300         UNUSED(config);
301 #else
302         if (vconfig != NULL)
303                 voptions = cfg_tuple_get(vconfig, "options");
304
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);
310
311         for (element = cfg_list_first(keys);
312              element != NULL;
313              element = cfg_list_next(element))
314         {
315                 keylist = cfg_listelt_value(element);
316                 for (element2 = cfg_list_first(keylist);
317                      element2 != NULL;
318                      element2 = cfg_list_next(element2))
319                 {
320                         key = cfg_listelt_value(element2);
321                         CHECK(configure_view_dnsseckey(vconfig, key,
322                                                        keytable, mctx));
323                 }
324         }
325 #endif
326         dns_keytable_detach(target);
327         *target = keytable; /* Transfer ownership. */
328         keytable = NULL;
329         result = ISC_R_SUCCESS;
330         
331  cleanup:
332         return (result);
333 }
334
335
336 /*
337  * Get a dispatch appropriate for the resolver of a given view.
338  */
339 static isc_result_t
340 get_view_querysource_dispatch(cfg_obj_t **maps,
341                               int af, dns_dispatch_t **dispatchp)
342 {
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;
348
349         /*
350          * Make compiler happy.
351          */
352         result = ISC_R_FAILURE;
353
354         switch (af) {
355         case AF_INET:
356                 result = ns_config_get(maps, "query-source", &obj);
357                 INSIST(result == ISC_R_SUCCESS);
358
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);
366         }
367
368         sa = *(cfg_obj_assockaddr(obj));
369         INSIST(isc_sockaddr_pf(&sa) == af);
370
371         /*
372          * If we don't support this address family, we're done!
373          */
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);
383         }
384         if (result != ISC_R_SUCCESS)
385                 return (ISC_R_SUCCESS);
386
387         /*
388          * Try to find a dispatcher that we can share.
389          */
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;
399         }
400         attrmask = 0;
401         attrmask |= DNS_DISPATCHATTR_UDP;
402         attrmask |= DNS_DISPATCHATTR_TCP;
403         attrmask |= DNS_DISPATCHATTR_IPV4;
404         attrmask |= DNS_DISPATCHATTR_IPV6;
405
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];
414
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;
422                 }
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);
431         }
432
433         *dispatchp = disp;
434
435         return (ISC_R_SUCCESS);
436 }
437
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;
446
447         sa = cfg_obj_assockaddr(cfg_map_getname(cpeer));
448         isc_netaddr_fromsockaddr(&na, sa);
449
450         peer = NULL;
451         result = dns_peer_new(mctx, &na, &peer);
452         if (result != ISC_R_SUCCESS)
453                 return (result);
454
455         obj = NULL;
456         (void)cfg_map_get(cpeer, "bogus", &obj);
457         if (obj != NULL)
458                 dns_peer_setbogus(peer, cfg_obj_asboolean(obj));
459
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));
464
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));
469
470         obj = NULL;
471         (void)cfg_map_get(cpeer, "edns", &obj);
472         if (obj != NULL)
473                 dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj));
474
475         obj = NULL;
476         (void)cfg_map_get(cpeer, "transfers", &obj);
477         if (obj != NULL)
478                 dns_peer_settransfers(peer, cfg_obj_asuint32(obj));
479
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);
490         }
491
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;
498         }
499         *peerp = peer;
500         return (ISC_R_SUCCESS);
501
502  cleanup:
503         dns_peer_detach(&peer);
504         return (result);
505 }
506
507 /*
508  * Configure 'view' according to 'vconfig', taking defaults from 'config'
509  * where values are missing in 'vconfig'.
510  *
511  * When configuring the default view, 'vconfig' will be NULL and the
512  * global defaults in 'config' used exclusively.
513  */
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)
517 {
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;
540
541         REQUIRE(DNS_VIEW_VALID(view));
542
543         cmctx = NULL;
544
545         if (config != NULL)
546                 cfg_map_get(config, "options", &options);
547
548         i = 0;
549         if (vconfig != NULL) {
550                 voptions = cfg_tuple_get(vconfig, "options");
551                 maps[i++] = voptions;
552         }
553         if (options != NULL)
554                 maps[i++] = options;
555         maps[i++] = ns_g_defaults;
556         maps[i] = NULL;
557
558         i = 0;
559         if (voptions != NULL)
560                 cfgmaps[i++] = voptions;
561         if (config != NULL)
562                 cfgmaps[i++] = config;
563         cfgmaps[i] = NULL;
564
565
566         /*
567          * Set the view's port number for outgoing queries.
568          */
569         CHECKM(ns_config_getport(config, &port), "port");
570         dns_view_setdstport(view, port);
571
572         /*
573          * Configure the zones.
574          */
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))
583         {
584                 cfg_obj_t *zconfig = cfg_listelt_value(element);
585                 CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
586                                      actx));
587         }
588
589         /*
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.
593          *
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.
601          */
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));
619         }
620         dns_view_setcache(view, cache);
621
622         /*
623          * cache-file cannot be inherited if views are present, but this
624          * should be caught by the configuration checking stage.
625          */
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));
632         }
633
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);
638
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;
656                 }
657                 max_cache_size = (isc_uint32_t)value;
658         }
659         dns_cache_setcachesize(cache, max_cache_size);
660
661         dns_cache_detach(&cache);
662
663         /*
664          * Resolver.
665          *
666          * XXXRTH  Hardwired number of tasks.
667          */
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;
676         }
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));
681
682         /*
683          * Set resolver's lame-ttl.
684          */
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);
692         
693         /*
694          * A global or view "forwarders" option, if present,
695          * creates an entry for "." in the forwarding table.
696          */
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));
704
705         /*
706          * We have default hints for class IN if we need them.
707          */
708         if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
709                 dns_view_sethints(view, ns_g_server->in_roothints);
710
711         /*
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.
717          */
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);
728                 }
729         }
730
731         /*
732          * Configure the view's TSIG keys.
733          */
734         ring = NULL;
735         CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
736         dns_view_setkeyring(view, ring);
737
738         /*
739          * Configure the view's peer list.
740          */
741         {
742                 cfg_obj_t *peers = NULL;
743                 cfg_listelt_t *element;
744                 dns_peerlist_t *newpeers = NULL;
745
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))
751                 {
752                         cfg_obj_t *cpeer = cfg_listelt_value(element);
753                         dns_peer_t *peer;
754
755                         CHECK(configure_peer(cpeer, mctx, &peer));
756                         dns_peerlist_addpeer(newpeers, peer);
757                         dns_peer_detach(&peer);
758                 }
759                 dns_peerlist_detach(&view->peers);
760                 view->peers = newpeers; /* Transfer ownership. */
761         }
762
763         /*
764          * Copy the aclenv object.
765          */
766         dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv);
767
768         /*
769          * Configure the "match-clients" and "match-destinations" ACL.
770          */
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));
775
776         /*
777          * Configure the "match-recursive-only" option.
778          */
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;
785
786         /*
787          * Configure other configurable data.
788          */
789         obj = NULL;
790         result = ns_config_get(maps, "recursion", &obj);
791         INSIST(result == ISC_R_SUCCESS);
792         view->recursion = cfg_obj_asboolean(obj);
793
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);
798
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);
803
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);
814         
815         /*
816          * Set sources where additional data and CNAME/DNAME
817          * targets for authoritative answers may be found.
818          */
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;
828         }
829
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;
839         }
840
841         CHECK(configure_view_acl(vconfig, config, "allow-query",
842                                  actx, ns_g_mctx, &view->queryacl));
843
844         if (strcmp(view->name, "_bind") != 0)
845                 CHECK(configure_view_acl(vconfig, config, "allow-recursion",
846                                          actx, ns_g_mctx, &view->recursionacl));
847
848         CHECK(configure_view_acl(vconfig, config, "allow-v6-synthesis",
849                                  actx, ns_g_mctx, &view->v6synthesisacl));
850
851         /*
852          * Warning if both "recursion no;" and allow-recursion are active
853          * except for "allow-recursion { none; };".
854          */
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;
861
862                 if (!strcmp(view->name, "_bind") ||
863                     !strcmp(view->name, "_default")) {
864                         forview = "";
865                         viewname = "";
866                 }
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);
871         }
872
873         CHECK(configure_view_acl(vconfig, config, "sortlist",
874                                  actx, ns_g_mctx, &view->sortlist));
875
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);
880
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);
885
886         /*
887          * For now, there is only one kind of trusted keys, the
888          * "security roots".
889          */
890         CHECK(configure_view_dnsseckeys(vconfig, config, mctx,
891                                   &view->secroots));
892
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);
897
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;
904
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;
915
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));
929                         }
930                 }
931         } else
932                 dns_view_setrootdelonly(view, ISC_FALSE);
933
934         result = ISC_R_SUCCESS;
935
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);
943
944         if (cache != NULL)
945                 dns_cache_detach(&cache);
946
947         return (result);
948 }
949
950 /*
951  * Create the special view that handles queries under "bind. CH".
952  */
953 static isc_result_t
954 create_bind_view(dns_view_t **viewp) {
955         isc_result_t result;
956         dns_view_t *view = NULL;
957
958         REQUIRE(viewp != NULL && *viewp == NULL);
959
960         CHECK(dns_view_create(ns_g_mctx, dns_rdataclass_ch, "_bind", &view));
961
962         /* Transfer ownership. */
963         *viewp = view;
964         view = NULL;
965
966         result = ISC_R_SUCCESS;
967
968  cleanup:
969         if (view != NULL)
970                 dns_view_detach(&view);
971
972         return (result);
973 }
974
975 /*
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.
979  */
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;
997
998         dns_diff_init(ns_g_mctx, &diff);
999
1000         dns_name_init(&origin, NULL);
1001         r.base = origindata;
1002         r.length = sizeof(origindata);
1003         dns_name_fromregion(&origin, &r);
1004
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);
1013
1014         r.base = buf;
1015         r.length = 1 + len;
1016         dns_rdata_fromregion(&rdata, dns_rdataclass_ch, dns_rdatatype_txt, &r);
1017
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);
1027
1028         CHECK(dns_zonemgr_managezone(zmgr, zone));
1029
1030         CHECK(dns_db_create(ns_g_mctx, "rbt", &origin, dns_dbtype_zone,
1031                             dns_rdataclass_ch, 0, NULL, &db));
1032
1033         CHECK(dns_db_newversion(db, &dbver));
1034
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));
1039
1040         dns_db_closeversion(db, &dbver, ISC_TRUE);
1041
1042         CHECK(dns_zone_replacedb(zone, db, ISC_FALSE));
1043
1044         CHECK(dns_view_addzone(view, zone));
1045                         
1046         result = ISC_R_SUCCESS;
1047
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);
1056
1057         return (result);
1058 }
1059
1060 /*
1061  * Create the special zone that handles queries for "authors.bind. CH".
1062  * The strings returned list the BIND 9 authors.
1063  */
1064 static isc_result_t
1065 create_authors_zone(cfg_obj_t *options, dns_zonemgr_t *zmgr, dns_view_t *view)
1066 {
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,
1093         };
1094         cfg_obj_t *obj = NULL;
1095         dns_acl_t *acl = NULL;
1096
1097         /*
1098          * If a version string is specified, disable the authors.bind zone.
1099          */
1100         if (options != NULL &&
1101             cfg_map_get(options, "version", &obj) == ISC_R_SUCCESS)
1102                 return (ISC_R_SUCCESS);
1103
1104         dns_diff_init(ns_g_mctx, &diff);
1105
1106         dns_name_init(&origin, NULL);
1107         DE_CONST(origindata, r.base);
1108         r.length = sizeof(origindata);
1109         dns_name_fromregion(&origin, &r);
1110
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);
1120
1121         CHECK(dns_zonemgr_managezone(zmgr, zone));
1122
1123         CHECK(dns_db_create(ns_g_mctx, "rbt", &origin, dns_dbtype_zone,
1124                             dns_rdataclass_ch, 0, NULL, &db));
1125
1126         CHECK(dns_db_newversion(db, &dbver));
1127
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);
1139         }
1140
1141         CHECK(dns_diff_apply(&diff, db, dbver));
1142
1143         dns_db_closeversion(db, &dbver, ISC_TRUE);
1144
1145         CHECK(dns_zone_replacedb(zone, db, ISC_FALSE));
1146
1147         CHECK(dns_view_addzone(view, zone));
1148
1149         result = ISC_R_SUCCESS;
1150
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);
1159
1160         return (result);
1161 }
1162
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;
1167
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);
1173         }
1174
1175         return (result);
1176 }
1177
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)
1181 {
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;
1190
1191         /*
1192          * Determine which port to send forwarded requests to.
1193          */
1194         if (ns_g_lwresdonly && ns_g_port != 0)
1195                 port = ns_g_port;
1196         else
1197                 CHECKM(ns_config_getport(config, &port), "port");
1198
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);
1207                         }
1208                         port = (in_port_t) val;
1209                 }
1210         }
1211
1212         faddresses = NULL;
1213         if (forwarders != NULL)
1214                 faddresses = cfg_tuple_get(forwarders, "addresses");
1215
1216         ISC_LIST_INIT(addresses);
1217
1218         for (element = cfg_list_first(faddresses);
1219              element != NULL;
1220              element = cfg_list_next(element))
1221         {
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;
1227                 }
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);
1233         }
1234
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);
1252                 }
1253         }
1254
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;
1264         }
1265
1266         result = ISC_R_SUCCESS;
1267
1268  cleanup:
1269
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));
1274         }
1275
1276         return (result);
1277 }
1278
1279 /*
1280  * Create a new view and add it to the list.
1281  *
1282  * If 'vconfig' is NULL, create the default view.
1283  *
1284  * The view created is attached to '*viewp'.
1285  */
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;
1292
1293         if (vconfig != NULL) {
1294                 cfg_obj_t *classobj = NULL;
1295
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;
1303         }
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);
1310
1311         result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
1312         if (result != ISC_R_SUCCESS)
1313                 return (result);
1314
1315         ISC_LIST_APPEND(*viewlist, view, link);
1316         dns_view_attach(view, viewp);
1317         return (ISC_R_SUCCESS);
1318 }
1319
1320 /*
1321  * Configure or reconfigure a zone.
1322  */
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)
1327 {
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;
1345
1346         options = NULL;
1347         (void)cfg_map_get(config, "options", &options);
1348
1349         zoptions = cfg_tuple_get(zconfig, "options");
1350
1351         /*
1352          * Get the zone origin as a dns_name_t.
1353          */
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);
1361
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>";
1371         
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;
1378         }
1379
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);
1385         }
1386         ztypestr = cfg_obj_asstring(typeobj);
1387
1388         /*
1389          * "hints zones" aren't zones.  If we've got one,
1390          * configure it and return.
1391          */
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;
1401                 }
1402                 if (dns_name_equal(origin, dns_rootname)) {
1403                         char *hintsfile = cfg_obj_asstring(fileobj);
1404
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;
1414                         }
1415                         /*
1416                          * Hint zones may also refer to delegation only points.
1417                          */
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;
1429                 }
1430                 /* Skip ordinary zone processing. */
1431                 goto cleanup;
1432         }
1433
1434         /*
1435          * "forward zones" aren't zones either.  Translate this syntax into
1436          * the appropriate selective forwarding configuration and return.
1437          */
1438         if (strcasecmp(ztypestr, "forward") == 0) {
1439                 forwardtype = NULL;
1440                 forwarders = NULL;
1441
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;
1447         }
1448
1449         /*
1450          * "delegation-only zones" aren't zones either.
1451          */
1452         if (strcasecmp(ztypestr, "delegation-only") == 0) {
1453                 result = dns_view_adddelegationonly(view, origin);
1454                 goto cleanup;
1455         }
1456
1457         /*
1458          * Check for duplicates in the new zone table.
1459          */
1460         result = dns_view_findzone(view, origin, &dupzone);
1461         if (result == ISC_R_SUCCESS) {
1462                 /*
1463                  * We already have this zone!
1464                  */
1465                 dns_zone_detach(&dupzone);
1466                 result = ISC_R_EXISTS;
1467                 goto cleanup;
1468         }
1469         INSIST(dupzone == NULL);
1470
1471         /*
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)
1479          */
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);
1492         }
1493
1494         if (zone != NULL) {
1495                 /*
1496                  * We found a reusable zone.  Make it use the
1497                  * new view.
1498                  */
1499                 dns_zone_setview(zone, view);
1500         } else {
1501                 /*
1502                  * We cannot reuse an existing zone, we have
1503                  * to create a new one.
1504                  */
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));
1509         }
1510
1511         /*
1512          * If the zone contains a 'forwarders' statement, configure
1513          * selective forwarding.
1514          */
1515         forwarders = NULL;
1516         if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
1517         {
1518                 forwardtype = NULL;
1519                 cfg_map_get(zoptions, "forward", &forwardtype);
1520                 CHECK(configure_forward(config, view, origin, forwarders,
1521                                         forwardtype));
1522         }
1523
1524         /*
1525          * Stub and forward zones may also refer to delegation only points.
1526          */
1527         only = NULL;
1528         if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
1529         {
1530                 if (cfg_obj_asboolean(only))
1531                         CHECK(dns_view_adddelegationonly(view, origin));
1532         }
1533
1534         /*
1535          * Configure the zone.
1536          */
1537         CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone));
1538
1539         /*
1540          * Add the zone to its view in the new view list.
1541          */
1542         CHECK(dns_view_addzone(view, zone));
1543
1544  cleanup:
1545         if (zone != NULL)
1546                 dns_zone_detach(&zone);
1547         if (pview != NULL)
1548                 dns_view_detach(&pview);
1549
1550         return (result);
1551 }
1552
1553 /*
1554  * Configure a single server quota.
1555  */
1556 static void
1557 configure_server_quota(cfg_obj_t **maps, const char *name, isc_quota_t *quota)
1558 {
1559         cfg_obj_t *obj = NULL;
1560         isc_result_t result;
1561
1562         result = ns_config_get(maps, name, &obj);
1563         INSIST(result == ISC_R_SUCCESS);
1564         quota->max = cfg_obj_asuint32(obj);
1565 }
1566
1567 /*
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.
1570  */
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;
1575
1576         REQUIRE(strcasecmp("directory", clausename) == 0);
1577
1578         UNUSED(arg);
1579         UNUSED(clausename);
1580
1581         /*
1582          * Change directory.
1583          */
1584         directory = cfg_obj_asstring(obj);
1585
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);
1590
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);
1597         }
1598
1599         return (ISC_R_SUCCESS);
1600 }
1601
1602 static void
1603 scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
1604         isc_boolean_t match_mapped = server->aclenv.match_mapped;
1605
1606         ns_interfacemgr_scan(server->interfacemgr, verbose);
1607         /*
1608          * Update the "localhost" and "localnets" ACLs to match the
1609          * current set of network interfaces.
1610          */
1611         dns_aclenv_copy(&server->aclenv,
1612                         ns_interfacemgr_getaclenv(server->interfacemgr));
1613
1614         server->aclenv.match_mapped = match_mapped;
1615 }
1616
1617 /*
1618  * This event callback is invoked to do periodic network
1619  * interface scanning.
1620  */
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);
1628         /*
1629          * XXX should scan interfaces unlocked and get exclusive access
1630          * only to replace ACLs.
1631          */
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);    
1636 }
1637
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;
1642
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);
1649         }
1650 }
1651
1652 static isc_result_t
1653 setstatsfile(ns_server_t *server, const char *name) {
1654         char *p;
1655
1656         REQUIRE(name != NULL);
1657
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);
1665 }
1666
1667 static isc_result_t
1668 setdumpfile(ns_server_t *server, const char *name) {
1669         char *p;
1670
1671         REQUIRE(name != NULL);
1672
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);
1680 }
1681
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)
1685 {
1686         cfg_obj_t *obj = NULL;
1687         char *resource;
1688         isc_resourcevalue_t value;
1689         isc_result_t result;
1690
1691         if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
1692                 return;
1693
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;
1701                 }
1702         } else
1703                 value = cfg_obj_asuint64(obj);
1704
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));
1711 }
1712
1713 #define SETLIMIT(cfgvar, resource, description) \
1714         set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
1715                   ns_g_init ## resource)
1716
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");
1723 }
1724
1725 static isc_result_t
1726 load_configuration(const char *filename, ns_server_t *server,
1727                    isc_boolean_t first_time)
1728 {
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;
1746
1747         ns_aclconfctx_init(&aclconfctx);
1748         ISC_LIST_INIT(viewlist);
1749
1750         /* Ensure exclusive access to configuration data. */
1751         result = isc_task_beginexclusive(server->task);
1752         RUNTIME_CHECK(result == ISC_R_SUCCESS); 
1753
1754         /*
1755          * Parse the global default pseudo-config file.
1756          */
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);
1762         }
1763
1764         /*
1765          * Parse the configuration file using the new config code.
1766          */
1767         result = ISC_R_FAILURE;
1768         config = NULL;
1769
1770         /*
1771          * Unless this is lwresd with the -C option, parse the config file.
1772          */
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);
1782         }
1783
1784         /*
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.
1787          */
1788         if (ns_g_lwresdonly &&
1789             (lwresd_g_useresolvconf ||
1790              (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
1791         {
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);
1801         }
1802         CHECK(result);
1803
1804         /*
1805          * Check the validity of the configuration.
1806          */
1807         CHECK(cfg_check_namedconf(config, ns_g_lctx, ns_g_mctx));
1808
1809         /*
1810          * Fill in the maps array, used for resolving defaults.
1811          */
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;
1819
1820         /*
1821          * Set process limits, which (usually) needs to be done as root.
1822          */
1823         set_limits(maps);
1824
1825         /*
1826          * Configure various server options.
1827          */
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);
1832
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);
1838
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);
1843
1844         /*
1845          * Configure the zone manager.
1846          */
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));
1851
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));
1856
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));
1861
1862         /*
1863          * Determine which port to use for listening for incoming connections.
1864          */
1865         if (ns_g_port != 0)
1866                 listen_port = ns_g_port;
1867         else
1868                 CHECKM(ns_config_getport(config, &listen_port), "port");
1869
1870         /*
1871          * Configure the interface manager according to the "listen-on"
1872          * statement.
1873          */
1874         {
1875                 cfg_obj_t *clistenon = NULL;
1876                 ns_listenlist_t *listenon = NULL;
1877
1878                 clistenon = NULL;
1879                 /*
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.
1883                  */
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) {
1893                         /*
1894                          * Not specified, use default.
1895                          */
1896                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
1897                                                     ISC_TRUE, &listenon));
1898                 }
1899                 if (listenon != NULL) {
1900                         ns_interfacemgr_setlistenon4(server->interfacemgr,
1901                                                      listenon);
1902                         ns_listenlist_detach(&listenon);
1903                 }
1904         }
1905         /*
1906          * Ditto for IPv6.
1907          */
1908         {
1909                 cfg_obj_t *clistenon = NULL;
1910                 ns_listenlist_t *listenon = NULL;
1911
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) {
1921                         /*
1922                          * Not specified, use default.
1923                          */
1924                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
1925                                                     ISC_FALSE, &listenon));
1926                 }
1927                 if (listenon != NULL) {
1928                         ns_interfacemgr_setlistenon6(server->interfacemgr,
1929                                                      listenon);
1930                         ns_listenlist_detach(&listenon);
1931                 }
1932         }
1933
1934         /*
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.
1939          */
1940         scan_interfaces(server, ISC_TRUE);
1941
1942         /*
1943          * Arrange for further interface scanning to occur periodically
1944          * as specified by the "interface-interval" option.
1945          */
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);
1959         }
1960         server->interface_interval = interface_interval;
1961
1962         /*
1963          * Configure the dialup heartbeat timer.
1964          */
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);
1978         }
1979         server->heartbeat_interval = heartbeat_interval;
1980
1981         /*
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.
1985          */
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))
1991         {
1992                 cfg_obj_t *vconfig;
1993
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);
2002         }
2003
2004         /*
2005          * Make sure we have a default view if and only if there
2006          * were no explicit views.
2007          */
2008         if (views == NULL) {
2009                 /*
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.
2014                  */
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);
2020         }
2021
2022         /*
2023          * Create (or recreate) the internal _bind view.
2024          */
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;
2033
2034         /*
2035          * Swap our new view list with the production one.
2036          */
2037         tmpviewlist = server->viewlist;
2038         server->viewlist = viewlist;
2039         viewlist = tmpviewlist;
2040
2041         /*
2042          * Load the TKEY information from the configuration.
2043          */
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;
2052         }
2053
2054         /*
2055          * Bind the control port(s).
2056          */
2057         CHECKM(ns_controls_configure(ns_g_server->controls, config,
2058                                      &aclconfctx),
2059                "binding control channel(s)");
2060
2061         /*
2062          * Bind the lwresd port(s).
2063          */
2064         CHECKM(ns_lwresd_configure(ns_g_mctx, config),
2065                "binding lightweight resolver ports");
2066
2067         /*
2068          * Open the source of entropy.
2069          */
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));
2090                 }
2091         }
2092
2093         /*
2094          * Relinquish root privileges.
2095          */
2096         if (first_time)
2097                 ns_os_changeuser();
2098
2099         /*
2100          * Configure the logging system.
2101          *
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.
2105          */
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;
2114
2115                 CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
2116                        "creating new logging configuration");
2117
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'");
2130                 }
2131
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");
2136                 }
2137
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");
2142         }
2143
2144         /*
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.
2149          */
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))
2161                         {
2162                                 cfg_obj_t *catobj;
2163                                 char *str;
2164
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;
2170                         }
2171                 }
2172         }
2173
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);
2181
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");
2186
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");
2191
2192  cleanup:
2193         ns_aclconfctx_destroy(&aclconfctx);
2194
2195         if (parser != NULL) {
2196                 if (config != NULL)
2197                         cfg_obj_destroy(parser, &config);
2198                 cfg_parser_destroy(&parser);
2199         }
2200
2201         if (view != NULL)
2202                 dns_view_detach(&view);
2203
2204         /*
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.
2208          */
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);
2215
2216         }
2217
2218         /* Relinquish exclusive access to configuration data. */
2219         isc_task_endexclusive(server->task);
2220
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));
2224
2225         return (result);
2226 }
2227
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;
2232
2233         result = isc_task_beginexclusive(server->task);
2234         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2235
2236         /*
2237          * Load zone data from disk.
2238          */
2239         for (view = ISC_LIST_HEAD(server->viewlist);
2240              view != NULL;
2241              view = ISC_LIST_NEXT(view, link))
2242         {
2243                 CHECK(dns_view_load(view, stop));
2244         }
2245
2246         /*
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.
2250          */
2251         CHECK(dns_zonemgr_forcemaint(server->zonemgr));
2252  cleanup:
2253         isc_task_endexclusive(server->task);    
2254         return (result);
2255 }
2256
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;
2261
2262         result = isc_task_beginexclusive(server->task);
2263         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2264
2265         /*
2266          * Load zone data from disk.
2267          */
2268         for (view = ISC_LIST_HEAD(server->viewlist);
2269              view != NULL;
2270              view = ISC_LIST_NEXT(view, link))
2271         {
2272                 CHECK(dns_view_loadnew(view, stop));
2273         }
2274         /*
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.
2278          */
2279         CHECK(dns_zonemgr_forcemaint(server->zonemgr));
2280  cleanup:
2281         isc_task_endexclusive(server->task);    
2282         return (result);
2283 }
2284
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;
2289
2290         UNUSED(task);
2291
2292         isc_event_free(&event);
2293
2294         CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
2295                                           &ns_g_dispatchmgr),
2296                    "creating dispatch manager");
2297
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");
2302
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");
2308
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");
2314
2315         CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
2316                    "creating default configuration parser");
2317
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");
2325
2326         isc_hash_init();
2327
2328         CHECKFATAL(load_zones(server, ISC_FALSE),
2329                    "loading zones");
2330
2331         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2332                       ISC_LOG_INFO, "running");
2333 }
2334
2335 void 
2336 ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
2337
2338         REQUIRE(NS_SERVER_VALID(server));
2339
2340         server->flushonshutdown = flush;
2341 }
2342
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;
2349
2350         UNUSED(task);
2351         INSIST(task == server->task);
2352
2353         result = isc_task_beginexclusive(server->task);
2354         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2355
2356         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2357                       ISC_LOG_INFO, "shutting down%s",
2358                       flush ? ": flushing changes" : "");
2359
2360         ns_controls_shutdown(server->controls);
2361         end_reserved_dispatches(server, ISC_TRUE);
2362
2363         cfg_obj_destroy(ns_g_parser, &ns_g_config);
2364         cfg_parser_destroy(&ns_g_parser);
2365
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);
2375         }
2376
2377         isc_timer_detach(&server->interface_timer);
2378         isc_timer_detach(&server->heartbeat_timer);
2379
2380         ns_interfacemgr_shutdown(server->interfacemgr);
2381         ns_interfacemgr_detach(&server->interfacemgr);
2382
2383         dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
2384
2385         dns_zonemgr_shutdown(server->zonemgr);
2386
2387         if (server->blackholeacl != NULL)
2388                 dns_acl_detach(&server->blackholeacl);
2389
2390         dns_db_detach(&server->in_roothints);
2391
2392         isc_task_endexclusive(server->task);
2393
2394         isc_task_detach(&server->task);
2395
2396         isc_event_free(&event);
2397 }
2398
2399 void
2400 ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
2401         isc_result_t result;
2402
2403         ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
2404         if (server == NULL)
2405                 fatal("allocating server object", ISC_R_NOMEMORY);
2406
2407         server->mctx = mctx;
2408         server->task = NULL;
2409
2410         /* Initialize configuration data with default values. */
2411
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);
2418
2419         result = dns_aclenv_init(mctx, &server->aclenv);
2420         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2421
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;
2428
2429         CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
2430                                      &server->in_roothints),
2431                    "setting up root hints");
2432
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");
2444
2445         CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY),
2446                    "initializing DST");
2447
2448         server->tkeyctx = NULL;
2449         CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
2450                                       &server->tkeyctx),
2451                    "creating TKEY context");
2452
2453         /*
2454          * Setup the server task, which is responsible for coordinating
2455          * startup and shutdown of the server.
2456          */
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");
2464
2465         server->interface_timer = NULL;
2466         server->heartbeat_timer = NULL;
2467         
2468         server->interface_interval = 0;
2469         server->heartbeat_interval = 0;
2470
2471         CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
2472                                       ns_g_socketmgr, &server->zonemgr),
2473                    "dns_zonemgr_create");
2474
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");
2481
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");
2485
2486         server->flushonshutdown = ISC_FALSE;
2487         server->log_queries = ISC_FALSE;
2488
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);
2494
2495         server->magic = NS_SERVER_MAGIC;
2496         *serverp = server;
2497 }
2498
2499 void
2500 ns_server_destroy(ns_server_t **serverp) {
2501         ns_server_t *server = *serverp;
2502         REQUIRE(NS_SERVER_VALID(server));
2503
2504         ns_controls_destroy(&server->controls);
2505
2506         dns_stats_freecounters(server->mctx, &server->querystats);
2507         isc_mem_free(server->mctx, server->statsfile);
2508
2509         isc_mem_free(server->mctx, server->dumpfile);
2510
2511         dns_zonemgr_detach(&server->zonemgr);
2512
2513         if (server->tkeyctx != NULL)
2514                 dns_tkeyctx_destroy(&server->tkeyctx);
2515
2516         dst_lib_destroy();
2517
2518         isc_event_free(&server->reload_event);
2519
2520         INSIST(ISC_LIST_EMPTY(server->viewlist));
2521
2522         dns_aclenv_destroy(&server->aclenv);
2523
2524         isc_quota_destroy(&server->recursionquota);
2525         isc_quota_destroy(&server->tcpquota);
2526         isc_quota_destroy(&server->xfroutquota);
2527
2528         server->magic = 0;
2529         isc_mem_put(server->mctx, server, sizeof(*server));
2530         *serverp = NULL;
2531 }
2532
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);
2541 }
2542
2543 static void
2544 start_reserved_dispatches(ns_server_t *server) {
2545
2546         REQUIRE(NS_SERVER_VALID(server));
2547
2548         server->dispatchgen++;
2549 }
2550
2551 static void
2552 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
2553         ns_dispatch_t *dispatch, *nextdispatch;
2554
2555         REQUIRE(NS_SERVER_VALID(server));
2556
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));
2566         }
2567 }
2568
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;
2576
2577         REQUIRE(NS_SERVER_VALID(server));
2578
2579         port = isc_sockaddr_getport(addr);
2580         if (port == 0 || port >= 1024)
2581                 return;
2582
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;
2588         }
2589         if (dispatch != NULL) {
2590                 dispatch->dispatchgen = server->dispatchgen;
2591                 return;
2592         }
2593
2594         dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
2595         if (dispatch == NULL) {
2596                 result = ISC_R_NOMEMORY;
2597                 goto cleanup;
2598         }
2599
2600         dispatch->addr = *addr;
2601         dispatch->dispatchgen = server->dispatchgen;
2602         dispatch->dispatch = NULL;
2603
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;
2616         }
2617         attrmask = 0;
2618         attrmask |= DNS_DISPATCHATTR_UDP;
2619         attrmask |= DNS_DISPATCHATTR_TCP;
2620         attrmask |= DNS_DISPATCHATTR_IPV4;
2621         attrmask |= DNS_DISPATCHATTR_IPV6;
2622
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;
2629
2630         ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
2631
2632         return;
2633
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));
2642 }
2643
2644
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);
2661 }
2662
2663 static void
2664 reload(ns_server_t *server) {
2665         isc_result_t result;
2666         CHECK(loadconfig(server));
2667
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));
2674         }
2675  cleanup: ;
2676 }
2677
2678 static void
2679 reconfig(ns_server_t *server) {
2680         isc_result_t result;
2681         CHECK(loadconfig(server));
2682
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));
2689         }
2690  cleanup: ;
2691 }
2692
2693 /*
2694  * Handle a reload event (from SIGHUP).
2695  */
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;
2699
2700         INSIST(task = server->task);
2701         UNUSED(task);
2702
2703         reload(server);
2704
2705         LOCK(&server->reload_event_lock);
2706         INSIST(server->reload_event == NULL);
2707         server->reload_event = event;
2708         UNLOCK(&server->reload_event_lock);
2709 }
2710
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);
2717 }
2718
2719 static char *
2720 next_token(char **stringp, const char *delim) {
2721         char *res;
2722
2723         do {
2724                 res = strsep(stringp, delim);
2725                 if (res == NULL)
2726                         break;
2727         } while (*res == '\0');
2728         return (res);
2729 }                       
2730
2731 /*
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.
2735  */
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;
2747
2748         REQUIRE(zonep != NULL && *zonep == NULL);
2749
2750         input = args;
2751
2752         /* Skip the command name. */
2753         ptr = next_token(&input, " \t");
2754         if (ptr == NULL)
2755                 return (ISC_R_UNEXPECTEDEND);
2756
2757         /* Look for the zone name. */
2758         zonetxt = next_token(&input, " \t");
2759         if (zonetxt == NULL)
2760                 return (ISC_R_SUCCESS);
2761
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");
2767         }
2768
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;
2776
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;
2786         }
2787         
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;
2794         
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);
2803 }
2804
2805 /*
2806  * Act on a "reload" command from the command channel.
2807  */
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;
2813         
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);
2826         }
2827         return (ISC_R_SUCCESS);
2828 }       
2829
2830 /*
2831  * Act on a "reconfig" command from the command channel.
2832  */
2833 isc_result_t
2834 ns_server_reconfigcommand(ns_server_t *server, char *args) {
2835         UNUSED(args);
2836
2837         reconfig(server);
2838         return (ISC_R_SUCCESS);
2839 }
2840
2841 /*
2842  * Act on a "refresh" command from the command channel.
2843  */
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;
2848
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);
2854         
2855         dns_zone_refresh(zone);
2856         dns_zone_detach(&zone);
2857
2858         return (ISC_R_SUCCESS);
2859 }       
2860
2861 isc_result_t
2862 ns_server_togglequerylog(ns_server_t *server) {
2863         server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE;
2864         
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);
2870 }
2871
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)
2876 {
2877         isc_result_t result;
2878         cfg_listelt_t *element;
2879         ns_listenlist_t *dlist = NULL;
2880
2881         REQUIRE(target != NULL && *target == NULL);
2882
2883         result = ns_listenlist_create(mctx, &dlist);
2884         if (result != ISC_R_SUCCESS)
2885                 return (result);
2886
2887         for (element = cfg_list_first(listenlist);
2888              element != NULL;
2889              element = cfg_list_next(element))
2890         {
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);
2898         }
2899         *target = dlist;
2900         return (ISC_R_SUCCESS);
2901
2902  cleanup:
2903         ns_listenlist_detach(&dlist);
2904         return (result);
2905 }
2906
2907 /*
2908  * Create a listen list from the corresponding configuration
2909  * data structure.
2910  */
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)
2915 {
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);
2921
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);
2930                 }
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);
2937                 }
2938                 port = (in_port_t)cfg_obj_asuint32(portobj);
2939         }
2940
2941         result = ns_listenelt_create(mctx, port, NULL, &delt);
2942         if (result != ISC_R_SUCCESS)
2943                 return (result);
2944
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);
2950         }
2951         *target = delt;
2952         return (ISC_R_SUCCESS);
2953 }
2954
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;
2963
2964         isc_stdtime_get(&now);
2965
2966         CHECKM(isc_stdio_open(server->statsfile, "a", &fp),
2967                "could not open statistics dump file");
2968         
2969         ncounters = DNS_STATS_NCOUNTERS;
2970         fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);
2971         
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]);
2976         
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)
2981         {
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;
2987                         
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");
3001                         }
3002                 }
3003         }
3004         if (result == ISC_R_NOMORE)
3005                 result = ISC_R_SUCCESS;
3006         CHECK(result);
3007         
3008         fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);
3009
3010  cleanup:
3011         if (fp != NULL)
3012                 (void)isc_stdio_close(fp);
3013         return (result);
3014 }
3015
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;
3021
3022         CHECKM(isc_stdio_open(server->dumpfile, "w", &fp),
3023                "could not open dump file");
3024
3025         for (view = ISC_LIST_HEAD(server->viewlist);
3026              view != NULL;
3027              view = ISC_LIST_NEXT(view, link))
3028         {
3029                 if (view->cachedb != NULL)
3030                         CHECKM(dns_view_dumpdbtostream(view, fp),
3031                                "could not dump view databases");
3032         }
3033  cleanup:
3034         if (fp != NULL)
3035                 (void)isc_stdio_close(fp);
3036         return (result);
3037 }
3038
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;
3045
3046         UNUSED(server);
3047
3048         /* Skip the command name. */
3049         ptr = next_token(&args, " \t");
3050         if (ptr == NULL)
3051                 return (ISC_R_UNEXPECTEDEND);
3052
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;
3063         }
3064         isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
3065         return (ISC_R_SUCCESS);
3066 }
3067
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;
3074
3075         /* Skip the command name. */
3076         ptr = next_token(&args, " \t");
3077         if (ptr == NULL)
3078                 return (ISC_R_UNEXPECTEDEND);
3079
3080         /* Look for the view name. */
3081         viewname = next_token(&args, " \t");
3082
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))
3088         {
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;
3095         }
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);
3103 }
3104
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;
3109
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);
3132 }