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