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