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