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