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