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