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