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