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