Merge from vendor branch INTEL_ACPICA:
[dragonfly.git] / contrib / bind-9.3 / bin / named / server.c
1 /*
2  * Copyright (C) 2004, 2005  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.15.2.65 2005/07/27 02:53:15 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/parseint.h>
32 #include <isc/print.h>
33 #include <isc/resource.h>
34 #include <isc/stdio.h>
35 #include <isc/string.h>
36 #include <isc/task.h>
37 #include <isc/timer.h>
38 #include <isc/util.h>
39
40 #include <isccfg/namedconf.h>
41
42 #include <bind9/check.h>
43
44 #include <dns/adb.h>
45 #include <dns/cache.h>
46 #include <dns/db.h>
47 #include <dns/dispatch.h>
48 #include <dns/forward.h>
49 #include <dns/journal.h>
50 #include <dns/keytable.h>
51 #include <dns/master.h>
52 #include <dns/masterdump.h>
53 #include <dns/order.h>
54 #include <dns/peer.h>
55 #include <dns/portlist.h>
56 #include <dns/rdataclass.h>
57 #include <dns/rdataset.h>
58 #include <dns/rdatastruct.h>
59 #include <dns/resolver.h>
60 #include <dns/rootns.h>
61 #include <dns/secalg.h>
62 #include <dns/stats.h>
63 #include <dns/tkey.h>
64 #include <dns/view.h>
65 #include <dns/zone.h>
66 #include <dns/zt.h>
67
68 #include <dst/dst.h>
69 #include <dst/result.h>
70
71 #include <named/client.h>
72 #include <named/config.h>
73 #include <named/control.h>
74 #include <named/interfacemgr.h>
75 #include <named/log.h>
76 #include <named/logconf.h>
77 #include <named/lwresd.h>
78 #include <named/main.h>
79 #include <named/os.h>
80 #include <named/server.h>
81 #include <named/tkeyconf.h>
82 #include <named/tsigconf.h>
83 #include <named/zoneconf.h>
84 #ifdef HAVE_LIBSCF
85 #include <named/ns_smf_globals.h>
86 #include <stdlib.h>
87 #endif
88
89 /*
90  * Check an operation for failure.  Assumes that the function
91  * using it has a 'result' variable and a 'cleanup' label.
92  */
93 #define CHECK(op) \
94         do { result = (op);                                      \
95                if (result != ISC_R_SUCCESS) goto cleanup;        \
96         } while (0)
97
98 #define CHECKM(op, msg) \
99         do { result = (op);                                       \
100                if (result != ISC_R_SUCCESS) {                     \
101                         isc_log_write(ns_g_lctx,                  \
102                                       NS_LOGCATEGORY_GENERAL,     \
103                                       NS_LOGMODULE_SERVER,        \
104                                       ISC_LOG_ERROR,              \
105                                       "%s: %s", msg,              \
106                                       isc_result_totext(result)); \
107                         goto cleanup;                             \
108                 }                                                 \
109         } while (0)                                               \
110
111 #define CHECKMF(op, msg, file) \
112         do { result = (op);                                       \
113                if (result != ISC_R_SUCCESS) {                     \
114                         isc_log_write(ns_g_lctx,                  \
115                                       NS_LOGCATEGORY_GENERAL,     \
116                                       NS_LOGMODULE_SERVER,        \
117                                       ISC_LOG_ERROR,              \
118                                       "%s '%s': %s", msg, file,   \
119                                       isc_result_totext(result)); \
120                         goto cleanup;                             \
121                 }                                                 \
122         } while (0)                                               \
123
124 #define CHECKFATAL(op, msg) \
125         do { result = (op);                                       \
126                if (result != ISC_R_SUCCESS)                       \
127                         fatal(msg, result);                       \
128         } while (0)                                               \
129
130 struct ns_dispatch {
131         isc_sockaddr_t                  addr;
132         unsigned int                    dispatchgen;
133         dns_dispatch_t                  *dispatch;
134         ISC_LINK(struct ns_dispatch)    link;
135 };
136
137 struct dumpcontext {
138         isc_mem_t                       *mctx;
139         isc_boolean_t                   dumpcache;
140         isc_boolean_t                   dumpzones;
141         FILE                            *fp;
142         ISC_LIST(struct viewlistentry)  viewlist;
143         struct viewlistentry            *view;
144         struct zonelistentry            *zone;
145         dns_dumpctx_t                   *mdctx;
146         dns_db_t                        *db;
147         dns_db_t                        *cache;
148         isc_task_t                      *task;
149         dns_dbversion_t                 *version;
150 };
151
152 struct viewlistentry {
153         dns_view_t                      *view;
154         ISC_LINK(struct viewlistentry)  link;
155         ISC_LIST(struct zonelistentry)  zonelist;
156 };
157
158 struct zonelistentry {
159         dns_zone_t                      *zone;
160         ISC_LINK(struct zonelistentry)  link;
161 };
162
163 static void
164 fatal(const char *msg, isc_result_t result);
165
166 static void
167 ns_server_reload(isc_task_t *task, isc_event_t *event);
168
169 static isc_result_t
170 ns_listenelt_fromconfig(cfg_obj_t *listener, cfg_obj_t *config,
171                         ns_aclconfctx_t *actx,
172                         isc_mem_t *mctx, ns_listenelt_t **target);
173 static isc_result_t
174 ns_listenlist_fromconfig(cfg_obj_t *listenlist, cfg_obj_t *config,
175                          ns_aclconfctx_t *actx,
176                          isc_mem_t *mctx, ns_listenlist_t **target);
177
178 static isc_result_t
179 configure_forward(cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
180                   cfg_obj_t *forwarders, cfg_obj_t *forwardtype);
181
182 static isc_result_t
183 configure_alternates(cfg_obj_t *config, dns_view_t *view,
184                      cfg_obj_t *alternates);
185
186 static isc_result_t
187 configure_zone(cfg_obj_t *config, cfg_obj_t *zconfig, cfg_obj_t *vconfig,
188                isc_mem_t *mctx, dns_view_t *view,
189                ns_aclconfctx_t *aclconf);
190
191 static void
192 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all);
193
194 /*
195  * Configure a single view ACL at '*aclp'.  Get its configuration by
196  * calling 'getvcacl' (for per-view configuration) and maybe 'getscacl'
197  * (for a global default).
198  */
199 static isc_result_t
200 configure_view_acl(cfg_obj_t *vconfig, cfg_obj_t *config,
201                    const char *aclname, ns_aclconfctx_t *actx,
202                    isc_mem_t *mctx, dns_acl_t **aclp)
203 {
204         isc_result_t result;
205         cfg_obj_t *maps[3];
206         cfg_obj_t *aclobj = NULL;
207         int i = 0;
208
209         if (*aclp != NULL)
210                 dns_acl_detach(aclp);
211         if (vconfig != NULL)
212                 maps[i++] = cfg_tuple_get(vconfig, "options");
213         if (config != NULL) {
214                 cfg_obj_t *options = NULL;
215                 (void)cfg_map_get(config, "options", &options);
216                 if (options != NULL)
217                         maps[i++] = options;
218         }
219         maps[i] = NULL;
220
221         result = ns_config_get(maps, aclname, &aclobj);
222         if (aclobj == NULL)
223                 /*
224                  * No value available.  *aclp == NULL.
225                  */
226                 return (ISC_R_SUCCESS);
227
228         result = ns_acl_fromconfig(aclobj, config, actx, mctx, aclp);
229
230         return (result);
231 }
232
233 static isc_result_t
234 configure_view_dnsseckey(cfg_obj_t *vconfig, cfg_obj_t *key,
235                          dns_keytable_t *keytable, isc_mem_t *mctx)
236 {
237         dns_rdataclass_t viewclass;
238         dns_rdata_dnskey_t keystruct;
239         isc_uint32_t flags, proto, alg;
240         char *keystr, *keynamestr;
241         unsigned char keydata[4096];
242         isc_buffer_t keydatabuf;
243         unsigned char rrdata[4096];
244         isc_buffer_t rrdatabuf;
245         isc_region_t r;
246         dns_fixedname_t fkeyname;
247         dns_name_t *keyname;
248         isc_buffer_t namebuf;
249         isc_result_t result;
250         dst_key_t *dstkey = NULL;
251
252         flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
253         proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
254         alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
255         keyname = dns_fixedname_name(&fkeyname);
256         keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
257
258         if (vconfig == NULL)
259                 viewclass = dns_rdataclass_in;
260         else {
261                 cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
262                 CHECK(ns_config_getclass(classobj, dns_rdataclass_in,
263                                          &viewclass));
264         }
265         keystruct.common.rdclass = viewclass;
266         keystruct.common.rdtype = dns_rdatatype_dnskey;
267         /*
268          * The key data in keystruct is not dynamically allocated.
269          */
270         keystruct.mctx = NULL;
271
272         ISC_LINK_INIT(&keystruct.common, link);
273
274         if (flags > 0xffff)
275                 CHECKM(ISC_R_RANGE, "key flags");
276         if (proto > 0xff)
277                 CHECKM(ISC_R_RANGE, "key protocol");
278         if (alg > 0xff)
279                 CHECKM(ISC_R_RANGE, "key algorithm");
280         keystruct.flags = (isc_uint16_t)flags;
281         keystruct.protocol = (isc_uint8_t)proto;
282         keystruct.algorithm = (isc_uint8_t)alg;
283
284         isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
285         isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
286
287         keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
288         CHECK(isc_base64_decodestring(keystr, &keydatabuf));
289         isc_buffer_usedregion(&keydatabuf, &r);
290         keystruct.datalen = r.length;
291         keystruct.data = r.base;
292
293         CHECK(dns_rdata_fromstruct(NULL,
294                                    keystruct.common.rdclass,
295                                    keystruct.common.rdtype,
296                                    &keystruct, &rrdatabuf));
297         dns_fixedname_init(&fkeyname);
298         isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr));
299         isc_buffer_add(&namebuf, strlen(keynamestr));
300         CHECK(dns_name_fromtext(keyname, &namebuf,
301                                 dns_rootname, ISC_FALSE,
302                                 NULL));
303         CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
304                               mctx, &dstkey));
305
306         CHECK(dns_keytable_add(keytable, &dstkey));
307         INSIST(dstkey == NULL);
308         return (ISC_R_SUCCESS);
309
310  cleanup:
311         if (result == DST_R_NOCRYPTO) {
312                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
313                             "ignoring trusted key for '%s': no crypto support",
314                             keynamestr);
315                 result = ISC_R_SUCCESS;
316         } else {
317                 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
318                             "configuring trusted key for '%s': %s",
319                             keynamestr, isc_result_totext(result));
320                 result = ISC_R_FAILURE;
321         }
322
323         if (dstkey != NULL)
324                 dst_key_free(&dstkey);
325
326         return (result);
327 }
328
329 /*
330  * Configure DNSSEC keys for a view.  Currently used only for
331  * the security roots.
332  *
333  * The per-view configuration values and the server-global defaults are read
334  * from 'vconfig' and 'config'.  The variable to be configured is '*target'.
335  */
336 static isc_result_t
337 configure_view_dnsseckeys(cfg_obj_t *vconfig, cfg_obj_t *config,
338                           isc_mem_t *mctx, dns_keytable_t **target)
339 {
340         isc_result_t result;
341         cfg_obj_t *keys = NULL;
342         cfg_obj_t *voptions = NULL;
343         cfg_listelt_t *element, *element2;
344         cfg_obj_t *keylist;
345         cfg_obj_t *key;
346         dns_keytable_t *keytable = NULL;
347
348         CHECK(dns_keytable_create(mctx, &keytable));
349
350         if (vconfig != NULL)
351                 voptions = cfg_tuple_get(vconfig, "options");
352
353         keys = NULL;
354         if (voptions != NULL)
355                 (void)cfg_map_get(voptions, "trusted-keys", &keys);
356         if (keys == NULL)
357                 (void)cfg_map_get(config, "trusted-keys", &keys);
358
359         for (element = cfg_list_first(keys);
360              element != NULL;
361              element = cfg_list_next(element))
362         {
363                 keylist = cfg_listelt_value(element);
364                 for (element2 = cfg_list_first(keylist);
365                      element2 != NULL;
366                      element2 = cfg_list_next(element2))
367                 {
368                         key = cfg_listelt_value(element2);
369                         CHECK(configure_view_dnsseckey(vconfig, key,
370                                                        keytable, mctx));
371                 }
372         }
373
374         dns_keytable_detach(target);
375         *target = keytable; /* Transfer ownership. */
376         keytable = NULL;
377         result = ISC_R_SUCCESS;
378         
379  cleanup:
380         return (result);
381 }
382
383 static isc_result_t
384 mustbesecure(cfg_obj_t *mbs, dns_resolver_t *resolver)
385 {
386         cfg_listelt_t *element;
387         cfg_obj_t *obj;
388         const char *str;
389         dns_fixedname_t fixed;
390         dns_name_t *name;
391         isc_boolean_t value;
392         isc_result_t result;
393         isc_buffer_t b;
394         
395         dns_fixedname_init(&fixed);
396         name = dns_fixedname_name(&fixed);
397         for (element = cfg_list_first(mbs);
398              element != NULL;
399              element = cfg_list_next(element))
400         {
401                 obj = cfg_listelt_value(element);
402                 str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
403                 isc_buffer_init(&b, str, strlen(str));
404                 isc_buffer_add(&b, strlen(str));
405                 CHECK(dns_name_fromtext(name, &b, dns_rootname,
406                                         ISC_FALSE, NULL));
407                 value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
408                 CHECK(dns_resolver_setmustbesecure(resolver, name, value));
409         }
410
411         result = ISC_R_SUCCESS;
412         
413  cleanup:
414         return (result);
415 }
416
417 /*
418  * Get a dispatch appropriate for the resolver of a given view.
419  */
420 static isc_result_t
421 get_view_querysource_dispatch(cfg_obj_t **maps,
422                               int af, dns_dispatch_t **dispatchp)
423 {
424         isc_result_t result;
425         dns_dispatch_t *disp;
426         isc_sockaddr_t sa;
427         unsigned int attrs, attrmask;
428         cfg_obj_t *obj = NULL;
429
430         /*
431          * Make compiler happy.
432          */
433         result = ISC_R_FAILURE;
434
435         switch (af) {
436         case AF_INET:
437                 result = ns_config_get(maps, "query-source", &obj);
438                 INSIST(result == ISC_R_SUCCESS);
439
440                 break;
441         case AF_INET6:
442                 result = ns_config_get(maps, "query-source-v6", &obj);
443                 INSIST(result == ISC_R_SUCCESS);
444                 break;
445         default:
446                 INSIST(0);
447         }
448
449         sa = *(cfg_obj_assockaddr(obj));
450         INSIST(isc_sockaddr_pf(&sa) == af);
451
452         /*
453          * If we don't support this address family, we're done!
454          */
455         switch (af) {
456         case AF_INET:
457                 result = isc_net_probeipv4();
458                 break;
459         case AF_INET6:
460                 result = isc_net_probeipv6();
461                 break;
462         default:
463                 INSIST(0);
464         }
465         if (result != ISC_R_SUCCESS)
466                 return (ISC_R_SUCCESS);
467
468         /*
469          * Try to find a dispatcher that we can share.
470          */
471         attrs = 0;
472         attrs |= DNS_DISPATCHATTR_UDP;
473         switch (af) {
474         case AF_INET:
475                 attrs |= DNS_DISPATCHATTR_IPV4;
476                 break;
477         case AF_INET6:
478                 attrs |= DNS_DISPATCHATTR_IPV6;
479                 break;
480         }
481         attrmask = 0;
482         attrmask |= DNS_DISPATCHATTR_UDP;
483         attrmask |= DNS_DISPATCHATTR_TCP;
484         attrmask |= DNS_DISPATCHATTR_IPV4;
485         attrmask |= DNS_DISPATCHATTR_IPV6;
486
487         disp = NULL;
488         result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
489                                      ns_g_taskmgr, &sa, 4096,
490                                      1000, 32768, 16411, 16433,
491                                      attrs, attrmask, &disp);
492         if (result != ISC_R_SUCCESS) {
493                 isc_sockaddr_t any;
494                 char buf[ISC_SOCKADDR_FORMATSIZE];
495
496                 switch (af) {
497                 case AF_INET:
498                         isc_sockaddr_any(&any);
499                         break;
500                 case AF_INET6:
501                         isc_sockaddr_any6(&any);
502                         break;
503                 }
504                 if (isc_sockaddr_equal(&sa, &any))
505                         return (ISC_R_SUCCESS);
506                 isc_sockaddr_format(&sa, buf, sizeof(buf));
507                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
508                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
509                               "could not get query source dispatcher (%s)",
510                               buf);
511                 return (result);
512         }
513
514         *dispatchp = disp;
515
516         return (ISC_R_SUCCESS);
517 }
518
519 static isc_result_t
520 configure_order(dns_order_t *order, cfg_obj_t *ent) {
521         dns_rdataclass_t rdclass;
522         dns_rdatatype_t rdtype;
523         cfg_obj_t *obj;
524         dns_fixedname_t fixed;
525         unsigned int mode = 0;
526         const char *str;
527         isc_buffer_t b;
528         isc_result_t result;
529         isc_boolean_t addroot;
530
531         result = ns_config_getclass(cfg_tuple_get(ent, "class"),
532                                     dns_rdataclass_any, &rdclass);
533         if (result != ISC_R_SUCCESS)
534                 return (result);
535
536         result = ns_config_gettype(cfg_tuple_get(ent, "type"),
537                                    dns_rdatatype_any, &rdtype);
538         if (result != ISC_R_SUCCESS)
539                 return (result);
540
541         obj = cfg_tuple_get(ent, "name");
542         if (cfg_obj_isstring(obj)) 
543                 str = cfg_obj_asstring(obj);
544         else
545                 str = "*";
546         addroot = ISC_TF(strcmp(str, "*") == 0);
547         isc_buffer_init(&b, str, strlen(str));
548         isc_buffer_add(&b, strlen(str));
549         dns_fixedname_init(&fixed);
550         result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
551                                    dns_rootname, ISC_FALSE, NULL);
552         if (result != ISC_R_SUCCESS)
553                 return (result);
554
555         obj = cfg_tuple_get(ent, "ordering");
556         INSIST(cfg_obj_isstring(obj));
557         str = cfg_obj_asstring(obj);
558         if (!strcasecmp(str, "fixed"))
559                 mode = DNS_RDATASETATTR_FIXEDORDER;
560         else if (!strcasecmp(str, "random"))
561                 mode = DNS_RDATASETATTR_RANDOMIZE;
562         else if (!strcasecmp(str, "cyclic"))
563                 mode = 0;
564         else
565                 INSIST(0);
566
567         /*
568          * "*" should match everything including the root (BIND 8 compat).
569          * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
570          * explict entry for "." when the name is "*".
571          */
572         if (addroot) {
573                 result = dns_order_add(order, dns_rootname,
574                                        rdtype, rdclass, mode);
575                 if (result != ISC_R_SUCCESS)
576                         return (result);
577         }
578
579         return (dns_order_add(order, dns_fixedname_name(&fixed),
580                               rdtype, rdclass, mode));
581 }
582
583 static isc_result_t
584 configure_peer(cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
585         isc_sockaddr_t *sa;
586         isc_netaddr_t na;
587         dns_peer_t *peer;
588         cfg_obj_t *obj;
589         char *str;
590         isc_result_t result;
591
592         sa = cfg_obj_assockaddr(cfg_map_getname(cpeer));
593         isc_netaddr_fromsockaddr(&na, sa);
594
595         peer = NULL;
596         result = dns_peer_new(mctx, &na, &peer);
597         if (result != ISC_R_SUCCESS)
598                 return (result);
599
600         obj = NULL;
601         (void)cfg_map_get(cpeer, "bogus", &obj);
602         if (obj != NULL)
603                 CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
604
605         obj = NULL;
606         (void)cfg_map_get(cpeer, "provide-ixfr", &obj);
607         if (obj != NULL)
608                 CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
609
610         obj = NULL;
611         (void)cfg_map_get(cpeer, "request-ixfr", &obj);
612         if (obj != NULL)
613                 CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
614
615         obj = NULL;
616         (void)cfg_map_get(cpeer, "edns", &obj);
617         if (obj != NULL)
618                 CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
619
620         obj = NULL;
621         (void)cfg_map_get(cpeer, "transfers", &obj);
622         if (obj != NULL)
623                 CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
624
625         obj = NULL;
626         (void)cfg_map_get(cpeer, "transfer-format", &obj);
627         if (obj != NULL) {
628                 str = cfg_obj_asstring(obj);
629                 if (strcasecmp(str, "many-answers") == 0)
630                         CHECK(dns_peer_settransferformat(peer,
631                                                          dns_many_answers));
632                 else if (strcasecmp(str, "one-answer") == 0)
633                         CHECK(dns_peer_settransferformat(peer,
634                                                          dns_one_answer));
635                 else
636                         INSIST(0);
637         }
638
639         obj = NULL;
640         (void)cfg_map_get(cpeer, "keys", &obj);
641         if (obj != NULL) {
642                 result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
643                 if (result != ISC_R_SUCCESS)
644                         goto cleanup;
645         }
646
647         obj = NULL;
648         if (isc_sockaddr_pf(sa) == AF_INET)
649                 (void)cfg_map_get(cpeer, "transfer-source", &obj);
650         else
651                 (void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
652         if (obj != NULL) {
653                 result = dns_peer_settransfersource(peer,
654                                                     cfg_obj_assockaddr(obj));
655                 if (result != ISC_R_SUCCESS)
656                         goto cleanup;
657         }
658         *peerp = peer;
659         return (ISC_R_SUCCESS);
660
661  cleanup:
662         dns_peer_detach(&peer);
663         return (result);
664 }
665
666 static isc_result_t
667 disable_algorithms(cfg_obj_t *disabled, dns_resolver_t *resolver) {
668         isc_result_t result;
669         cfg_obj_t *algorithms;
670         cfg_listelt_t *element;
671         const char *str;
672         dns_fixedname_t fixed;
673         dns_name_t *name;
674         isc_buffer_t b;
675
676         dns_fixedname_init(&fixed);
677         name = dns_fixedname_name(&fixed);
678         str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
679         isc_buffer_init(&b, str, strlen(str));
680         isc_buffer_add(&b, strlen(str));
681         CHECK(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL));
682
683         algorithms = cfg_tuple_get(disabled, "algorithms");
684         for (element = cfg_list_first(algorithms);
685              element != NULL;
686              element = cfg_list_next(element))
687         {
688                 isc_textregion_t r;
689                 dns_secalg_t alg;
690
691                 r.base = cfg_obj_asstring(cfg_listelt_value(element));
692                 r.length = strlen(r.base);
693
694                 result = dns_secalg_fromtext(&alg, &r);
695                 if (result != ISC_R_SUCCESS) {
696                         isc_uint8_t ui;
697                         result = isc_parse_uint8(&ui, r.base, 10);
698                         alg = ui;
699                 }
700                 if (result != ISC_R_SUCCESS) {
701                         cfg_obj_log(cfg_listelt_value(element),
702                                     ns_g_lctx, ISC_LOG_ERROR,
703                                     "invalid algorithm");
704                         CHECK(result);
705                 }
706                 CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
707         }
708  cleanup:
709         return (result);
710 }
711
712 /*
713  * Configure 'view' according to 'vconfig', taking defaults from 'config'
714  * where values are missing in 'vconfig'.
715  *
716  * When configuring the default view, 'vconfig' will be NULL and the
717  * global defaults in 'config' used exclusively.
718  */
719 static isc_result_t
720 configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
721                isc_mem_t *mctx, ns_aclconfctx_t *actx,
722                isc_boolean_t need_hints)
723 {
724         cfg_obj_t *maps[4];
725         cfg_obj_t *cfgmaps[3];
726         cfg_obj_t *options = NULL;
727         cfg_obj_t *voptions = NULL;
728         cfg_obj_t *forwardtype;
729         cfg_obj_t *forwarders;
730         cfg_obj_t *alternates;
731         cfg_obj_t *zonelist;
732         cfg_obj_t *disabled;
733         cfg_obj_t *obj;
734         cfg_listelt_t *element;
735         in_port_t port;
736         dns_cache_t *cache = NULL;
737         isc_result_t result;
738         isc_uint32_t max_adb_size;
739         isc_uint32_t max_cache_size;
740         isc_uint32_t lame_ttl;
741         dns_tsig_keyring_t *ring;
742         dns_view_t *pview = NULL;       /* Production view */
743         isc_mem_t *cmctx;
744         dns_dispatch_t *dispatch4 = NULL;
745         dns_dispatch_t *dispatch6 = NULL;
746         isc_boolean_t reused_cache = ISC_FALSE;
747         int i;
748         const char *str;
749         dns_order_t *order = NULL;
750         isc_uint32_t udpsize;
751         unsigned int check = 0;
752
753         REQUIRE(DNS_VIEW_VALID(view));
754
755         cmctx = NULL;
756
757         if (config != NULL)
758                 (void)cfg_map_get(config, "options", &options);
759
760         i = 0;
761         if (vconfig != NULL) {
762                 voptions = cfg_tuple_get(vconfig, "options");
763                 maps[i++] = voptions;
764         }
765         if (options != NULL)
766                 maps[i++] = options;
767         maps[i++] = ns_g_defaults;
768         maps[i] = NULL;
769
770         i = 0;
771         if (voptions != NULL)
772                 cfgmaps[i++] = voptions;
773         if (config != NULL)
774                 cfgmaps[i++] = config;
775         cfgmaps[i] = NULL;
776
777         /*
778          * Set the view's port number for outgoing queries.
779          */
780         CHECKM(ns_config_getport(config, &port), "port");
781         dns_view_setdstport(view, port);
782
783         /*
784          * Configure the zones.
785          */
786         zonelist = NULL;
787         if (voptions != NULL)
788                 (void)cfg_map_get(voptions, "zone", &zonelist);
789         else
790                 (void)cfg_map_get(config, "zone", &zonelist);
791         for (element = cfg_list_first(zonelist);
792              element != NULL;
793              element = cfg_list_next(element))
794         {
795                 cfg_obj_t *zconfig = cfg_listelt_value(element);
796                 CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
797                                      actx));
798         }
799
800         /*
801          * Configure the view's cache.  Try to reuse an existing
802          * cache if possible, otherwise create a new cache.
803          * Note that the ADB is not preserved in either case.
804          *
805          * XXX Determining when it is safe to reuse a cache is
806          * tricky.  When the view's configuration changes, the cached
807          * data may become invalid because it reflects our old
808          * view of the world.  As more view attributes become
809          * configurable, we will have to add code here to check
810          * whether they have changed in ways that could
811          * invalidate the cache.
812          */
813         result = dns_viewlist_find(&ns_g_server->viewlist,
814                                    view->name, view->rdclass,
815                                    &pview);
816         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
817                 goto cleanup;
818         if (pview != NULL) {
819                 INSIST(pview->cache != NULL);
820                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
821                               NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3),
822                               "reusing existing cache");
823                 reused_cache = ISC_TRUE;
824                 dns_cache_attach(pview->cache, &cache);
825                 dns_view_detach(&pview);
826         } else {
827                 CHECK(isc_mem_create(0, 0, &cmctx));
828                 CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr,
829                                        view->rdclass, "rbt", 0, NULL, &cache));
830         }
831         dns_view_setcache(view, cache);
832
833         /*
834          * cache-file cannot be inherited if views are present, but this
835          * should be caught by the configuration checking stage.
836          */
837         obj = NULL;
838         result = ns_config_get(maps, "cache-file", &obj);
839         if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
840                 CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
841                 if (!reused_cache)
842                         CHECK(dns_cache_load(cache));
843         }
844
845         obj = NULL;
846         result = ns_config_get(maps, "cleaning-interval", &obj);
847         INSIST(result == ISC_R_SUCCESS);
848         dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60);
849
850         obj = NULL;
851         result = ns_config_get(maps, "max-cache-size", &obj);
852         INSIST(result == ISC_R_SUCCESS);
853         if (cfg_obj_isstring(obj)) {
854                 str = cfg_obj_asstring(obj);
855                 INSIST(strcasecmp(str, "unlimited") == 0);
856                 max_cache_size = ISC_UINT32_MAX;
857         } else {
858                 isc_resourcevalue_t value;
859                 value = cfg_obj_asuint64(obj);
860                 if (value > ISC_UINT32_MAX) {
861                         cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
862                                     "'max-cache-size "
863                                     "%" ISC_PRINT_QUADFORMAT "d' is too large",
864                                     value);
865                         result = ISC_R_RANGE;
866                         goto cleanup;
867                 }
868                 max_cache_size = (isc_uint32_t)value;
869         }
870         dns_cache_setcachesize(cache, max_cache_size);
871
872         dns_cache_detach(&cache);
873
874         /*
875          * Check-names.
876          */
877         obj = NULL;
878         result = ns_checknames_get(maps, "response", &obj);
879         INSIST(result == ISC_R_SUCCESS);
880
881         str = cfg_obj_asstring(obj);
882         if (strcasecmp(str, "fail") == 0) {
883                 check = DNS_RESOLVER_CHECKNAMES |
884                         DNS_RESOLVER_CHECKNAMESFAIL;
885                 view->checknames = ISC_TRUE;
886         } else if (strcasecmp(str, "warn") == 0) {
887                 check = DNS_RESOLVER_CHECKNAMES;
888                 view->checknames = ISC_FALSE;
889         } else if (strcasecmp(str, "ignore") == 0) {
890                 check = 0;
891                 view->checknames = ISC_FALSE;
892         } else
893                 INSIST(0);
894
895         /*
896          * Resolver.
897          *
898          * XXXRTH  Hardwired number of tasks.
899          */
900         CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4));
901         CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6));
902         if (dispatch4 == NULL && dispatch6 == NULL) {
903                 UNEXPECTED_ERROR(__FILE__, __LINE__,
904                                  "unable to obtain neither an IPv4 nor"
905                                  " an IPv6 dispatch");
906                 result = ISC_R_UNEXPECTED;
907                 goto cleanup;
908         }
909         CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31,
910                                       ns_g_socketmgr, ns_g_timermgr,
911                                       check, ns_g_dispatchmgr,
912                                       dispatch4, dispatch6));
913
914         /*
915          * Set the ADB cache size to 1/8th of the max-cache-size.
916          */
917         max_adb_size = 0;
918         if (max_cache_size != 0) {
919                 max_adb_size = max_cache_size / 8;
920                 if (max_adb_size == 0)
921                         max_adb_size = 1;       /* Force minimum. */
922         }
923         dns_adb_setadbsize(view->adb, max_adb_size);
924
925         /*
926          * Set resolver's lame-ttl.
927          */
928         obj = NULL;
929         result = ns_config_get(maps, "lame-ttl", &obj);
930         INSIST(result == ISC_R_SUCCESS);
931         lame_ttl = cfg_obj_asuint32(obj);
932         if (lame_ttl > 1800)
933                 lame_ttl = 1800;
934         dns_resolver_setlamettl(view->resolver, lame_ttl);
935         
936         /*
937          * Set the resolver's EDNS UDP size.
938          */
939         obj = NULL;
940         result = ns_config_get(maps, "edns-udp-size", &obj);
941         INSIST(result == ISC_R_SUCCESS);
942         udpsize = cfg_obj_asuint32(obj);
943         if (udpsize < 512)
944                 udpsize = 512;
945         if (udpsize > 4096)
946                 udpsize = 4096;
947         dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize);
948         
949         /*
950          * Set supported DNSSEC algorithms.
951          */
952         dns_resolver_reset_algorithms(view->resolver);
953         disabled = NULL;
954         (void)ns_config_get(maps, "disable-algorithms", &disabled);
955         if (disabled != NULL) {
956                 for (element = cfg_list_first(disabled);
957                      element != NULL;
958                      element = cfg_list_next(element))
959                         CHECK(disable_algorithms(cfg_listelt_value(element),
960                                                  view->resolver));
961         }
962
963         /*
964          * A global or view "forwarders" option, if present,
965          * creates an entry for "." in the forwarding table.
966          */
967         forwardtype = NULL;
968         forwarders = NULL;
969         (void)ns_config_get(maps, "forward", &forwardtype);
970         (void)ns_config_get(maps, "forwarders", &forwarders);
971         if (forwarders != NULL)
972                 CHECK(configure_forward(config, view, dns_rootname, 
973                                         forwarders, forwardtype));
974
975         /*
976          * Dual Stack Servers.
977          */
978         alternates = NULL;
979         (void)ns_config_get(maps, "dual-stack-servers", &alternates);
980         if (alternates != NULL)
981                 CHECK(configure_alternates(config, view, alternates));
982
983         /*
984          * We have default hints for class IN if we need them.
985          */
986         if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
987                 dns_view_sethints(view, ns_g_server->in_roothints);
988
989         /*
990          * If we still have no hints, this is a non-IN view with no
991          * "hints zone" configured.  Issue a warning, except if this
992          * is a root server.  Root servers never need to consult 
993          * their hints, so it's no point requiring users to configure
994          * them.
995          */
996         if (view->hints == NULL) {
997                 dns_zone_t *rootzone = NULL;
998                 (void)dns_view_findzone(view, dns_rootname, &rootzone);
999                 if (rootzone != NULL) {
1000                         dns_zone_detach(&rootzone);
1001                         need_hints = ISC_FALSE;
1002                 }
1003                 if (need_hints)
1004                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1005                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1006                                       "no root hints for view '%s'",
1007                                       view->name);
1008         }
1009
1010         /*
1011          * Configure the view's TSIG keys.
1012          */
1013         ring = NULL;
1014         CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring));
1015         dns_view_setkeyring(view, ring);
1016
1017         /*
1018          * Configure the view's peer list.
1019          */
1020         {
1021                 cfg_obj_t *peers = NULL;
1022                 cfg_listelt_t *element;
1023                 dns_peerlist_t *newpeers = NULL;
1024
1025                 (void)ns_config_get(cfgmaps, "server", &peers);
1026                 CHECK(dns_peerlist_new(mctx, &newpeers));
1027                 for (element = cfg_list_first(peers);
1028                      element != NULL;
1029                      element = cfg_list_next(element))
1030                 {
1031                         cfg_obj_t *cpeer = cfg_listelt_value(element);
1032                         dns_peer_t *peer;
1033
1034                         CHECK(configure_peer(cpeer, mctx, &peer));
1035                         dns_peerlist_addpeer(newpeers, peer);
1036                         dns_peer_detach(&peer);
1037                 }
1038                 dns_peerlist_detach(&view->peers);
1039                 view->peers = newpeers; /* Transfer ownership. */
1040         }
1041
1042         /*
1043          *      Configure the views rrset-order.
1044          */
1045         {
1046                 cfg_obj_t *rrsetorder = NULL;
1047                 cfg_listelt_t *element;
1048
1049                 (void)ns_config_get(maps, "rrset-order", &rrsetorder);
1050                 CHECK(dns_order_create(mctx, &order));
1051                 for (element = cfg_list_first(rrsetorder);
1052                      element != NULL;
1053                      element = cfg_list_next(element))
1054                 {
1055                         cfg_obj_t *ent = cfg_listelt_value(element);
1056
1057                         CHECK(configure_order(order, ent));
1058                 }
1059                 if (view->order != NULL)
1060                         dns_order_detach(&view->order);
1061                 dns_order_attach(order, &view->order);
1062                 dns_order_detach(&order);
1063         }
1064         /*
1065          * Copy the aclenv object.
1066          */
1067         dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv);
1068
1069         /*
1070          * Configure the "match-clients" and "match-destinations" ACL.
1071          */
1072         CHECK(configure_view_acl(vconfig, config, "match-clients", actx,
1073                                  ns_g_mctx, &view->matchclients));
1074         CHECK(configure_view_acl(vconfig, config, "match-destinations", actx,
1075                                  ns_g_mctx, &view->matchdestinations));
1076
1077         /*
1078          * Configure the "match-recursive-only" option.
1079          */
1080         obj = NULL;
1081         (void) ns_config_get(maps, "match-recursive-only", &obj);
1082         if (obj != NULL && cfg_obj_asboolean(obj))
1083                 view->matchrecursiveonly = ISC_TRUE;
1084         else
1085                 view->matchrecursiveonly = ISC_FALSE;
1086
1087         /*
1088          * Configure other configurable data.
1089          */
1090         obj = NULL;
1091         result = ns_config_get(maps, "recursion", &obj);
1092         INSIST(result == ISC_R_SUCCESS);
1093         view->recursion = cfg_obj_asboolean(obj);
1094
1095         obj = NULL;
1096         result = ns_config_get(maps, "auth-nxdomain", &obj);
1097         INSIST(result == ISC_R_SUCCESS);
1098         view->auth_nxdomain = cfg_obj_asboolean(obj);
1099
1100         obj = NULL;
1101         result = ns_config_get(maps, "minimal-responses", &obj);
1102         INSIST(result == ISC_R_SUCCESS);
1103         view->minimalresponses = cfg_obj_asboolean(obj);
1104
1105         obj = NULL;
1106         result = ns_config_get(maps, "transfer-format", &obj);
1107         INSIST(result == ISC_R_SUCCESS);
1108         str = cfg_obj_asstring(obj);
1109         if (strcasecmp(str, "many-answers") == 0)
1110                 view->transfer_format = dns_many_answers;
1111         else if (strcasecmp(str, "one-answer") == 0)
1112                 view->transfer_format = dns_one_answer;
1113         else
1114                 INSIST(0);
1115         
1116         /*
1117          * Set sources where additional data and CNAME/DNAME
1118          * targets for authoritative answers may be found.
1119          */
1120         obj = NULL;
1121         result = ns_config_get(maps, "additional-from-auth", &obj);
1122         INSIST(result == ISC_R_SUCCESS);
1123         view->additionalfromauth = cfg_obj_asboolean(obj);
1124         if (view->recursion && ! view->additionalfromauth) {
1125                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
1126                             "'additional-from-auth no' is only supported "
1127                             "with 'recursion no'");
1128                 view->additionalfromauth = ISC_TRUE;
1129         }
1130
1131         obj = NULL;
1132         result = ns_config_get(maps, "additional-from-cache", &obj);
1133         INSIST(result == ISC_R_SUCCESS);
1134         view->additionalfromcache = cfg_obj_asboolean(obj);
1135         if (view->recursion && ! view->additionalfromcache) {
1136                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
1137                             "'additional-from-cache no' is only supported "
1138                             "with 'recursion no'");
1139                 view->additionalfromcache = ISC_TRUE;
1140         }
1141
1142         CHECK(configure_view_acl(vconfig, config, "allow-query",
1143                                  actx, ns_g_mctx, &view->queryacl));
1144
1145         if (strcmp(view->name, "_bind") != 0)
1146                 CHECK(configure_view_acl(vconfig, config, "allow-recursion",
1147                                          actx, ns_g_mctx, &view->recursionacl));
1148
1149         /*
1150          * Warning if both "recursion no;" and allow-recursion are active
1151          * except for "allow-recursion { none; };".
1152          */
1153         if (!view->recursion && view->recursionacl != NULL &&
1154             (view->recursionacl->length != 1 ||
1155              view->recursionacl->elements[0].type != dns_aclelementtype_any ||
1156              view->recursionacl->elements[0].negative != ISC_TRUE)) {
1157                 const char *forview = " for view ";
1158                 const char *viewname = view->name;
1159
1160                 if (!strcmp(view->name, "_bind") ||
1161                     !strcmp(view->name, "_default")) {
1162                         forview = "";
1163                         viewname = "";
1164                 }
1165                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1166                               NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1167                               "both \"recursion no;\" and \"allow-recursion\" "
1168                               "active%s%s", forview, viewname);
1169         }
1170
1171         CHECK(configure_view_acl(vconfig, config, "sortlist",
1172                                  actx, ns_g_mctx, &view->sortlist));
1173
1174         obj = NULL;
1175         result = ns_config_get(maps, "request-ixfr", &obj);
1176         INSIST(result == ISC_R_SUCCESS);
1177         view->requestixfr = cfg_obj_asboolean(obj);
1178
1179         obj = NULL;
1180         result = ns_config_get(maps, "provide-ixfr", &obj);
1181         INSIST(result == ISC_R_SUCCESS);
1182         view->provideixfr = cfg_obj_asboolean(obj);
1183                         
1184         obj = NULL;
1185         result = ns_config_get(maps, "dnssec-enable", &obj);
1186         INSIST(result == ISC_R_SUCCESS);
1187         view->enablednssec = cfg_obj_asboolean(obj);
1188
1189         obj = NULL;
1190         result = ns_config_get(maps, "dnssec-lookaside", &obj);
1191         if (result == ISC_R_SUCCESS) {
1192                 for (element = cfg_list_first(obj);
1193                      element != NULL;
1194                      element = cfg_list_next(element))
1195                 {
1196                         const char *str;
1197                         isc_buffer_t b;
1198                         dns_name_t *dlv;
1199
1200                         obj = cfg_listelt_value(element);
1201 #if 0
1202                         dns_fixedname_t fixed;
1203                         dns_name_t *name;
1204
1205                         /*
1206                          * When we support multiple dnssec-lookaside
1207                          * entries this is how to find the domain to be
1208                          * checked. XXXMPA
1209                          */
1210                         dns_fixedname_init(&fixed);
1211                         name = dns_fixedname_name(&fixed);
1212                         str = cfg_obj_asstring(cfg_tuple_get(obj,
1213                                                              "domain"));
1214                         isc_buffer_init(&b, str, strlen(str));
1215                         isc_buffer_add(&b, strlen(str));
1216                         CHECK(dns_name_fromtext(name, &b, dns_rootname,
1217                                                 ISC_TRUE, NULL));
1218 #endif
1219                         str = cfg_obj_asstring(cfg_tuple_get(obj,
1220                                                              "trust-anchor"));
1221                         isc_buffer_init(&b, str, strlen(str));
1222                         isc_buffer_add(&b, strlen(str));
1223                         dlv = dns_fixedname_name(&view->dlv_fixed);
1224                         CHECK(dns_name_fromtext(dlv, &b, dns_rootname,
1225                                                 ISC_TRUE, NULL));
1226                         view->dlv = dns_fixedname_name(&view->dlv_fixed);
1227                 }
1228         } else
1229                 view->dlv = NULL;
1230
1231         /*
1232          * For now, there is only one kind of trusted keys, the
1233          * "security roots".
1234          */
1235         if (view->enablednssec) {
1236                 CHECK(configure_view_dnsseckeys(vconfig, config, mctx,
1237                                                 &view->secroots));
1238                 dns_resolver_resetmustbesecure(view->resolver);
1239                 obj = NULL;
1240                 result = ns_config_get(maps, "dnssec-must-be-secure", &obj);
1241                 if (result == ISC_R_SUCCESS)
1242                         CHECK(mustbesecure(obj, view->resolver));
1243         }
1244
1245         obj = NULL;
1246         result = ns_config_get(maps, "max-cache-ttl", &obj);
1247         INSIST(result == ISC_R_SUCCESS);
1248         view->maxcachettl = cfg_obj_asuint32(obj);
1249
1250         obj = NULL;
1251         result = ns_config_get(maps, "max-ncache-ttl", &obj);
1252         INSIST(result == ISC_R_SUCCESS);
1253         view->maxncachettl = cfg_obj_asuint32(obj);
1254         if (view->maxncachettl > 7 * 24 * 3600)
1255                 view->maxncachettl = 7 * 24 * 3600;
1256
1257         obj = NULL;
1258         result = ns_config_get(maps, "preferred-glue", &obj);
1259         if (result == ISC_R_SUCCESS) {
1260                 str = cfg_obj_asstring(obj);
1261                 if (strcasecmp(str, "a") == 0)
1262                         view->preferred_glue = dns_rdatatype_a;
1263                 else if (strcasecmp(str, "aaaa") == 0)
1264                         view->preferred_glue = dns_rdatatype_aaaa;
1265                 else
1266                         view->preferred_glue = 0;
1267         } else
1268                 view->preferred_glue = 0;
1269
1270         obj = NULL;
1271         result = ns_config_get(maps, "root-delegation-only", &obj);
1272         if (result == ISC_R_SUCCESS) {
1273                 dns_view_setrootdelonly(view, ISC_TRUE);
1274                 if (!cfg_obj_isvoid(obj)) {
1275                         dns_fixedname_t fixed;
1276                         dns_name_t *name;
1277                         isc_buffer_t b;
1278                         char *str;
1279                         cfg_obj_t *exclude;
1280
1281                         dns_fixedname_init(&fixed);
1282                         name = dns_fixedname_name(&fixed);
1283                         for (element = cfg_list_first(obj);
1284                              element != NULL;
1285                              element = cfg_list_next(element)) {
1286                                 exclude = cfg_listelt_value(element);
1287                                 str = cfg_obj_asstring(exclude);
1288                                 isc_buffer_init(&b, str, strlen(str));
1289                                 isc_buffer_add(&b, strlen(str));
1290                                 CHECK(dns_name_fromtext(name, &b, dns_rootname,
1291                                                         ISC_FALSE, NULL));
1292                                 CHECK(dns_view_excludedelegationonly(view,
1293                                                                      name));
1294                         }
1295                 }
1296         } else
1297                 dns_view_setrootdelonly(view, ISC_FALSE);
1298
1299         result = ISC_R_SUCCESS;
1300
1301  cleanup:
1302         if (dispatch4 != NULL)
1303                 dns_dispatch_detach(&dispatch4);
1304         if (dispatch6 != NULL)
1305                 dns_dispatch_detach(&dispatch6);
1306         if (order != NULL)
1307                 dns_order_detach(&order);
1308         if (cmctx != NULL)
1309                 isc_mem_detach(&cmctx);
1310
1311         if (cache != NULL)
1312                 dns_cache_detach(&cache);
1313
1314         return (result);
1315 }
1316
1317 static isc_result_t
1318 configure_hints(dns_view_t *view, const char *filename) {
1319         isc_result_t result;
1320         dns_db_t *db;
1321
1322         db = NULL;
1323         result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
1324         if (result == ISC_R_SUCCESS) {
1325                 dns_view_sethints(view, db);
1326                 dns_db_detach(&db);
1327         }
1328
1329         return (result);
1330 }
1331
1332 static isc_result_t
1333 configure_alternates(cfg_obj_t *config, dns_view_t *view,
1334                      cfg_obj_t *alternates)
1335 {
1336         cfg_obj_t *portobj;
1337         cfg_obj_t *addresses;
1338         cfg_listelt_t *element;
1339         isc_result_t result = ISC_R_SUCCESS;
1340         in_port_t port;
1341
1342         /*
1343          * Determine which port to send requests to.
1344          */
1345         if (ns_g_lwresdonly && ns_g_port != 0)
1346                 port = ns_g_port;
1347         else
1348                 CHECKM(ns_config_getport(config, &port), "port");
1349
1350         if (alternates != NULL) {
1351                 portobj = cfg_tuple_get(alternates, "port");
1352                 if (cfg_obj_isuint32(portobj)) {
1353                         isc_uint32_t val = cfg_obj_asuint32(portobj);
1354                         if (val > ISC_UINT16_MAX) {
1355                                 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
1356                                             "port '%u' out of range", val);
1357                                 return (ISC_R_RANGE);
1358                         }
1359                         port = (in_port_t) val;
1360                 }
1361         }
1362
1363         addresses = NULL;
1364         if (alternates != NULL)
1365                 addresses = cfg_tuple_get(alternates, "addresses");
1366
1367         for (element = cfg_list_first(addresses);
1368              element != NULL;
1369              element = cfg_list_next(element))
1370         {
1371                 cfg_obj_t *alternate = cfg_listelt_value(element);
1372                 isc_sockaddr_t sa;
1373
1374                 if (!cfg_obj_issockaddr(alternate)) {
1375                         dns_fixedname_t fixed;
1376                         dns_name_t *name;
1377                         char *str = cfg_obj_asstring(cfg_tuple_get(alternate,
1378                                                                    "name"));
1379                         isc_buffer_t buffer;
1380                         in_port_t myport = port;
1381
1382                         isc_buffer_init(&buffer, str, strlen(str));
1383                         isc_buffer_add(&buffer, strlen(str));
1384                         dns_fixedname_init(&fixed);
1385                         name = dns_fixedname_name(&fixed);
1386                         CHECK(dns_name_fromtext(name, &buffer, dns_rootname,
1387                                                 ISC_FALSE, NULL));
1388
1389                         portobj = cfg_tuple_get(alternate, "port");
1390                         if (cfg_obj_isuint32(portobj)) {
1391                                 isc_uint32_t val = cfg_obj_asuint32(portobj);
1392                                 if (val > ISC_UINT16_MAX) {
1393                                         cfg_obj_log(portobj, ns_g_lctx,
1394                                                     ISC_LOG_ERROR,
1395                                                     "port '%u' out of range",
1396                                                      val);
1397                                         return (ISC_R_RANGE);
1398                                 }
1399                                 myport = (in_port_t) val;
1400                         }
1401                         CHECK(dns_resolver_addalternate(view->resolver, NULL,
1402                                                         name, myport));
1403                         continue;
1404                 }
1405
1406                 sa = *cfg_obj_assockaddr(alternate);
1407                 if (isc_sockaddr_getport(&sa) == 0)
1408                         isc_sockaddr_setport(&sa, port);
1409                 CHECK(dns_resolver_addalternate(view->resolver, &sa,
1410                                                 NULL, 0));
1411         }
1412
1413  cleanup:
1414         return (result);
1415 }
1416
1417 static isc_result_t
1418 configure_forward(cfg_obj_t *config, dns_view_t *view, dns_name_t *origin,
1419                   cfg_obj_t *forwarders, cfg_obj_t *forwardtype)
1420 {
1421         cfg_obj_t *portobj;
1422         cfg_obj_t *faddresses;
1423         cfg_listelt_t *element;
1424         dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
1425         isc_sockaddrlist_t addresses;
1426         isc_sockaddr_t *sa;
1427         isc_result_t result;
1428         in_port_t port;
1429
1430         /*
1431          * Determine which port to send forwarded requests to.
1432          */
1433         if (ns_g_lwresdonly && ns_g_port != 0)
1434                 port = ns_g_port;
1435         else
1436                 CHECKM(ns_config_getport(config, &port), "port");
1437
1438         if (forwarders != NULL) {
1439                 portobj = cfg_tuple_get(forwarders, "port");
1440                 if (cfg_obj_isuint32(portobj)) {
1441                         isc_uint32_t val = cfg_obj_asuint32(portobj);
1442                         if (val > ISC_UINT16_MAX) {
1443                                 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
1444                                             "port '%u' out of range", val);
1445                                 return (ISC_R_RANGE);
1446                         }
1447                         port = (in_port_t) val;
1448                 }
1449         }
1450
1451         faddresses = NULL;
1452         if (forwarders != NULL)
1453                 faddresses = cfg_tuple_get(forwarders, "addresses");
1454
1455         ISC_LIST_INIT(addresses);
1456
1457         for (element = cfg_list_first(faddresses);
1458              element != NULL;
1459              element = cfg_list_next(element))
1460         {
1461                 cfg_obj_t *forwarder = cfg_listelt_value(element);
1462                 sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t));
1463                 if (sa == NULL) {
1464                         result = ISC_R_NOMEMORY;
1465                         goto cleanup;
1466                 }
1467                 *sa = *cfg_obj_assockaddr(forwarder);
1468                 if (isc_sockaddr_getport(sa) == 0)
1469                         isc_sockaddr_setport(sa, port);
1470                 ISC_LINK_INIT(sa, link);
1471                 ISC_LIST_APPEND(addresses, sa, link);
1472         }
1473
1474         if (ISC_LIST_EMPTY(addresses)) {
1475                 if (forwardtype != NULL)
1476                         cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
1477                                     "no forwarders seen; disabling "
1478                                     "forwarding");
1479                 fwdpolicy = dns_fwdpolicy_none;
1480         } else {
1481                 if (forwardtype == NULL)
1482                         fwdpolicy = dns_fwdpolicy_first;
1483                 else {
1484                         char *forwardstr = cfg_obj_asstring(forwardtype);
1485                         if (strcasecmp(forwardstr, "first") == 0)
1486                                 fwdpolicy = dns_fwdpolicy_first;
1487                         else if (strcasecmp(forwardstr, "only") == 0)
1488                                 fwdpolicy = dns_fwdpolicy_only;
1489                         else
1490                                 INSIST(0);
1491                 }
1492         }
1493
1494         result = dns_fwdtable_add(view->fwdtable, origin, &addresses,
1495                                   fwdpolicy);
1496         if (result != ISC_R_SUCCESS) {
1497                 char namebuf[DNS_NAME_FORMATSIZE];
1498                 dns_name_format(origin, namebuf, sizeof(namebuf));
1499                 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING,
1500                             "could not set up forwarding for domain '%s': %s",
1501                             namebuf, isc_result_totext(result));
1502                 goto cleanup;
1503         }
1504
1505         result = ISC_R_SUCCESS;
1506
1507  cleanup:
1508
1509         while (!ISC_LIST_EMPTY(addresses)) {
1510                 sa = ISC_LIST_HEAD(addresses);
1511                 ISC_LIST_UNLINK(addresses, sa, link);
1512                 isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t));
1513         }
1514
1515         return (result);
1516 }
1517
1518 /*
1519  * Create a new view and add it to the list.
1520  *
1521  * If 'vconfig' is NULL, create the default view.
1522  *
1523  * The view created is attached to '*viewp'.
1524  */
1525 static isc_result_t
1526 create_view(cfg_obj_t *vconfig, dns_viewlist_t *viewlist, dns_view_t **viewp) {
1527         isc_result_t result;
1528         const char *viewname;
1529         dns_rdataclass_t viewclass;
1530         dns_view_t *view = NULL;
1531
1532         if (vconfig != NULL) {
1533                 cfg_obj_t *classobj = NULL;
1534
1535                 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
1536                 classobj = cfg_tuple_get(vconfig, "class");
1537                 result = ns_config_getclass(classobj, dns_rdataclass_in,
1538                                             &viewclass);
1539         } else {
1540                 viewname = "_default";
1541                 viewclass = dns_rdataclass_in;
1542         }
1543         result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
1544         if (result == ISC_R_SUCCESS)
1545                 return (ISC_R_EXISTS);
1546         if (result != ISC_R_NOTFOUND)
1547                 return (result);
1548         INSIST(view == NULL);
1549
1550         result = dns_view_create(ns_g_mctx, viewclass, viewname, &view);
1551         if (result != ISC_R_SUCCESS)
1552                 return (result);
1553
1554         ISC_LIST_APPEND(*viewlist, view, link);
1555         dns_view_attach(view, viewp);
1556         return (ISC_R_SUCCESS);
1557 }
1558
1559 /*
1560  * Configure or reconfigure a zone.
1561  */
1562 static isc_result_t
1563 configure_zone(cfg_obj_t *config, cfg_obj_t *zconfig, cfg_obj_t *vconfig,
1564                isc_mem_t *mctx, dns_view_t *view,
1565                ns_aclconfctx_t *aclconf)
1566 {
1567         dns_view_t *pview = NULL;       /* Production view */
1568         dns_zone_t *zone = NULL;        /* New or reused zone */
1569         dns_zone_t *dupzone = NULL;
1570         cfg_obj_t *options = NULL;
1571         cfg_obj_t *zoptions = NULL;
1572         cfg_obj_t *typeobj = NULL;
1573         cfg_obj_t *forwarders = NULL;
1574         cfg_obj_t *forwardtype = NULL;
1575         cfg_obj_t *only = NULL;
1576         isc_result_t result;
1577         isc_result_t tresult;
1578         isc_buffer_t buffer;
1579         dns_fixedname_t fixorigin;
1580         dns_name_t *origin;
1581         const char *zname;
1582         dns_rdataclass_t zclass;
1583         const char *ztypestr;
1584
1585         options = NULL;
1586         (void)cfg_map_get(config, "options", &options);
1587
1588         zoptions = cfg_tuple_get(zconfig, "options");
1589
1590         /*
1591          * Get the zone origin as a dns_name_t.
1592          */
1593         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1594         isc_buffer_init(&buffer, zname, strlen(zname));
1595         isc_buffer_add(&buffer, strlen(zname));
1596         dns_fixedname_init(&fixorigin);
1597         CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
1598                                 &buffer, dns_rootname, ISC_FALSE, NULL));
1599         origin = dns_fixedname_name(&fixorigin);
1600
1601         CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
1602                                  view->rdclass, &zclass));
1603         if (zclass != view->rdclass) {
1604                 const char *vname = NULL;
1605                 if (vconfig != NULL)
1606                         vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
1607                                                                "name"));
1608                 else
1609                         vname = "<default view>";
1610         
1611                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1612                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1613                               "zone '%s': wrong class for view '%s'",
1614                               zname, vname);
1615                 result = ISC_R_FAILURE;
1616                 goto cleanup;
1617         }
1618
1619         (void)cfg_map_get(zoptions, "type", &typeobj);
1620         if (typeobj == NULL) {
1621                 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
1622                             "zone '%s' 'type' not specified", zname);
1623                 return (ISC_R_FAILURE);
1624         }
1625         ztypestr = cfg_obj_asstring(typeobj);
1626
1627         /*
1628          * "hints zones" aren't zones.  If we've got one,
1629          * configure it and return.
1630          */
1631         if (strcasecmp(ztypestr, "hint") == 0) {
1632                 cfg_obj_t *fileobj = NULL;
1633                 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
1634                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1635                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
1636                                       "zone '%s': 'file' not specified",
1637                                       zname);
1638                         result = ISC_R_FAILURE;
1639                         goto cleanup;
1640                 }
1641                 if (dns_name_equal(origin, dns_rootname)) {
1642                         char *hintsfile = cfg_obj_asstring(fileobj);
1643
1644                         result = configure_hints(view, hintsfile);
1645                         if (result != ISC_R_SUCCESS) {
1646                                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1647                                               NS_LOGMODULE_SERVER,
1648                                               ISC_LOG_ERROR,
1649                                               "could not configure root hints "
1650                                               "from '%s': %s", hintsfile,
1651                                               isc_result_totext(result));
1652                                 goto cleanup;
1653                         }
1654                         /*
1655                          * Hint zones may also refer to delegation only points.
1656                          */
1657                         only = NULL;
1658                         tresult = cfg_map_get(zoptions, "delegation-only",
1659                                               &only);
1660                         if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
1661                                 CHECK(dns_view_adddelegationonly(view, origin));
1662                 } else {
1663                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1664                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1665                                       "ignoring non-root hint zone '%s'",
1666                                       zname);
1667                         result = ISC_R_SUCCESS;
1668                 }
1669                 /* Skip ordinary zone processing. */
1670                 goto cleanup;
1671         }
1672
1673         /*
1674          * "forward zones" aren't zones either.  Translate this syntax into
1675          * the appropriate selective forwarding configuration and return.
1676          */
1677         if (strcasecmp(ztypestr, "forward") == 0) {
1678                 forwardtype = NULL;
1679                 forwarders = NULL;
1680
1681                 (void)cfg_map_get(zoptions, "forward", &forwardtype);
1682                 (void)cfg_map_get(zoptions, "forwarders", &forwarders);
1683                 result = configure_forward(config, view, origin, forwarders,
1684                                            forwardtype);
1685                 goto cleanup;
1686         }
1687
1688         /*
1689          * "delegation-only zones" aren't zones either.
1690          */
1691         if (strcasecmp(ztypestr, "delegation-only") == 0) {
1692                 result = dns_view_adddelegationonly(view, origin);
1693                 goto cleanup;
1694         }
1695
1696         /*
1697          * Check for duplicates in the new zone table.
1698          */
1699         result = dns_view_findzone(view, origin, &dupzone);
1700         if (result == ISC_R_SUCCESS) {
1701                 /*
1702                  * We already have this zone!
1703                  */
1704                 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
1705                             "zone '%s' already exists", zname);
1706                 dns_zone_detach(&dupzone);
1707                 result = ISC_R_EXISTS;
1708                 goto cleanup;
1709         }
1710         INSIST(dupzone == NULL);
1711
1712         /*
1713          * See if we can reuse an existing zone.  This is
1714          * only possible if all of these are true:
1715          *   - The zone's view exists
1716          *   - A zone with the right name exists in the view
1717          *   - The zone is compatible with the config
1718          *     options (e.g., an existing master zone cannot
1719          *     be reused if the options specify a slave zone)
1720          */
1721         result = dns_viewlist_find(&ns_g_server->viewlist,
1722                                    view->name, view->rdclass,
1723                                    &pview);
1724         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
1725                 goto cleanup;
1726         if (pview != NULL)
1727                 result = dns_view_findzone(pview, origin, &zone);
1728         if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
1729                 goto cleanup;
1730         if (zone != NULL) {
1731                 if (! ns_zone_reusable(zone, zconfig))
1732                         dns_zone_detach(&zone);
1733         }
1734
1735         if (zone != NULL) {
1736                 /*
1737                  * We found a reusable zone.  Make it use the
1738                  * new view.
1739                  */
1740                 dns_zone_setview(zone, view);
1741         } else {
1742                 /*
1743                  * We cannot reuse an existing zone, we have
1744                  * to create a new one.
1745                  */
1746                 CHECK(dns_zone_create(&zone, mctx));
1747                 CHECK(dns_zone_setorigin(zone, origin));
1748                 dns_zone_setview(zone, view);
1749                 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
1750         }
1751
1752         /*
1753          * If the zone contains a 'forwarders' statement, configure
1754          * selective forwarding.
1755          */
1756         forwarders = NULL;
1757         if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
1758         {
1759                 forwardtype = NULL;
1760                 (void)cfg_map_get(zoptions, "forward", &forwardtype);
1761                 CHECK(configure_forward(config, view, origin, forwarders,
1762                                         forwardtype));
1763         }
1764
1765         /*
1766          * Stub and forward zones may also refer to delegation only points.
1767          */
1768         only = NULL;
1769         if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
1770         {
1771                 if (cfg_obj_asboolean(only))
1772                         CHECK(dns_view_adddelegationonly(view, origin));
1773         }
1774
1775         /*
1776          * Configure the zone.
1777          */
1778         CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone));
1779
1780         /*
1781          * Add the zone to its view in the new view list.
1782          */
1783         CHECK(dns_view_addzone(view, zone));
1784
1785  cleanup:
1786         if (zone != NULL)
1787                 dns_zone_detach(&zone);
1788         if (pview != NULL)
1789                 dns_view_detach(&pview);
1790
1791         return (result);
1792 }
1793
1794 /*
1795  * Configure a single server quota.
1796  */
1797 static void
1798 configure_server_quota(cfg_obj_t **maps, const char *name, isc_quota_t *quota)
1799 {
1800         cfg_obj_t *obj = NULL;
1801         isc_result_t result;
1802
1803         result = ns_config_get(maps, name, &obj);
1804         INSIST(result == ISC_R_SUCCESS);
1805         isc_quota_max(quota, cfg_obj_asuint32(obj));
1806 }
1807
1808 /*
1809  * This function is called as soon as the 'directory' statement has been
1810  * parsed.  This can be extended to support other options if necessary.
1811  */
1812 static isc_result_t
1813 directory_callback(const char *clausename, cfg_obj_t *obj, void *arg) {
1814         isc_result_t result;
1815         char *directory;
1816
1817         REQUIRE(strcasecmp("directory", clausename) == 0);
1818
1819         UNUSED(arg);
1820         UNUSED(clausename);
1821
1822         /*
1823          * Change directory.
1824          */
1825         directory = cfg_obj_asstring(obj);
1826
1827         if (! isc_file_ischdiridempotent(directory))
1828                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
1829                             "option 'directory' contains relative path '%s'",
1830                             directory);
1831
1832         result = isc_dir_chdir(directory);
1833         if (result != ISC_R_SUCCESS) {
1834                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
1835                             "change directory to '%s' failed: %s",
1836                             directory, isc_result_totext(result));
1837                 return (result);
1838         }
1839
1840         return (ISC_R_SUCCESS);
1841 }
1842
1843 static void
1844 scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
1845         isc_boolean_t match_mapped = server->aclenv.match_mapped;
1846
1847         ns_interfacemgr_scan(server->interfacemgr, verbose);
1848         /*
1849          * Update the "localhost" and "localnets" ACLs to match the
1850          * current set of network interfaces.
1851          */
1852         dns_aclenv_copy(&server->aclenv,
1853                         ns_interfacemgr_getaclenv(server->interfacemgr));
1854
1855         server->aclenv.match_mapped = match_mapped;
1856 }
1857
1858 static isc_result_t
1859 add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr) {
1860         ns_listenelt_t *lelt = NULL;
1861         dns_acl_t *src_acl = NULL;
1862         dns_aclelement_t aelt;
1863         isc_result_t result;
1864         isc_sockaddr_t any_sa6;
1865
1866         REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
1867
1868         isc_sockaddr_any6(&any_sa6);
1869         if (!isc_sockaddr_equal(&any_sa6, addr)) {
1870                 aelt.type = dns_aclelementtype_ipprefix;
1871                 aelt.negative = ISC_FALSE;
1872                 aelt.u.ip_prefix.prefixlen = 128;
1873                 isc_netaddr_fromin6(&aelt.u.ip_prefix.address,
1874                                     &addr->type.sin6.sin6_addr);
1875
1876                 result = dns_acl_create(mctx, 1, &src_acl);
1877                 if (result != ISC_R_SUCCESS)
1878                         return (result);
1879                 result = dns_acl_appendelement(src_acl, &aelt);
1880                 if (result != ISC_R_SUCCESS)
1881                         goto clean;
1882
1883                 result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
1884                                              src_acl, &lelt);
1885                 if (result != ISC_R_SUCCESS)
1886                         goto clean;
1887                 ISC_LIST_APPEND(list->elts, lelt, link);
1888         }
1889
1890         return (ISC_R_SUCCESS);
1891
1892  clean:
1893         INSIST(lelt == NULL);
1894         if (src_acl != NULL)
1895                 dns_acl_detach(&src_acl);
1896
1897         return (result);
1898 }
1899
1900 /*
1901  * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
1902  * to update the listening interfaces accordingly.
1903  * We currently only consider IPv6, because this only affects IPv6 wildcard
1904  * sockets.
1905  */
1906 static void
1907 adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
1908         isc_result_t result;
1909         ns_listenlist_t *list = NULL;
1910         dns_view_t *view;
1911         dns_zone_t *zone, *next;
1912         isc_sockaddr_t addr, *addrp;
1913
1914         result = ns_listenlist_create(mctx, &list);
1915         if (result != ISC_R_SUCCESS)
1916                 return;
1917
1918         for (view = ISC_LIST_HEAD(server->viewlist);
1919              view != NULL;
1920              view = ISC_LIST_NEXT(view, link)) {
1921                 dns_dispatch_t *dispatch6;
1922
1923                 dispatch6 = dns_resolver_dispatchv6(view->resolver);
1924                 if (dispatch6 == NULL)
1925                         continue;
1926                 result = dns_dispatch_getlocaladdress(dispatch6, &addr);
1927                 if (result != ISC_R_SUCCESS)
1928                         goto fail;
1929                 result = add_listenelt(mctx, list, &addr);
1930                 if (result != ISC_R_SUCCESS)
1931                         goto fail;
1932         }
1933
1934         zone = NULL;
1935         for (result = dns_zone_first(server->zonemgr, &zone);
1936              result == ISC_R_SUCCESS;
1937              next = NULL, result = dns_zone_next(zone, &next), zone = next) {
1938                 dns_view_t *zoneview;
1939
1940                 /*
1941                  * At this point the zone list may contain a stale zone
1942                  * just removed from the configuration.  To see the validity,
1943                  * check if the corresponding view is in our current view list.
1944                  * There may also be old zones that are still in the process
1945                  * of shutting down and have detached from their old view
1946                  * (zoneview == NULL).
1947                  */
1948                 zoneview = dns_zone_getview(zone);
1949                 if (zoneview == NULL)
1950                         continue;
1951                 for (view = ISC_LIST_HEAD(server->viewlist);
1952                      view != NULL && view != zoneview;
1953                      view = ISC_LIST_NEXT(view, link))
1954                         ;
1955                 if (view == NULL)
1956                         continue;
1957
1958                 addrp = dns_zone_getnotifysrc6(zone);
1959                 result = add_listenelt(mctx, list, addrp);
1960                 if (result != ISC_R_SUCCESS)
1961                         goto fail;
1962
1963                 addrp = dns_zone_getxfrsource6(zone);
1964                 result = add_listenelt(mctx, list, addrp);
1965                 if (result != ISC_R_SUCCESS)
1966                         goto fail;
1967         }
1968
1969         ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
1970         
1971  clean:
1972         ns_listenlist_detach(&list);
1973         return;
1974
1975  fail:
1976         /*
1977          * Even when we failed the procedure, most of other interfaces
1978          * should work correctly.  We therefore just warn it.
1979          */
1980         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1981                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1982                       "could not adjust the listen-on list; "
1983                       "some interfaces may not work");
1984         goto clean;
1985 }
1986
1987 /*
1988  * This event callback is invoked to do periodic network
1989  * interface scanning.
1990  */
1991 static void
1992 interface_timer_tick(isc_task_t *task, isc_event_t *event) {
1993         isc_result_t result;
1994         ns_server_t *server = (ns_server_t *) event->ev_arg;
1995         INSIST(task == server->task);
1996         UNUSED(task);
1997         isc_event_free(&event);
1998         /*
1999          * XXX should scan interfaces unlocked and get exclusive access
2000          * only to replace ACLs.
2001          */
2002         result = isc_task_beginexclusive(server->task);
2003         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2004         scan_interfaces(server, ISC_FALSE);
2005         isc_task_endexclusive(server->task);
2006 }
2007
2008 static void
2009 heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
2010         ns_server_t *server = (ns_server_t *) event->ev_arg;
2011         dns_view_t *view;
2012
2013         UNUSED(task);
2014         isc_event_free(&event);
2015         view = ISC_LIST_HEAD(server->viewlist);
2016         while (view != NULL) {
2017                 dns_view_dialup(view);
2018                 view = ISC_LIST_NEXT(view, link);
2019         }
2020 }
2021
2022 /*
2023  * Replace the current value of '*field', a dynamically allocated
2024  * string or NULL, with a dynamically allocated copy of the
2025  * null-terminated string pointed to by 'value', or NULL.
2026  */
2027 static isc_result_t
2028 setstring(ns_server_t *server, char **field, const char *value) {
2029         char *copy;
2030
2031         if (value != NULL) {
2032                 copy = isc_mem_strdup(server->mctx, value);
2033                 if (copy == NULL)
2034                         return (ISC_R_NOMEMORY);
2035         } else {
2036                 copy = NULL;
2037         }
2038
2039         if (*field != NULL)
2040                 isc_mem_free(server->mctx, *field);
2041
2042         *field = copy;
2043         return (ISC_R_SUCCESS);
2044 }       
2045
2046 /*
2047  * Replace the current value of '*field', a dynamically allocated
2048  * string or NULL, with another dynamically allocated string
2049  * or NULL if whether 'obj' is a string or void value, respectively.
2050  */
2051 static isc_result_t
2052 setoptstring(ns_server_t *server, char **field, cfg_obj_t *obj) {
2053         if (cfg_obj_isvoid(obj))
2054                 return (setstring(server, field, NULL));
2055         else
2056                 return (setstring(server, field, cfg_obj_asstring(obj)));
2057 }
2058
2059 static void
2060 set_limit(cfg_obj_t **maps, const char *configname, const char *description,
2061           isc_resource_t resourceid, isc_resourcevalue_t defaultvalue)
2062 {
2063         cfg_obj_t *obj = NULL;
2064         char *resource;
2065         isc_resourcevalue_t value;
2066         isc_result_t result;
2067
2068         if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
2069                 return;
2070
2071         if (cfg_obj_isstring(obj)) {
2072                 resource = cfg_obj_asstring(obj);
2073                 if (strcasecmp(resource, "unlimited") == 0)
2074                         value = ISC_RESOURCE_UNLIMITED;
2075                 else {
2076                         INSIST(strcasecmp(resource, "default") == 0);
2077                         value = defaultvalue;
2078                 }
2079         } else
2080                 value = cfg_obj_asuint64(obj);
2081
2082         result = isc_resource_setlimit(resourceid, value);
2083         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2084                       result == ISC_R_SUCCESS ?
2085                         ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
2086                       "set maximum %s to %" ISC_PRINT_QUADFORMAT "d: %s",
2087                       description, value, isc_result_totext(result));
2088 }
2089
2090 #define SETLIMIT(cfgvar, resource, description) \
2091         set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
2092                   ns_g_init ## resource)
2093
2094 static void
2095 set_limits(cfg_obj_t **maps) {
2096         SETLIMIT("stacksize", stacksize, "stack size");
2097         SETLIMIT("datasize", datasize, "data size");
2098         SETLIMIT("coresize", coresize, "core size");
2099         SETLIMIT("files", openfiles, "open files");
2100 }
2101
2102 static isc_result_t
2103 portlist_fromconf(dns_portlist_t *portlist, unsigned int family,
2104                   cfg_obj_t *ports)
2105 {
2106         cfg_listelt_t *element;
2107         isc_result_t result = ISC_R_SUCCESS;
2108
2109         for (element = cfg_list_first(ports);
2110              element != NULL;
2111              element = cfg_list_next(element)) {
2112                 cfg_obj_t *obj = cfg_listelt_value(element);
2113                 in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
2114                 
2115                 result = dns_portlist_add(portlist, family, port);
2116                 if (result != ISC_R_SUCCESS)
2117                         break;
2118         }
2119         return (result);
2120 }
2121
2122 static isc_result_t
2123 load_configuration(const char *filename, ns_server_t *server,
2124                    isc_boolean_t first_time)
2125 {
2126         isc_result_t result;
2127         cfg_parser_t *parser = NULL;
2128         cfg_obj_t *config;
2129         cfg_obj_t *options;
2130         cfg_obj_t *views;
2131         cfg_obj_t *obj;
2132         cfg_obj_t *v4ports, *v6ports;
2133         cfg_obj_t *maps[3];
2134         cfg_obj_t *builtin_views;
2135         cfg_listelt_t *element;
2136         dns_view_t *view = NULL;
2137         dns_view_t *view_next;
2138         dns_viewlist_t viewlist;
2139         dns_viewlist_t tmpviewlist;
2140         ns_aclconfctx_t aclconfctx;
2141         isc_uint32_t interface_interval;
2142         isc_uint32_t heartbeat_interval;
2143         isc_uint32_t udpsize;
2144         in_port_t listen_port;
2145         int i;
2146
2147         ns_aclconfctx_init(&aclconfctx);
2148         ISC_LIST_INIT(viewlist);
2149
2150         /* Ensure exclusive access to configuration data. */
2151         result = isc_task_beginexclusive(server->task);
2152         RUNTIME_CHECK(result == ISC_R_SUCCESS); 
2153
2154         /*
2155          * Parse the global default pseudo-config file.
2156          */
2157         if (first_time) {
2158                 CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config));
2159                 RUNTIME_CHECK(cfg_map_get(ns_g_config, "options",
2160                                           &ns_g_defaults) ==
2161                               ISC_R_SUCCESS);
2162         }
2163
2164         /*
2165          * Parse the configuration file using the new config code.
2166          */
2167         result = ISC_R_FAILURE;
2168         config = NULL;
2169
2170         /*
2171          * Unless this is lwresd with the -C option, parse the config file.
2172          */
2173         if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) {
2174                 isc_log_write(ns_g_lctx,
2175                               NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2176                               ISC_LOG_INFO, "loading configuration from '%s'",
2177                               filename);
2178                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
2179                 cfg_parser_setcallback(parser, directory_callback, NULL);
2180                 result = cfg_parse_file(parser, filename, &cfg_type_namedconf,
2181                                         &config);
2182         }
2183
2184         /*
2185          * If this is lwresd with the -C option, or lwresd with no -C or -c
2186          * option where the above parsing failed, parse resolv.conf.
2187          */
2188         if (ns_g_lwresdonly &&
2189             (lwresd_g_useresolvconf ||
2190              (!ns_g_conffileset && result == ISC_R_FILENOTFOUND)))
2191         {
2192                 isc_log_write(ns_g_lctx,
2193                               NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2194                               ISC_LOG_INFO, "loading configuration from '%s'",
2195                               lwresd_g_resolvconffile);
2196                 if (parser != NULL)
2197                         cfg_parser_destroy(&parser);
2198                 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser));
2199                 result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser,
2200                                                     &config);
2201         }
2202         CHECK(result);
2203
2204         /*
2205          * Check the validity of the configuration.
2206          */
2207         CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx));
2208
2209         /*
2210          * Fill in the maps array, used for resolving defaults.
2211          */
2212         i = 0;
2213         options = NULL;
2214         result = cfg_map_get(config, "options", &options);
2215         if (result == ISC_R_SUCCESS)
2216                 maps[i++] = options;
2217         maps[i++] = ns_g_defaults;
2218         maps[i++] = NULL;
2219
2220         /*
2221          * Set process limits, which (usually) needs to be done as root.
2222          */
2223         set_limits(maps);
2224
2225         /*
2226          * Configure various server options.
2227          */
2228         configure_server_quota(maps, "transfers-out", &server->xfroutquota);
2229         configure_server_quota(maps, "tcp-clients", &server->tcpquota);
2230         configure_server_quota(maps, "recursive-clients",
2231                                &server->recursionquota);
2232         if (server->recursionquota.max > 1000)
2233                 isc_quota_soft(&server->recursionquota,
2234                                server->recursionquota.max - 100);
2235         else
2236                 isc_quota_soft(&server->recursionquota, 0);
2237
2238         CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx,
2239                                  ns_g_mctx, &server->blackholeacl));
2240         if (server->blackholeacl != NULL)
2241                 dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
2242                                              server->blackholeacl);
2243
2244         obj = NULL;
2245         result = ns_config_get(maps, "match-mapped-addresses", &obj);
2246         INSIST(result == ISC_R_SUCCESS);
2247         server->aclenv.match_mapped = cfg_obj_asboolean(obj);
2248
2249         v4ports = NULL;
2250         v6ports = NULL;
2251         (void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports);
2252         (void)ns_config_get(maps, "avoid-v6-udp-ports", &v6ports);
2253         if (v4ports != NULL || v6ports != NULL) {
2254                 dns_portlist_t *portlist = NULL;
2255                 result = dns_portlist_create(ns_g_mctx, &portlist);
2256                 if (result == ISC_R_SUCCESS && v4ports != NULL)
2257                         result = portlist_fromconf(portlist, AF_INET, v4ports);
2258                 if (result == ISC_R_SUCCESS && v6ports != NULL)
2259                         portlist_fromconf(portlist, AF_INET6, v6ports);
2260                 if (result == ISC_R_SUCCESS)
2261                         dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, portlist);
2262                 if (portlist != NULL)
2263                         dns_portlist_detach(&portlist);
2264                 CHECK(result);
2265         } else
2266                 dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, NULL);
2267
2268         /*
2269          * Set the EDNS UDP size when we don't match a view.
2270          */
2271         obj = NULL;
2272         result = ns_config_get(maps, "edns-udp-size", &obj);
2273         INSIST(result == ISC_R_SUCCESS);
2274         udpsize = cfg_obj_asuint32(obj);
2275         if (udpsize < 512)
2276                 udpsize = 512;
2277         if (udpsize > 4096)
2278                 udpsize = 4096;
2279         ns_g_udpsize = (isc_uint16_t)udpsize;
2280
2281         /*
2282          * Configure the zone manager.
2283          */
2284         obj = NULL;
2285         result = ns_config_get(maps, "transfers-in", &obj);
2286         INSIST(result == ISC_R_SUCCESS);
2287         dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
2288
2289         obj = NULL;
2290         result = ns_config_get(maps, "transfers-per-ns", &obj);
2291         INSIST(result == ISC_R_SUCCESS);
2292         dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
2293
2294         obj = NULL;
2295         result = ns_config_get(maps, "serial-query-rate", &obj);
2296         INSIST(result == ISC_R_SUCCESS);
2297         dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
2298
2299         /*
2300          * Determine which port to use for listening for incoming connections.
2301          */
2302         if (ns_g_port != 0)
2303                 listen_port = ns_g_port;
2304         else
2305                 CHECKM(ns_config_getport(config, &listen_port), "port");
2306
2307         /*
2308          * Find the listen queue depth.
2309          */
2310         obj = NULL;
2311         result = ns_config_get(maps, "tcp-listen-queue", &obj);
2312         INSIST(result == ISC_R_SUCCESS);
2313         ns_g_listen = cfg_obj_asuint32(obj);
2314         if (ns_g_listen < 3)
2315                 ns_g_listen = 3;
2316
2317         /*
2318          * Configure the interface manager according to the "listen-on"
2319          * statement.
2320          */
2321         {
2322                 cfg_obj_t *clistenon = NULL;
2323                 ns_listenlist_t *listenon = NULL;
2324
2325                 clistenon = NULL;
2326                 /*
2327                  * Even though listen-on is present in the default
2328                  * configuration, we can't use it here, since it isn't
2329                  * used if we're in lwresd mode.  This way is easier.
2330                  */
2331                 if (options != NULL)
2332                         (void)cfg_map_get(options, "listen-on", &clistenon);
2333                 if (clistenon != NULL) {
2334                         result = ns_listenlist_fromconfig(clistenon,
2335                                                           config,
2336                                                           &aclconfctx,
2337                                                           ns_g_mctx,
2338                                                           &listenon);
2339                 } else if (!ns_g_lwresdonly) {
2340                         /*
2341                          * Not specified, use default.
2342                          */
2343                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
2344                                                     ISC_TRUE, &listenon));
2345                 }
2346                 if (listenon != NULL) {
2347                         ns_interfacemgr_setlistenon4(server->interfacemgr,
2348                                                      listenon);
2349                         ns_listenlist_detach(&listenon);
2350                 }
2351         }
2352         /*
2353          * Ditto for IPv6.
2354          */
2355         {
2356                 cfg_obj_t *clistenon = NULL;
2357                 ns_listenlist_t *listenon = NULL;
2358
2359                 if (options != NULL)
2360                         (void)cfg_map_get(options, "listen-on-v6", &clistenon);
2361                 if (clistenon != NULL) {
2362                         result = ns_listenlist_fromconfig(clistenon,
2363                                                           config,
2364                                                           &aclconfctx,
2365                                                           ns_g_mctx,
2366                                                           &listenon);
2367                 } else if (!ns_g_lwresdonly) {
2368                         /*
2369                          * Not specified, use default.
2370                          */
2371                         CHECK(ns_listenlist_default(ns_g_mctx, listen_port,
2372                                                     ISC_FALSE, &listenon));
2373                 }
2374                 if (listenon != NULL) {
2375                         ns_interfacemgr_setlistenon6(server->interfacemgr,
2376                                                      listenon);
2377                         ns_listenlist_detach(&listenon);
2378                 }
2379         }
2380
2381         /*
2382          * Rescan the interface list to pick up changes in the
2383          * listen-on option.  It's important that we do this before we try
2384          * to configure the query source, since the dispatcher we use might
2385          * be shared with an interface.
2386          */
2387         scan_interfaces(server, ISC_TRUE);
2388
2389         /*
2390          * Arrange for further interface scanning to occur periodically
2391          * as specified by the "interface-interval" option.
2392          */
2393         obj = NULL;
2394         result = ns_config_get(maps, "interface-interval", &obj);
2395         INSIST(result == ISC_R_SUCCESS);
2396         interface_interval = cfg_obj_asuint32(obj) * 60;
2397         if (interface_interval == 0) {
2398                 CHECK(isc_timer_reset(server->interface_timer,
2399                                       isc_timertype_inactive,
2400                                       NULL, NULL, ISC_TRUE));
2401         } else if (server->interface_interval != interface_interval) {
2402                 isc_interval_t interval;
2403                 isc_interval_set(&interval, interface_interval, 0);
2404                 CHECK(isc_timer_reset(server->interface_timer,
2405                                       isc_timertype_ticker,
2406                                       NULL, &interval, ISC_FALSE));
2407         }
2408         server->interface_interval = interface_interval;
2409
2410         /*
2411          * Configure the dialup heartbeat timer.
2412          */
2413         obj = NULL;
2414         result = ns_config_get(maps, "heartbeat-interval", &obj);
2415         INSIST(result == ISC_R_SUCCESS);
2416         heartbeat_interval = cfg_obj_asuint32(obj) * 60;
2417         if (heartbeat_interval == 0) {
2418                 CHECK(isc_timer_reset(server->heartbeat_timer,
2419                                       isc_timertype_inactive,
2420                                       NULL, NULL, ISC_TRUE));
2421         } else if (server->heartbeat_interval != heartbeat_interval) {
2422                 isc_interval_t interval;
2423                 isc_interval_set(&interval, heartbeat_interval, 0);
2424                 CHECK(isc_timer_reset(server->heartbeat_timer,
2425                                       isc_timertype_ticker,
2426                                       NULL, &interval, ISC_FALSE));
2427         }
2428         server->heartbeat_interval = heartbeat_interval;
2429
2430         /*
2431          * Configure and freeze all explicit views.  Explicit
2432          * views that have zones were already created at parsing
2433          * time, but views with no zones must be created here.
2434          */
2435         views = NULL;
2436         (void)cfg_map_get(config, "view", &views);
2437         for (element = cfg_list_first(views);
2438              element != NULL;
2439              element = cfg_list_next(element))
2440         {
2441                 cfg_obj_t *vconfig = cfg_listelt_value(element);
2442                 view = NULL;
2443
2444                 CHECK(create_view(vconfig, &viewlist, &view));
2445                 INSIST(view != NULL);
2446                 CHECK(configure_view(view, config, vconfig,
2447                                      ns_g_mctx, &aclconfctx, ISC_TRUE));
2448                 dns_view_freeze(view);
2449                 dns_view_detach(&view);
2450         }
2451
2452         /*
2453          * Make sure we have a default view if and only if there
2454          * were no explicit views.
2455          */
2456         if (views == NULL) {
2457                 /*
2458                  * No explicit views; there ought to be a default view.
2459                  * There may already be one created as a side effect
2460                  * of zone statements, or we may have to create one.
2461                  * In either case, we need to configure and freeze it.
2462                  */
2463                 CHECK(create_view(NULL, &viewlist, &view));
2464                 CHECK(configure_view(view, config, NULL, ns_g_mctx,
2465                                      &aclconfctx, ISC_TRUE));
2466                 dns_view_freeze(view);
2467                 dns_view_detach(&view);
2468         }
2469
2470         /*
2471          * Create (or recreate) the built-in views.  Currently
2472          * there is only one, the _bind view.
2473          */
2474         builtin_views = NULL;
2475         RUNTIME_CHECK(cfg_map_get(ns_g_config, "view",
2476                                   &builtin_views) == ISC_R_SUCCESS);
2477         for (element = cfg_list_first(builtin_views);
2478              element != NULL;
2479              element = cfg_list_next(element))
2480         {
2481                 cfg_obj_t *vconfig = cfg_listelt_value(element);
2482                 CHECK(create_view(vconfig, &viewlist, &view));
2483                 CHECK(configure_view(view, config, vconfig, ns_g_mctx,
2484                                      &aclconfctx, ISC_FALSE));
2485                 dns_view_freeze(view);
2486                 dns_view_detach(&view);
2487                 view = NULL;
2488         }
2489
2490         /*
2491          * Swap our new view list with the production one.
2492          */
2493         tmpviewlist = server->viewlist;
2494         server->viewlist = viewlist;
2495         viewlist = tmpviewlist;
2496
2497         /*
2498          * Load the TKEY information from the configuration.
2499          */
2500         if (options != NULL) {
2501                 dns_tkeyctx_t *t = NULL;
2502                 CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy,
2503                                              &t),
2504                        "configuring TKEY");
2505                 if (server->tkeyctx != NULL)
2506                         dns_tkeyctx_destroy(&server->tkeyctx);
2507                 server->tkeyctx = t;
2508         }
2509
2510         /*
2511          * Bind the control port(s).
2512          */
2513         CHECKM(ns_controls_configure(ns_g_server->controls, config,
2514                                      &aclconfctx),
2515                "binding control channel(s)");
2516
2517         /*
2518          * Bind the lwresd port(s).
2519          */
2520         CHECKM(ns_lwresd_configure(ns_g_mctx, config),
2521                "binding lightweight resolver ports");
2522
2523         /*
2524          * Open the source of entropy.
2525          */
2526         if (first_time) {
2527                 obj = NULL;
2528                 result = ns_config_get(maps, "random-device", &obj);
2529                 if (result != ISC_R_SUCCESS) {
2530                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2531                                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
2532                                       "no source of entropy found");
2533                 } else {
2534                         const char *randomdev = cfg_obj_asstring(obj);
2535                         result = isc_entropy_createfilesource(ns_g_entropy,
2536                                                               randomdev);
2537                         if (result != ISC_R_SUCCESS)
2538                                 isc_log_write(ns_g_lctx,
2539                                               NS_LOGCATEGORY_GENERAL,
2540                                               NS_LOGMODULE_SERVER,
2541                                               ISC_LOG_INFO,
2542                                               "could not open entropy source "
2543                                               "%s: %s",
2544                                               randomdev,
2545                                               isc_result_totext(result));
2546 #ifdef PATH_RANDOMDEV
2547                         if (ns_g_fallbackentropy != NULL) {
2548                                 if (result != ISC_R_SUCCESS) {
2549                                         isc_log_write(ns_g_lctx,
2550                                                       NS_LOGCATEGORY_GENERAL,
2551                                                       NS_LOGMODULE_SERVER,
2552                                                       ISC_LOG_INFO,
2553                                                       "using pre-chroot entropy source "
2554                                                       "%s",
2555                                                       PATH_RANDOMDEV);
2556                                         isc_entropy_detach(&ns_g_entropy);
2557                                         isc_entropy_attach(ns_g_fallbackentropy,
2558                                                            &ns_g_entropy);
2559                                 }
2560                                 isc_entropy_detach(&ns_g_fallbackentropy);
2561                         }
2562 #endif
2563                 }
2564         }
2565
2566         /*
2567          * Relinquish root privileges.
2568          */
2569         if (first_time)
2570                 ns_os_changeuser();
2571
2572         /*
2573          * Configure the logging system.
2574          *
2575          * Do this after changing UID to make sure that any log
2576          * files specified in named.conf get created by the
2577          * unprivileged user, not root.
2578          */
2579         if (ns_g_logstderr) {
2580                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2581                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
2582                               "ignoring config file logging "
2583                               "statement due to -g option");
2584         } else {
2585                 cfg_obj_t *logobj = NULL;
2586                 isc_logconfig_t *logc = NULL;
2587
2588                 CHECKM(isc_logconfig_create(ns_g_lctx, &logc),
2589                        "creating new logging configuration");
2590
2591                 logobj = NULL;
2592                 (void)cfg_map_get(config, "logging", &logobj);
2593                 if (logobj != NULL) {
2594                         CHECKM(ns_log_configure(logc, logobj),
2595                                "configuring logging");
2596                 } else {
2597                         CHECKM(ns_log_setdefaultchannels(logc),
2598                                "setting up default logging channels");
2599                         CHECKM(ns_log_setunmatchedcategory(logc),
2600                                "setting up default 'category unmatched'");
2601                         CHECKM(ns_log_setdefaultcategory(logc),
2602                                "setting up default 'category default'");
2603                 }
2604
2605                 result = isc_logconfig_use(ns_g_lctx, logc);
2606                 if (result != ISC_R_SUCCESS) {
2607                         isc_logconfig_destroy(&logc);
2608                         CHECKM(result, "installing logging configuration");
2609                 }
2610
2611                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
2612                               NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
2613                               "now using logging configuration from "
2614                               "config file");
2615         }
2616
2617         /*
2618          * Set the default value of the query logging flag depending
2619          * whether a "queries" category has been defined.  This is
2620          * a disgusting hack, but we need to do this for BIND 8
2621          * compatibility.
2622          */
2623         if (first_time) {
2624                 cfg_obj_t *logobj = NULL;
2625                 cfg_obj_t *categories = NULL;
2626
2627                 obj = NULL;
2628                 if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
2629                         server->log_queries = cfg_obj_asboolean(obj);
2630                 } else {
2631
2632                         (void)cfg_map_get(config, "logging", &logobj);
2633                         if (logobj != NULL)
2634                                 (void)cfg_map_get(logobj, "category",
2635                                                   &categories);
2636                         if (categories != NULL) {
2637                                 cfg_listelt_t *element;
2638                                 for (element = cfg_list_first(categories);
2639                                      element != NULL;
2640                                      element = cfg_list_next(element))
2641                                 {
2642                                         cfg_obj_t *catobj;
2643                                         char *str;
2644
2645                                         obj = cfg_listelt_value(element);
2646                                         catobj = cfg_tuple_get(obj, "name");
2647                                         str = cfg_obj_asstring(catobj);
2648                                         if (strcasecmp(str, "queries") == 0)
2649                                                 server->log_queries = ISC_TRUE;
2650                                 }
2651                         }
2652                 }
2653         }
2654
2655         obj = NULL;
2656         if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS)
2657                 if (cfg_obj_isvoid(obj))
2658                         ns_os_writepidfile(NULL, first_time);
2659                 else
2660                         ns_os_writepidfile(cfg_obj_asstring(obj), first_time);
2661         else if (ns_g_lwresdonly)
2662                 ns_os_writepidfile(lwresd_g_defaultpidfile, first_time);
2663         else
2664                 ns_os_writepidfile(ns_g_defaultpidfile, first_time);
2665         
2666         obj = NULL;
2667         if (options != NULL &&
2668             cfg_map_get(options, "memstatistics-file", &obj) == ISC_R_SUCCESS)
2669                 ns_main_setmemstats(cfg_obj_asstring(obj));
2670         else
2671                 ns_main_setmemstats(NULL);
2672
2673         obj = NULL;
2674         result = ns_config_get(maps, "statistics-file", &obj);
2675         INSIST(result == ISC_R_SUCCESS);
2676         CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
2677                "strdup");
2678
2679         obj = NULL;
2680         result = ns_config_get(maps, "dump-file", &obj);
2681         INSIST(result == ISC_R_SUCCESS);
2682         CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
2683                "strdup");
2684
2685         obj = NULL;
2686         result = ns_config_get(maps, "recursing-file", &obj);
2687         INSIST(result == ISC_R_SUCCESS);
2688         CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
2689                "strdup");
2690
2691         obj = NULL;
2692         result = ns_config_get(maps, "version", &obj);
2693         if (result == ISC_R_SUCCESS) {
2694                 CHECKM(setoptstring(server, &server->version, obj), "strdup");
2695                 server->version_set = ISC_TRUE;
2696         } else {
2697                 server->version_set = ISC_FALSE;
2698         }
2699
2700         obj = NULL;
2701         result = ns_config_get(maps, "hostname", &obj);
2702         if (result == ISC_R_SUCCESS) {
2703                 CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
2704                 server->hostname_set = ISC_TRUE;
2705         } else {
2706                 server->hostname_set = ISC_FALSE;
2707         }
2708
2709         obj = NULL;
2710         result = ns_config_get(maps, "server-id", &obj);
2711         server->server_usehostname = ISC_FALSE;
2712         if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
2713                 server->server_usehostname = ISC_TRUE;
2714         } else if (result == ISC_R_SUCCESS) {
2715                 CHECKM(setoptstring(server, &server->server_id, obj), "strdup");
2716         } else {
2717                 result = setoptstring(server, &server->server_id, NULL);
2718                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2719         }
2720
2721         obj = NULL;
2722         result = ns_config_get(maps, "flush-zones-on-shutdown", &obj);
2723         if (result == ISC_R_SUCCESS) {
2724                 server->flushonshutdown = cfg_obj_asboolean(obj);
2725         } else {
2726                 server->flushonshutdown = ISC_FALSE;
2727         }
2728
2729         result = ISC_R_SUCCESS;
2730
2731  cleanup:
2732         ns_aclconfctx_destroy(&aclconfctx);
2733
2734         if (parser != NULL) {
2735                 if (config != NULL)
2736                         cfg_obj_destroy(parser, &config);
2737                 cfg_parser_destroy(&parser);
2738         }
2739
2740         if (view != NULL)
2741                 dns_view_detach(&view);
2742
2743         /*
2744          * This cleans up either the old production view list
2745          * or our temporary list depending on whether they
2746          * were swapped above or not.
2747          */
2748         for (view = ISC_LIST_HEAD(viewlist);
2749              view != NULL;
2750              view = view_next) {
2751                 view_next = ISC_LIST_NEXT(view, link);
2752                 ISC_LIST_UNLINK(viewlist, view, link);
2753                 dns_view_detach(&view);
2754
2755         }
2756
2757         /*
2758          * Adjust the listening interfaces in accordance with the source
2759          * addresses specified in views and zones.
2760          */
2761         if (isc_net_probeipv6() == ISC_R_SUCCESS)
2762                 adjust_interfaces(server, ns_g_mctx);
2763
2764         /* Relinquish exclusive access to configuration data. */
2765         isc_task_endexclusive(server->task);
2766
2767         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2768                       ISC_LOG_DEBUG(1), "load_configuration: %s",
2769                       isc_result_totext(result));
2770
2771         return (result);
2772 }
2773
2774 static isc_result_t
2775 load_zones(ns_server_t *server, isc_boolean_t stop) {
2776         isc_result_t result;
2777         dns_view_t *view;
2778
2779         result = isc_task_beginexclusive(server->task);
2780         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2781
2782         /*
2783          * Load zone data from disk.
2784          */
2785         for (view = ISC_LIST_HEAD(server->viewlist);
2786              view != NULL;
2787              view = ISC_LIST_NEXT(view, link))
2788         {
2789                 CHECK(dns_view_load(view, stop));
2790         }
2791
2792         /*
2793          * Force zone maintenance.  Do this after loading
2794          * so that we know when we need to force AXFR of
2795          * slave zones whose master files are missing.
2796          */
2797         CHECK(dns_zonemgr_forcemaint(server->zonemgr));
2798  cleanup:
2799         isc_task_endexclusive(server->task);    
2800         return (result);
2801 }
2802
2803 static isc_result_t
2804 load_new_zones(ns_server_t *server, isc_boolean_t stop) {
2805         isc_result_t result;
2806         dns_view_t *view;
2807
2808         result = isc_task_beginexclusive(server->task);
2809         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2810
2811         /*
2812          * Load zone data from disk.
2813          */
2814         for (view = ISC_LIST_HEAD(server->viewlist);
2815              view != NULL;
2816              view = ISC_LIST_NEXT(view, link))
2817         {
2818                 CHECK(dns_view_loadnew(view, stop));
2819         }
2820         /*
2821          * Force zone maintenance.  Do this after loading
2822          * so that we know when we need to force AXFR of
2823          * slave zones whose master files are missing.
2824          */
2825         dns_zonemgr_resumexfrs(server->zonemgr);
2826  cleanup:
2827         isc_task_endexclusive(server->task);    
2828         return (result);
2829 }
2830
2831 static void
2832 run_server(isc_task_t *task, isc_event_t *event) {
2833         isc_result_t result;
2834         ns_server_t *server = (ns_server_t *)event->ev_arg;
2835
2836         INSIST(task == server->task);
2837
2838         isc_event_free(&event);
2839
2840         CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy,
2841                                           &ns_g_dispatchmgr),
2842                    "creating dispatch manager");
2843
2844         CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
2845                                           ns_g_socketmgr, ns_g_dispatchmgr,
2846                                           &server->interfacemgr),
2847                    "creating interface manager");
2848
2849         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
2850                                     NULL, NULL, server->task,
2851                                     interface_timer_tick,
2852                                     server, &server->interface_timer),
2853                    "creating interface timer");
2854
2855         CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
2856                                     NULL, NULL, server->task,
2857                                     heartbeat_timer_tick,
2858                                     server, &server->heartbeat_timer),
2859                    "creating heartbeat timer");
2860
2861         CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser),
2862                    "creating default configuration parser");
2863
2864         if (ns_g_lwresdonly)
2865                 CHECKFATAL(load_configuration(lwresd_g_conffile, server,
2866                                               ISC_TRUE),
2867                            "loading configuration");
2868         else
2869                 CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE),
2870                            "loading configuration");
2871
2872         isc_hash_init();
2873
2874         CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones");
2875
2876         ns_os_started();
2877         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2878                       ISC_LOG_NOTICE, "running");
2879 }
2880
2881 void 
2882 ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) {
2883
2884         REQUIRE(NS_SERVER_VALID(server));
2885
2886         server->flushonshutdown = flush;
2887 }
2888
2889 static void
2890 shutdown_server(isc_task_t *task, isc_event_t *event) {
2891         isc_result_t result;
2892         dns_view_t *view, *view_next;
2893         ns_server_t *server = (ns_server_t *)event->ev_arg;
2894         isc_boolean_t flush = server->flushonshutdown;
2895
2896         UNUSED(task);
2897         INSIST(task == server->task);
2898
2899         result = isc_task_beginexclusive(server->task);
2900         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2901
2902         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
2903                       ISC_LOG_INFO, "shutting down%s",
2904                       flush ? ": flushing changes" : "");
2905
2906         ns_controls_shutdown(server->controls);
2907         end_reserved_dispatches(server, ISC_TRUE);
2908
2909         cfg_obj_destroy(ns_g_parser, &ns_g_config);
2910         cfg_parser_destroy(&ns_g_parser);
2911
2912         for (view = ISC_LIST_HEAD(server->viewlist);
2913              view != NULL;
2914              view = view_next) {
2915                 view_next = ISC_LIST_NEXT(view, link);
2916                 ISC_LIST_UNLINK(server->viewlist, view, link);
2917                 if (flush)
2918                         dns_view_flushanddetach(&view);
2919                 else
2920                         dns_view_detach(&view);
2921         }
2922
2923         isc_timer_detach(&server->interface_timer);
2924         isc_timer_detach(&server->heartbeat_timer);
2925
2926         ns_interfacemgr_shutdown(server->interfacemgr);
2927         ns_interfacemgr_detach(&server->interfacemgr);
2928
2929         dns_dispatchmgr_destroy(&ns_g_dispatchmgr);
2930
2931         dns_zonemgr_shutdown(server->zonemgr);
2932
2933         if (server->blackholeacl != NULL)
2934                 dns_acl_detach(&server->blackholeacl);
2935
2936         dns_db_detach(&server->in_roothints);
2937
2938         isc_task_endexclusive(server->task);
2939
2940         isc_task_detach(&server->task);
2941
2942         isc_event_free(&event);
2943 }
2944
2945 void
2946 ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
2947         isc_result_t result;
2948
2949         ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
2950         if (server == NULL)
2951                 fatal("allocating server object", ISC_R_NOMEMORY);
2952
2953         server->mctx = mctx;
2954         server->task = NULL;
2955
2956         /* Initialize configuration data with default values. */
2957
2958         result = isc_quota_init(&server->xfroutquota, 10);
2959         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2960         result = isc_quota_init(&server->tcpquota, 10);
2961         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2962         result = isc_quota_init(&server->recursionquota, 100);
2963         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2964
2965         result = dns_aclenv_init(mctx, &server->aclenv);
2966         RUNTIME_CHECK(result == ISC_R_SUCCESS);
2967
2968         /* Initialize server data structures. */
2969         server->zonemgr = NULL;
2970         server->interfacemgr = NULL;
2971         ISC_LIST_INIT(server->viewlist);
2972         server->in_roothints = NULL;
2973         server->blackholeacl = NULL;
2974
2975         CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
2976                                      &server->in_roothints),
2977                    "setting up root hints");
2978
2979         CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
2980                    "initializing reload event lock");
2981         server->reload_event =
2982                 isc_event_allocate(ns_g_mctx, server,
2983                                    NS_EVENT_RELOAD,
2984                                    ns_server_reload,
2985                                    server,
2986                                    sizeof(isc_event_t));
2987         CHECKFATAL(server->reload_event == NULL ?
2988                    ISC_R_NOMEMORY : ISC_R_SUCCESS,
2989                    "allocating reload event");
2990
2991         CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY),
2992                    "initializing DST");
2993
2994         server->tkeyctx = NULL;
2995         CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
2996                                       &server->tkeyctx),
2997                    "creating TKEY context");
2998
2999         /*
3000          * Setup the server task, which is responsible for coordinating
3001          * startup and shutdown of the server.
3002          */
3003         CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
3004                    "creating server task");
3005         isc_task_setname(server->task, "server", server);
3006         CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
3007                    "isc_task_onshutdown");
3008         CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
3009                    "isc_app_onrun");
3010
3011         server->interface_timer = NULL;
3012         server->heartbeat_timer = NULL;
3013         
3014         server->interface_interval = 0;
3015         server->heartbeat_interval = 0;
3016
3017         CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
3018                                       ns_g_socketmgr, &server->zonemgr),
3019                    "dns_zonemgr_create");
3020
3021         server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
3022         CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3023                    "isc_mem_strdup");
3024         server->querystats = NULL;
3025
3026         server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
3027         CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3028                    "isc_mem_strdup");
3029
3030         server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
3031         CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3032                    "isc_mem_strdup");
3033
3034         server->hostname_set = ISC_FALSE;
3035         server->hostname = NULL;
3036         server->version_set = ISC_FALSE;        
3037         server->version = NULL;
3038         server->server_usehostname = ISC_FALSE;
3039         server->server_id = NULL;
3040
3041         CHECKFATAL(dns_stats_alloccounters(ns_g_mctx, &server->querystats),
3042                    "dns_stats_alloccounters");
3043
3044         server->flushonshutdown = ISC_FALSE;
3045         server->log_queries = ISC_FALSE;
3046
3047         server->controls = NULL;
3048         CHECKFATAL(ns_controls_create(server, &server->controls),
3049                    "ns_controls_create");
3050         server->dispatchgen = 0;
3051         ISC_LIST_INIT(server->dispatches);
3052
3053         server->magic = NS_SERVER_MAGIC;
3054         *serverp = server;
3055 }
3056
3057 void
3058 ns_server_destroy(ns_server_t **serverp) {
3059         ns_server_t *server = *serverp;
3060         REQUIRE(NS_SERVER_VALID(server));
3061
3062         ns_controls_destroy(&server->controls);
3063
3064         dns_stats_freecounters(server->mctx, &server->querystats);
3065
3066         isc_mem_free(server->mctx, server->statsfile);
3067         isc_mem_free(server->mctx, server->dumpfile);
3068         isc_mem_free(server->mctx, server->recfile);
3069
3070         if (server->version != NULL)
3071                 isc_mem_free(server->mctx, server->version);
3072         if (server->hostname != NULL)
3073                 isc_mem_free(server->mctx, server->hostname);
3074         if (server->server_id != NULL)
3075                 isc_mem_free(server->mctx, server->server_id);
3076
3077         dns_zonemgr_detach(&server->zonemgr);
3078
3079         if (server->tkeyctx != NULL)
3080                 dns_tkeyctx_destroy(&server->tkeyctx);
3081
3082         dst_lib_destroy();
3083
3084         isc_event_free(&server->reload_event);
3085
3086         INSIST(ISC_LIST_EMPTY(server->viewlist));
3087
3088         dns_aclenv_destroy(&server->aclenv);
3089
3090         isc_quota_destroy(&server->recursionquota);
3091         isc_quota_destroy(&server->tcpquota);
3092         isc_quota_destroy(&server->xfroutquota);
3093
3094         server->magic = 0;
3095         isc_mem_put(server->mctx, server, sizeof(*server));
3096         *serverp = NULL;
3097 }
3098
3099 static void
3100 fatal(const char *msg, isc_result_t result) {
3101         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3102                       ISC_LOG_CRITICAL, "%s: %s", msg,
3103                       isc_result_totext(result));
3104         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
3105                       ISC_LOG_CRITICAL, "exiting (due to fatal error)");
3106         exit(1);
3107 }
3108
3109 static void
3110 start_reserved_dispatches(ns_server_t *server) {
3111
3112         REQUIRE(NS_SERVER_VALID(server));
3113
3114         server->dispatchgen++;
3115 }
3116
3117 static void
3118 end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) {
3119         ns_dispatch_t *dispatch, *nextdispatch;
3120
3121         REQUIRE(NS_SERVER_VALID(server));
3122
3123         for (dispatch = ISC_LIST_HEAD(server->dispatches);
3124              dispatch != NULL;
3125              dispatch = nextdispatch) {
3126                 nextdispatch = ISC_LIST_NEXT(dispatch, link);
3127                 if (!all && server->dispatchgen == dispatch-> dispatchgen)
3128                         continue;
3129                 ISC_LIST_UNLINK(server->dispatches, dispatch, link);
3130                 dns_dispatch_detach(&dispatch->dispatch);
3131                 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
3132         }
3133 }
3134
3135 void
3136 ns_add_reserved_dispatch(ns_server_t *server, isc_sockaddr_t *addr) {
3137         ns_dispatch_t *dispatch;
3138         in_port_t port;
3139         char addrbuf[ISC_SOCKADDR_FORMATSIZE];
3140         isc_result_t result;
3141         unsigned int attrs, attrmask;
3142
3143         REQUIRE(NS_SERVER_VALID(server));
3144
3145         port = isc_sockaddr_getport(addr);
3146         if (port == 0 || port >= 1024)
3147                 return;
3148
3149         for (dispatch = ISC_LIST_HEAD(server->dispatches);
3150              dispatch != NULL;
3151              dispatch = ISC_LIST_NEXT(dispatch, link)) {
3152                 if (isc_sockaddr_equal(&dispatch->addr, addr))
3153                         break;
3154         }
3155         if (dispatch != NULL) {
3156                 dispatch->dispatchgen = server->dispatchgen;
3157                 return;
3158         }
3159
3160         dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
3161         if (dispatch == NULL) {
3162                 result = ISC_R_NOMEMORY;
3163                 goto cleanup;
3164         }
3165
3166         dispatch->addr = *addr;
3167         dispatch->dispatchgen = server->dispatchgen;
3168         dispatch->dispatch = NULL;
3169
3170         attrs = 0;
3171         attrs |= DNS_DISPATCHATTR_UDP;
3172         switch (isc_sockaddr_pf(addr)) {
3173         case AF_INET:
3174                 attrs |= DNS_DISPATCHATTR_IPV4;
3175                 break;
3176         case AF_INET6:
3177                 attrs |= DNS_DISPATCHATTR_IPV6;
3178                 break;
3179         default:
3180                 result = ISC_R_NOTIMPLEMENTED;
3181                 goto cleanup;
3182         }
3183         attrmask = 0;
3184         attrmask |= DNS_DISPATCHATTR_UDP;
3185         attrmask |= DNS_DISPATCHATTR_TCP;
3186         attrmask |= DNS_DISPATCHATTR_IPV4;
3187         attrmask |= DNS_DISPATCHATTR_IPV6;
3188
3189         result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
3190                                      ns_g_taskmgr, &dispatch->addr, 4096,
3191                                      1000, 32768, 16411, 16433,
3192                                      attrs, attrmask, &dispatch->dispatch); 
3193         if (result != ISC_R_SUCCESS)
3194                 goto cleanup;
3195
3196         ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
3197
3198         return;
3199
3200  cleanup:
3201         if (dispatch != NULL)
3202                 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
3203         isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
3204         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3205                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
3206                       "unable to create dispatch for reserved port %s: %s",
3207                       addrbuf, isc_result_totext(result));
3208 }
3209
3210
3211 static isc_result_t
3212 loadconfig(ns_server_t *server) {
3213         isc_result_t result;
3214         start_reserved_dispatches(server);
3215         result = load_configuration(ns_g_lwresdonly ?
3216                                     lwresd_g_conffile : ns_g_conffile,
3217                                     server, ISC_FALSE);
3218         if (result == ISC_R_SUCCESS)
3219                 end_reserved_dispatches(server, ISC_FALSE);
3220         else
3221                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3222                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3223                               "reloading configuration failed: %s",
3224                               isc_result_totext(result));
3225         return (result);
3226 }
3227
3228 static isc_result_t
3229 reload(ns_server_t *server) {
3230         isc_result_t result;
3231         CHECK(loadconfig(server));
3232
3233         result = load_zones(server, ISC_FALSE);
3234         if (result != ISC_R_SUCCESS) {
3235                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3236                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3237                               "reloading zones failed: %s",
3238                               isc_result_totext(result));
3239         }
3240  cleanup:
3241         return (result);
3242 }
3243
3244 static void
3245 reconfig(ns_server_t *server) {
3246         isc_result_t result;
3247         CHECK(loadconfig(server));
3248
3249         result = load_new_zones(server, ISC_FALSE);
3250         if (result != ISC_R_SUCCESS) {
3251                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3252                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
3253                               "loading new zones failed: %s",
3254                               isc_result_totext(result));
3255         }
3256  cleanup: ;
3257 }
3258
3259 /*
3260  * Handle a reload event (from SIGHUP).
3261  */
3262 static void
3263 ns_server_reload(isc_task_t *task, isc_event_t *event) {
3264         ns_server_t *server = (ns_server_t *)event->ev_arg;
3265
3266         INSIST(task = server->task);
3267         UNUSED(task);
3268
3269         (void)reload(server);
3270
3271         LOCK(&server->reload_event_lock);
3272         INSIST(server->reload_event == NULL);
3273         server->reload_event = event;
3274         UNLOCK(&server->reload_event_lock);
3275 }
3276
3277 void
3278 ns_server_reloadwanted(ns_server_t *server) {
3279         LOCK(&server->reload_event_lock);
3280         if (server->reload_event != NULL)
3281                 isc_task_send(server->task, &server->reload_event);
3282         UNLOCK(&server->reload_event_lock);
3283 }
3284
3285 static char *
3286 next_token(char **stringp, const char *delim) {
3287         char *res;
3288
3289         do {
3290                 res = strsep(stringp, delim);
3291                 if (res == NULL)
3292                         break;
3293         } while (*res == '\0');
3294         return (res);
3295 }                       
3296
3297 /*
3298  * Find the zone specified in the control channel command 'args',
3299  * if any.  If a zone is specified, point '*zonep' at it, otherwise
3300  * set '*zonep' to NULL.
3301  */
3302 static isc_result_t
3303 zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) {
3304         char *input, *ptr;
3305         const char *zonetxt;
3306         char *classtxt;
3307         const char *viewtxt = NULL;
3308         dns_fixedname_t name;
3309         isc_result_t result;
3310         isc_buffer_t buf;
3311         dns_view_t *view = NULL;
3312         dns_rdataclass_t rdclass;
3313
3314         REQUIRE(zonep != NULL && *zonep == NULL);
3315
3316         input = args;
3317
3318         /* Skip the command name. */
3319         ptr = next_token(&input, " \t");
3320         if (ptr == NULL)
3321                 return (ISC_R_UNEXPECTEDEND);
3322
3323         /* Look for the zone name. */
3324         zonetxt = next_token(&input, " \t");
3325         if (zonetxt == NULL)
3326                 return (ISC_R_SUCCESS);
3327
3328         /* Look for the optional class name. */
3329         classtxt = next_token(&input, " \t");
3330         if (classtxt != NULL) {
3331                 /* Look for the optional view name. */
3332                 viewtxt = next_token(&input, " \t");
3333         }
3334
3335         isc_buffer_init(&buf, zonetxt, strlen(zonetxt));
3336         isc_buffer_add(&buf, strlen(zonetxt));
3337         dns_fixedname_init(&name);
3338         result = dns_name_fromtext(dns_fixedname_name(&name),
3339                                    &buf, dns_rootname, ISC_FALSE, NULL);
3340         if (result != ISC_R_SUCCESS)
3341                 goto fail1;
3342
3343         if (classtxt != NULL) {
3344                 isc_textregion_t r;
3345                 r.base = classtxt;
3346                 r.length = strlen(classtxt);
3347                 result = dns_rdataclass_fromtext(&rdclass, &r);
3348                 if (result != ISC_R_SUCCESS)
3349                         goto fail1;
3350         } else {
3351                 rdclass = dns_rdataclass_in;
3352         }
3353         
3354         if (viewtxt == NULL)
3355                 viewtxt = "_default";
3356         result = dns_viewlist_find(&server->viewlist, viewtxt,
3357                                    rdclass, &view);
3358         if (result != ISC_R_SUCCESS)
3359                 goto fail1;
3360         
3361         result = dns_zt_find(view->zonetable, dns_fixedname_name(&name),
3362                              0, NULL, zonep);
3363         /* Partial match? */
3364         if (result != ISC_R_SUCCESS && *zonep != NULL)
3365                 dns_zone_detach(zonep);
3366         dns_view_detach(&view);
3367  fail1:
3368         return (result);
3369 }
3370
3371 /*
3372  * Act on a "retransfer" command from the command channel.
3373  */
3374 isc_result_t
3375 ns_server_retransfercommand(ns_server_t *server, char *args) {
3376         isc_result_t result;
3377         dns_zone_t *zone = NULL;
3378         dns_zonetype_t type;
3379         
3380         result = zone_from_args(server, args, &zone);
3381         if (result != ISC_R_SUCCESS)
3382                 return (result);
3383         if (zone == NULL)
3384                 return (ISC_R_UNEXPECTEDEND);
3385         type = dns_zone_gettype(zone);
3386         if (type == dns_zone_slave || type == dns_zone_stub)
3387                 dns_zone_forcereload(zone);
3388         else
3389                 result = ISC_R_NOTFOUND;
3390         dns_zone_detach(&zone);
3391         return (result);
3392 }       
3393
3394 /*
3395  * Act on a "reload" command from the command channel.
3396  */
3397 isc_result_t
3398 ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
3399         isc_result_t result;
3400         dns_zone_t *zone = NULL;
3401         dns_zonetype_t type;
3402         const char *msg = NULL;
3403         
3404         result = zone_from_args(server, args, &zone);
3405         if (result != ISC_R_SUCCESS)
3406                 return (result);
3407         if (zone == NULL) {
3408                 result = reload(server);
3409                 if (result == ISC_R_SUCCESS)
3410                         msg = "server reload successful";
3411         } else {
3412                 type = dns_zone_gettype(zone);
3413                 if (type == dns_zone_slave || type == dns_zone_stub) {
3414                         dns_zone_refresh(zone);
3415                         msg = "zone refresh queued";
3416                 } else {
3417                         result = dns_zone_load(zone);
3418                         dns_zone_detach(&zone);
3419                         switch (result) {       
3420                         case ISC_R_SUCCESS:
3421                                  msg = "zone reload successful";
3422                                  break;
3423                         case DNS_R_CONTINUE:
3424                                 msg = "zone reload queued";
3425                                 result = ISC_R_SUCCESS;
3426                                 break;
3427                         case DNS_R_UPTODATE:
3428                                 msg = "zone reload up-to-date";
3429                                 result = ISC_R_SUCCESS;
3430                                 break;
3431                         default:
3432                                 /* failure message will be generated by rndc */
3433                                 break;
3434                         }
3435                 }
3436         }
3437         if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
3438                 isc_buffer_putmem(text, (const unsigned char *)msg,
3439                                   strlen(msg) + 1);
3440         return (result);
3441 }       
3442
3443 /*
3444  * Act on a "reconfig" command from the command channel.
3445  */
3446 isc_result_t
3447 ns_server_reconfigcommand(ns_server_t *server, char *args) {
3448         UNUSED(args);
3449
3450         reconfig(server);
3451         return (ISC_R_SUCCESS);
3452 }
3453
3454 /*
3455  * Act on a "refresh" command from the command channel.
3456  */
3457 isc_result_t
3458 ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) {
3459         isc_result_t result;
3460         dns_zone_t *zone = NULL;
3461         const unsigned char msg[] = "zone refresh queued";
3462
3463         result = zone_from_args(server, args, &zone);
3464         if (result != ISC_R_SUCCESS)
3465                 return (result);
3466         if (zone == NULL)
3467                 return (ISC_R_UNEXPECTEDEND);
3468         
3469         dns_zone_refresh(zone);
3470         dns_zone_detach(&zone);
3471         if (sizeof(msg) <= isc_buffer_availablelength(text))
3472                 isc_buffer_putmem(text, msg, sizeof(msg));
3473
3474         return (ISC_R_SUCCESS);
3475 }       
3476
3477 isc_result_t
3478 ns_server_togglequerylog(ns_server_t *server) {
3479         server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE;
3480         
3481         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3482                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3483                       "query logging is now %s",
3484                       server->log_queries ? "on" : "off");
3485         return (ISC_R_SUCCESS);
3486 }
3487
3488 static isc_result_t
3489 ns_listenlist_fromconfig(cfg_obj_t *listenlist, cfg_obj_t *config,
3490                          ns_aclconfctx_t *actx,
3491                          isc_mem_t *mctx, ns_listenlist_t **target)
3492 {
3493         isc_result_t result;
3494         cfg_listelt_t *element;
3495         ns_listenlist_t *dlist = NULL;
3496
3497         REQUIRE(target != NULL && *target == NULL);
3498
3499         result = ns_listenlist_create(mctx, &dlist);
3500         if (result != ISC_R_SUCCESS)
3501                 return (result);
3502
3503         for (element = cfg_list_first(listenlist);
3504              element != NULL;
3505              element = cfg_list_next(element))
3506         {
3507                 ns_listenelt_t *delt = NULL;
3508                 cfg_obj_t *listener = cfg_listelt_value(element);
3509                 result = ns_listenelt_fromconfig(listener, config, actx,
3510                                                  mctx, &delt);
3511                 if (result != ISC_R_SUCCESS)
3512                         goto cleanup;
3513                 ISC_LIST_APPEND(dlist->elts, delt, link);
3514         }
3515         *target = dlist;
3516         return (ISC_R_SUCCESS);
3517
3518  cleanup:
3519         ns_listenlist_detach(&dlist);
3520         return (result);
3521 }
3522
3523 /*
3524  * Create a listen list from the corresponding configuration
3525  * data structure.
3526  */
3527 static isc_result_t
3528 ns_listenelt_fromconfig(cfg_obj_t *listener, cfg_obj_t *config,
3529                         ns_aclconfctx_t *actx,
3530                         isc_mem_t *mctx, ns_listenelt_t **target)
3531 {
3532         isc_result_t result;
3533         cfg_obj_t *portobj;
3534         in_port_t port;
3535         ns_listenelt_t *delt = NULL;
3536         REQUIRE(target != NULL && *target == NULL);
3537
3538         portobj = cfg_tuple_get(listener, "port");
3539         if (!cfg_obj_isuint32(portobj)) {
3540                 if (ns_g_port != 0) {
3541                         port = ns_g_port;
3542                 } else {
3543                         result = ns_config_getport(config, &port);
3544                         if (result != ISC_R_SUCCESS)
3545                                 return (result);
3546                 }
3547         } else {
3548                 if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
3549                         cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
3550                                     "port value '%u' is out of range",
3551                                     cfg_obj_asuint32(portobj));
3552                         return (ISC_R_RANGE);
3553                 }
3554                 port = (in_port_t)cfg_obj_asuint32(portobj);
3555         }
3556
3557         result = ns_listenelt_create(mctx, port, NULL, &delt);
3558         if (result != ISC_R_SUCCESS)
3559                 return (result);
3560
3561         result = ns_acl_fromconfig(cfg_tuple_get(listener, "acl"),
3562                                    config, actx, mctx, &delt->acl);
3563         if (result != ISC_R_SUCCESS) {
3564                 ns_listenelt_destroy(delt);
3565                 return (result);
3566         }
3567         *target = delt;
3568         return (ISC_R_SUCCESS);
3569 }
3570
3571 isc_result_t
3572 ns_server_dumpstats(ns_server_t *server) {
3573         isc_result_t result;
3574         dns_zone_t *zone, *next;
3575         isc_stdtime_t now;
3576         FILE *fp = NULL;
3577         int i;
3578         int ncounters;
3579
3580         isc_stdtime_get(&now);
3581
3582         CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
3583                 "could not open statistics dump file", server->statsfile);
3584         
3585         ncounters = DNS_STATS_NCOUNTERS;
3586         fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now);
3587         
3588         for (i = 0; i < ncounters; i++)
3589                 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT "u\n",
3590                         dns_statscounter_names[i],
3591                         server->querystats[i]);
3592         
3593         zone = NULL;
3594         for (result = dns_zone_first(server->zonemgr, &zone);
3595              result == ISC_R_SUCCESS;
3596              next = NULL, result = dns_zone_next(zone, &next), zone = next)
3597         {
3598                 isc_uint64_t *zonestats = dns_zone_getstatscounters(zone);
3599                 if (zonestats != NULL) {
3600                         char zonename[DNS_NAME_FORMATSIZE];
3601                         dns_view_t *view;
3602                         char *viewname;
3603                         
3604                         dns_name_format(dns_zone_getorigin(zone),
3605                                         zonename, sizeof(zonename));
3606                         view = dns_zone_getview(zone);
3607                         viewname = view->name;
3608                         for (i = 0; i < ncounters; i++) {
3609                                 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT
3610                                         "u %s",
3611                                         dns_statscounter_names[i],
3612                                         zonestats[i],
3613                                         zonename);
3614                                 if (strcmp(viewname, "_default") != 0)
3615                                         fprintf(fp, " %s", viewname);
3616                                 fprintf(fp, "\n");
3617                         }
3618                 }
3619         }
3620         if (result == ISC_R_NOMORE)
3621                 result = ISC_R_SUCCESS;
3622         CHECK(result);
3623         
3624         fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now);
3625
3626  cleanup:
3627         if (fp != NULL)
3628                 (void)isc_stdio_close(fp);
3629         return (result);
3630 }
3631
3632 static isc_result_t
3633 add_zone_tolist(dns_zone_t *zone, void *uap) {
3634         struct dumpcontext *dctx = uap;
3635         struct zonelistentry *zle;
3636
3637         zle = isc_mem_get(dctx->mctx, sizeof *zle);
3638         if (zle ==  NULL)
3639                 return (ISC_R_NOMEMORY);
3640         zle->zone = NULL;
3641         dns_zone_attach(zone, &zle->zone);
3642         ISC_LINK_INIT(zle, link);
3643         ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
3644         return (ISC_R_SUCCESS);
3645 }
3646
3647 static isc_result_t
3648 add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
3649         struct viewlistentry *vle;
3650         isc_result_t result = ISC_R_SUCCESS;
3651         
3652         /*
3653          * Prevent duplicate views.
3654          */
3655         for (vle = ISC_LIST_HEAD(dctx->viewlist);
3656              vle != NULL;
3657              vle = ISC_LIST_NEXT(vle, link))
3658                 if (vle->view == view)
3659                         return (ISC_R_SUCCESS);
3660
3661         vle = isc_mem_get(dctx->mctx, sizeof *vle);
3662         if (vle == NULL)
3663                 return (ISC_R_NOMEMORY);
3664         vle->view = NULL;
3665         dns_view_attach(view, &vle->view);
3666         ISC_LINK_INIT(vle, link);
3667         ISC_LIST_INIT(vle->zonelist);
3668         ISC_LIST_APPEND(dctx->viewlist, vle, link);
3669         if (dctx->dumpzones)
3670                 result = dns_zt_apply(view->zonetable, ISC_TRUE,
3671                                       add_zone_tolist, dctx);
3672         return (result);
3673 }
3674
3675 static void
3676 dumpcontext_destroy(struct dumpcontext *dctx) {
3677         struct viewlistentry *vle;
3678         struct zonelistentry *zle;
3679
3680         vle = ISC_LIST_HEAD(dctx->viewlist);
3681         while (vle != NULL) {
3682                 ISC_LIST_UNLINK(dctx->viewlist, vle, link);
3683                 zle = ISC_LIST_HEAD(vle->zonelist);
3684                 while (zle != NULL) {
3685                         ISC_LIST_UNLINK(vle->zonelist, zle, link);
3686                         dns_zone_detach(&zle->zone);
3687                         isc_mem_put(dctx->mctx, zle, sizeof *zle);
3688                         zle = ISC_LIST_HEAD(vle->zonelist);
3689                 }
3690                 dns_view_detach(&vle->view);
3691                 isc_mem_put(dctx->mctx, vle, sizeof *vle);
3692                 vle = ISC_LIST_HEAD(dctx->viewlist);
3693         }
3694         if (dctx->version != NULL)
3695                 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
3696         if (dctx->db != NULL)
3697                 dns_db_detach(&dctx->db);
3698         if (dctx->cache != NULL)
3699                 dns_db_detach(&dctx->cache);
3700         if (dctx->task != NULL)
3701                 isc_task_detach(&dctx->task);
3702         if (dctx->fp != NULL)
3703                 (void)isc_stdio_close(dctx->fp);
3704         if (dctx->mdctx != NULL)
3705                 dns_dumpctx_detach(&dctx->mdctx);
3706         isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
3707 }
3708
3709 static void
3710 dumpdone(void *arg, isc_result_t result) {
3711         struct dumpcontext *dctx = arg;
3712         char buf[1024+32];
3713         const dns_master_style_t *style;
3714         
3715         if (result != ISC_R_SUCCESS)
3716                 goto cleanup;
3717         if (dctx->mdctx != NULL)
3718                 dns_dumpctx_detach(&dctx->mdctx);
3719         if (dctx->view == NULL) {
3720                 dctx->view = ISC_LIST_HEAD(dctx->viewlist);
3721                 if (dctx->view == NULL)
3722                         goto done;
3723                 INSIST(dctx->zone == NULL);
3724         } else
3725                 goto resume;
3726  nextview:
3727         fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
3728  resume:
3729         if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) {
3730                 style = &dns_master_style_cache;
3731                 /* start cache dump */
3732                 if (dctx->view->view->cachedb != NULL)
3733                         dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
3734                 if (dctx->cache != NULL) {
3735
3736                         fprintf(dctx->fp, ";\n; Cache dump of view '%s'\n;\n",
3737                                 dctx->view->view->name);
3738                         result = dns_master_dumptostreaminc(dctx->mctx,
3739                                                             dctx->cache, NULL,
3740                                                             style, dctx->fp,
3741                                                             dctx->task,
3742                                                             dumpdone, dctx,
3743                                                             &dctx->mdctx);
3744                         if (result == DNS_R_CONTINUE)
3745                                 return;
3746                         if (result == ISC_R_NOTIMPLEMENTED)
3747                                 fprintf(dctx->fp, "; %s\n",
3748                                         dns_result_totext(result));
3749                         else if (result != ISC_R_SUCCESS)
3750                                 goto cleanup;
3751                 }
3752         }
3753         if (dctx->cache != NULL) {
3754                 dns_adb_dump(dctx->view->view->adb, dctx->fp);
3755                 dns_db_detach(&dctx->cache);
3756         }
3757         if (dctx->dumpzones) {
3758                 style = &dns_master_style_full;
3759  nextzone:
3760                 if (dctx->version != NULL)
3761                         dns_db_closeversion(dctx->db, &dctx->version,
3762                                             ISC_FALSE);
3763                 if (dctx->db != NULL)
3764                         dns_db_detach(&dctx->db);
3765                 if (dctx->zone == NULL)
3766                         dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
3767                 else
3768                         dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
3769                 if (dctx->zone != NULL) {
3770                         /* start zone dump */
3771                         dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
3772                         fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
3773                         result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
3774                         if (result != ISC_R_SUCCESS) {
3775                                 fprintf(dctx->fp, "; %s\n",
3776                                         dns_result_totext(result));
3777                                 goto nextzone;
3778                         }
3779                         dns_db_currentversion(dctx->db, &dctx->version);
3780                         result = dns_master_dumptostreaminc(dctx->mctx,
3781                                                             dctx->db,
3782                                                             dctx->version,
3783                                                             style, dctx->fp,
3784                                                             dctx->task,
3785                                                             dumpdone, dctx,
3786                                                             &dctx->mdctx);
3787                         if (result == DNS_R_CONTINUE)
3788                                 return;
3789                         if (result == ISC_R_NOTIMPLEMENTED) {
3790                                 fprintf(dctx->fp, "; %s\n",
3791                                         dns_result_totext(result));
3792                                 result = ISC_R_SUCCESS;
3793                                 goto nextzone;
3794                         }
3795                         if (result != ISC_R_SUCCESS)
3796                                 goto cleanup;
3797                 }
3798         }
3799         if (dctx->view != NULL)
3800                 dctx->view = ISC_LIST_NEXT(dctx->view, link);
3801         if (dctx->view != NULL)
3802                 goto nextview;
3803  done:
3804         fprintf(dctx->fp, "; Dump complete\n");
3805         result = isc_stdio_flush(dctx->fp);
3806         if (result == ISC_R_SUCCESS)
3807                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3808                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3809                               "dumpdb complete");
3810  cleanup:
3811         if (result != ISC_R_SUCCESS)
3812                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3813                               NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3814                               "dumpdb failed: %s", dns_result_totext(result));
3815         dumpcontext_destroy(dctx);
3816 }
3817
3818 isc_result_t
3819 ns_server_dumpdb(ns_server_t *server, char *args) {
3820         struct dumpcontext *dctx = NULL;
3821         dns_view_t *view;
3822         isc_result_t result;
3823         char *ptr;
3824         const char *sep;
3825
3826         dctx = isc_mem_get(server->mctx, sizeof(*dctx));
3827         if (dctx == NULL)
3828                 return (ISC_R_NOMEMORY);
3829
3830         dctx->mctx = server->mctx;
3831         dctx->dumpcache = ISC_TRUE;
3832         dctx->dumpzones = ISC_FALSE;
3833         dctx->fp = NULL;
3834         ISC_LIST_INIT(dctx->viewlist);
3835         dctx->view = NULL;
3836         dctx->zone = NULL;
3837         dctx->cache = NULL;
3838         dctx->mdctx = NULL;
3839         dctx->db = NULL;
3840         dctx->cache = NULL;
3841         dctx->task = NULL;
3842         dctx->version = NULL;
3843         isc_task_attach(server->task, &dctx->task);
3844
3845         CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
3846                 "could not open dump file", server->dumpfile);
3847
3848         /* Skip the command name. */
3849         ptr = next_token(&args, " \t");
3850         if (ptr == NULL)
3851                 return (ISC_R_UNEXPECTEDEND);
3852
3853         sep = (args == NULL) ? "" : ": ";
3854         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
3855                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
3856                       "dumpdb started%s%s", sep, (args != NULL) ? args : "");
3857
3858         ptr = next_token(&args, " \t");
3859         if (ptr != NULL && strcmp(ptr, "-all") == 0) {
3860                 dctx->dumpzones = ISC_TRUE;
3861                 dctx->dumpcache = ISC_TRUE;
3862                 ptr = next_token(&args, " \t");
3863         } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
3864                 dctx->dumpzones = ISC_FALSE;
3865                 dctx->dumpcache = ISC_TRUE;
3866                 ptr = next_token(&args, " \t");
3867         } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
3868                 dctx->dumpzones = ISC_TRUE;
3869                 dctx->dumpcache = ISC_FALSE;
3870                 ptr = next_token(&args, " \t");
3871         } 
3872
3873  nextview:
3874         for (view = ISC_LIST_HEAD(server->viewlist);
3875              view != NULL;
3876              view = ISC_LIST_NEXT(view, link))
3877         {
3878                 if (ptr != NULL && strcmp(view->name, ptr) != 0)
3879                         continue;
3880                 CHECK(add_view_tolist(dctx, view));
3881         }
3882         if (ptr != NULL) {
3883                 ptr = next_token(&args, " \t");
3884                 if (ptr != NULL)
3885                         goto nextview;
3886         }
3887         dumpdone(dctx, ISC_R_SUCCESS);
3888         return (ISC_R_SUCCESS);
3889
3890  cleanup:
3891         if (dctx != NULL)
3892                 dumpcontext_destroy(dctx);
3893         return (result);
3894 }
3895
3896 isc_result_t
3897 ns_server_dumprecursing(ns_server_t *server) {
3898         FILE *fp = NULL;
3899         isc_result_t result;
3900
3901         CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
3902                 "could not open dump file", server->recfile);
3903         fprintf(fp,";\n; Recursing Queries\n;\n");
3904         ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
3905         fprintf(fp, "; Dump complete\n");
3906
3907  cleanup:
3908         if (fp != NULL)
3909                 result = isc_stdio_close(fp);
3910         return (result);
3911 }
3912
3913 isc_result_t
3914 ns_server_setdebuglevel(ns_server_t *server, char *args) {
3915         char *ptr;
3916         char *levelstr;
3917         char *endp;
3918         long newlevel;
3919
3920         UNUSED(server);
3921
3922         /* Skip the command name. */
3923         ptr = next_token(&args, " \t");
3924         if (ptr == NULL)
3925                 return (ISC_R_UNEXPECTEDEND);
3926
3927         /* Look for the new level name. */
3928         levelstr = next_token(&args, " \t");
3929         if (levelstr == NULL) {
3930                 if (ns_g_debuglevel < 99)
3931                         ns_g_debuglevel++;
3932         } else {
3933                 newlevel = strtol(levelstr, &endp, 10);
3934                 if (*endp != '\0' || newlevel < 0 || newlevel > 99)
3935                         return (ISC_R_RANGE);
3936                 ns_g_debuglevel = (unsigned int)newlevel;
3937         }
3938         isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel);
3939         return (ISC_R_SUCCESS);
3940 }
3941
3942 isc_result_t
3943 ns_server_flushcache(ns_server_t *server, char *args) {
3944         char *ptr, *viewname;
3945         dns_view_t *view;
3946         isc_boolean_t flushed = ISC_FALSE;
3947         isc_result_t result;
3948
3949         /* Skip the command name. */
3950         ptr = next_token(&args, " \t");
3951         if (ptr == NULL)
3952                 return (ISC_R_UNEXPECTEDEND);
3953
3954         /* Look for the view name. */
3955         viewname = next_token(&args, " \t");
3956
3957         result = isc_task_beginexclusive(server->task);
3958         RUNTIME_CHECK(result == ISC_R_SUCCESS);
3959         for (view = ISC_LIST_HEAD(server->viewlist);
3960              view != NULL;
3961              view = ISC_LIST_NEXT(view, link))
3962         {
3963                 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
3964                         continue;
3965                 result = dns_view_flushcache(view);
3966                 if (result != ISC_R_SUCCESS)
3967                         goto out;
3968                 flushed = ISC_TRUE;
3969         }
3970         if (flushed)
3971                 result = ISC_R_SUCCESS;
3972         else
3973                 result = ISC_R_FAILURE;
3974  out:
3975         isc_task_endexclusive(server->task);    
3976         return (result);
3977 }
3978
3979 isc_result_t
3980 ns_server_flushname(ns_server_t *server, char *args) {
3981         char *ptr, *target, *viewname;
3982         dns_view_t *view;
3983         isc_boolean_t flushed = ISC_FALSE;
3984         isc_result_t result;
3985         isc_buffer_t b;
3986         dns_fixedname_t fixed;
3987         dns_name_t *name;
3988
3989         /* Skip the command name. */
3990         ptr = next_token(&args, " \t");
3991         if (ptr == NULL)
3992                 return (ISC_R_UNEXPECTEDEND);
3993
3994         /* Find the domain name to flush. */
3995         target = next_token(&args, " \t");
3996         if (target == NULL)
3997                 return (ISC_R_UNEXPECTEDEND);
3998
3999         isc_buffer_init(&b, target, strlen(target));
4000         isc_buffer_add(&b, strlen(target));
4001         dns_fixedname_init(&fixed);
4002         name = dns_fixedname_name(&fixed);
4003         result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
4004         if (result != ISC_R_SUCCESS)
4005                 return (result);
4006
4007         /* Look for the view name. */
4008         viewname = next_token(&args, " \t");
4009
4010         result = isc_task_beginexclusive(server->task);
4011         RUNTIME_CHECK(result == ISC_R_SUCCESS);
4012         flushed = ISC_TRUE;
4013         for (view = ISC_LIST_HEAD(server->viewlist);
4014              view != NULL;
4015              view = ISC_LIST_NEXT(view, link))
4016         {
4017                 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
4018                         continue;
4019                 result = dns_view_flushname(view, name);
4020                 if (result != ISC_R_SUCCESS)
4021                         flushed = ISC_FALSE;
4022         }
4023         if (flushed)
4024                 result = ISC_R_SUCCESS;
4025         else
4026                 result = ISC_R_FAILURE;
4027         isc_task_endexclusive(server->task);    
4028         return (result);
4029 }
4030
4031 isc_result_t
4032 ns_server_status(ns_server_t *server, isc_buffer_t *text) {
4033         int zonecount, xferrunning, xferdeferred, soaqueries;
4034         unsigned int n;
4035
4036         zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
4037         xferrunning = dns_zonemgr_getcount(server->zonemgr,
4038                                            DNS_ZONESTATE_XFERRUNNING);
4039         xferdeferred = dns_zonemgr_getcount(server->zonemgr,
4040                                             DNS_ZONESTATE_XFERDEFERRED);
4041         soaqueries = dns_zonemgr_getcount(server->zonemgr,
4042                                           DNS_ZONESTATE_SOAQUERY);
4043         n = snprintf((char *)isc_buffer_used(text),
4044                      isc_buffer_availablelength(text),
4045                      "number of zones: %u\n"
4046                      "debug level: %d\n"
4047                      "xfers running: %u\n"
4048                      "xfers deferred: %u\n"
4049                      "soa queries in progress: %u\n"
4050                      "query logging is %s\n"
4051                      "recursive clients: %d/%d\n"
4052                      "tcp clients: %d/%d\n"
4053                      "server is up and running",
4054                      zonecount, ns_g_debuglevel, xferrunning, xferdeferred,
4055                      soaqueries, server->log_queries ? "ON" : "OFF",
4056                      server->recursionquota.used, server->recursionquota.max,
4057                      server->tcpquota.used, server->tcpquota.max);
4058         if (n >= isc_buffer_availablelength(text))
4059                 return (ISC_R_NOSPACE);
4060         isc_buffer_add(text, n);
4061         return (ISC_R_SUCCESS);
4062 }
4063
4064 /*
4065  * Act on a "freeze" or "unfreeze" command from the command channel.
4066  */
4067 isc_result_t
4068 ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) {
4069         isc_result_t result;
4070         dns_zone_t *zone = NULL;
4071         dns_zonetype_t type;
4072         char classstr[DNS_RDATACLASS_FORMATSIZE];
4073         char zonename[DNS_NAME_FORMATSIZE];
4074         dns_view_t *view;
4075         char *journal;
4076         const char *vname, *sep;
4077         isc_boolean_t frozen;
4078         
4079         result = zone_from_args(server, args, &zone);
4080         if (result != ISC_R_SUCCESS)
4081                 return (result);
4082         if (zone == NULL)
4083                 return (ISC_R_UNEXPECTEDEND);
4084         type = dns_zone_gettype(zone);
4085         if (type != dns_zone_master) {
4086                 dns_zone_detach(&zone);
4087                 return (ISC_R_NOTFOUND);
4088         }
4089
4090         frozen = dns_zone_getupdatedisabled(zone);
4091         if (freeze) {
4092                 if (frozen)
4093                         result = DNS_R_FROZEN;
4094                 if (result == ISC_R_SUCCESS)
4095                         result = dns_zone_flush(zone);
4096                 if (result == ISC_R_SUCCESS) {
4097                         journal = dns_zone_getjournal(zone);
4098                         if (journal != NULL)
4099                                 (void)isc_file_remove(journal);
4100                 }
4101         } else {
4102                 if (frozen) {
4103                         result = dns_zone_load(zone);
4104                         if (result == DNS_R_CONTINUE ||
4105                             result == DNS_R_UPTODATE)
4106                                 result = ISC_R_SUCCESS;
4107                 }
4108         }
4109         if (result == ISC_R_SUCCESS)
4110                 dns_zone_setupdatedisabled(zone, freeze);
4111
4112         view = dns_zone_getview(zone);
4113         if (strcmp(view->name, "_bind") == 0 ||
4114             strcmp(view->name, "_default") == 0)
4115         {
4116                 vname = "";
4117                 sep = "";
4118         } else {
4119                 vname = view->name;
4120                 sep = " ";
4121         }
4122         dns_rdataclass_format(dns_zone_getclass(zone), classstr,
4123                               sizeof(classstr));
4124         dns_name_format(dns_zone_getorigin(zone),
4125                         zonename, sizeof(zonename));
4126         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
4127                       NS_LOGMODULE_SERVER, ISC_LOG_INFO,
4128                       "%s zone '%s/%s'%s%s: %s",
4129                       freeze ? "freezing" : "unfreezing",
4130                       zonename, classstr, sep, vname,
4131                       isc_result_totext(result));
4132         dns_zone_detach(&zone);
4133         return (result);
4134 }
4135
4136 #ifdef HAVE_LIBSCF
4137 /*
4138  * This function adds a message for rndc to echo if named
4139  * is managed by smf and is also running chroot.
4140  */
4141 isc_result_t
4142 ns_smf_add_message(isc_buffer_t *text) {
4143         unsigned int n;
4144
4145         n = snprintf((char *)isc_buffer_used(text),
4146                 isc_buffer_availablelength(text),
4147                 "use svcadm(1M) to manage named");
4148         if (n >= isc_buffer_availablelength(text))
4149                 return (ISC_R_NOSPACE);
4150         isc_buffer_add(text, n);
4151         return (ISC_R_SUCCESS);
4152 }
4153 #endif /* HAVE_LIBSCF */