cvs updates from Wed Dec 15 17:45:22 EST 2010
[tridge/bind9.git] / lib / dns / view.c
1 /*
2  * Copyright (C) 2004-2010  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: view.c,v 1.172 2010/12/09 04:53:48 marka Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <isc/hash.h>
25 #include <isc/sha2.h>
26 #include <isc/stats.h>
27 #include <isc/string.h>         /* Required for HP/UX (and others?) */
28 #include <isc/task.h>
29 #include <isc/util.h>
30
31 #include <dns/acache.h>
32 #include <dns/acl.h>
33 #include <dns/adb.h>
34 #include <dns/cache.h>
35 #include <dns/db.h>
36 #include <dns/dlz.h>
37 #ifdef BIND9
38 #include <dns/dns64.h>
39 #endif
40 #include <dns/dnssec.h>
41 #include <dns/events.h>
42 #include <dns/forward.h>
43 #include <dns/keytable.h>
44 #include <dns/keyvalues.h>
45 #include <dns/master.h>
46 #include <dns/masterdump.h>
47 #include <dns/order.h>
48 #include <dns/peer.h>
49 #include <dns/rbt.h>
50 #include <dns/rdataset.h>
51 #include <dns/request.h>
52 #include <dns/resolver.h>
53 #include <dns/result.h>
54 #include <dns/stats.h>
55 #include <dns/tsig.h>
56 #include <dns/zone.h>
57 #include <dns/zt.h>
58
59 #define RESSHUTDOWN(v)  (((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
60 #define ADBSHUTDOWN(v)  (((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
61 #define REQSHUTDOWN(v)  (((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
62
63 #define DNS_VIEW_DELONLYHASH 111
64
65 static void resolver_shutdown(isc_task_t *task, isc_event_t *event);
66 static void adb_shutdown(isc_task_t *task, isc_event_t *event);
67 static void req_shutdown(isc_task_t *task, isc_event_t *event);
68
69 isc_result_t
70 dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
71                 const char *name, dns_view_t **viewp)
72 {
73         dns_view_t *view;
74         isc_result_t result;
75
76         /*
77          * Create a view.
78          */
79
80         REQUIRE(name != NULL);
81         REQUIRE(viewp != NULL && *viewp == NULL);
82
83         view = isc_mem_get(mctx, sizeof(*view));
84         if (view == NULL)
85                 return (ISC_R_NOMEMORY);
86         view->name = isc_mem_strdup(mctx, name);
87         if (view->name == NULL) {
88                 result = ISC_R_NOMEMORY;
89                 goto cleanup_view;
90         }
91         result = isc_mutex_init(&view->lock);
92         if (result != ISC_R_SUCCESS)
93                 goto cleanup_name;
94
95 #ifdef BIND9
96         view->zonetable = NULL;
97         result = dns_zt_create(mctx, rdclass, &view->zonetable);
98         if (result != ISC_R_SUCCESS) {
99                 UNEXPECTED_ERROR(__FILE__, __LINE__,
100                                  "dns_zt_create() failed: %s",
101                                  isc_result_totext(result));
102                 result = ISC_R_UNEXPECTED;
103                 goto cleanup_mutex;
104         }
105 #endif
106         view->secroots_priv = NULL;
107         view->fwdtable = NULL;
108         result = dns_fwdtable_create(mctx, &view->fwdtable);
109         if (result != ISC_R_SUCCESS) {
110                 UNEXPECTED_ERROR(__FILE__, __LINE__,
111                                  "dns_fwdtable_create() failed: %s",
112                                  isc_result_totext(result));
113                 result = ISC_R_UNEXPECTED;
114                 goto cleanup_zt;
115         }
116
117         view->acache = NULL;
118         view->cache = NULL;
119         view->cachedb = NULL;
120         view->dlzdatabase = NULL;
121         view->hints = NULL;
122         view->resolver = NULL;
123         view->adb = NULL;
124         view->requestmgr = NULL;
125         view->mctx = mctx;
126         view->rdclass = rdclass;
127         view->frozen = ISC_FALSE;
128         view->task = NULL;
129         result = isc_refcount_init(&view->references, 1);
130         if (result != ISC_R_SUCCESS)
131                 goto cleanup_fwdtable;
132         view->weakrefs = 0;
133         view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
134                             DNS_VIEWATTR_REQSHUTDOWN);
135         view->statickeys = NULL;
136         view->dynamickeys = NULL;
137         view->matchclients = NULL;
138         view->matchdestinations = NULL;
139         view->matchrecursiveonly = ISC_FALSE;
140         result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
141         if (result != ISC_R_SUCCESS)
142                 goto cleanup_references;
143         view->peers = NULL;
144         view->order = NULL;
145         view->delonly = NULL;
146         view->rootdelonly = ISC_FALSE;
147         view->rootexclude = NULL;
148         view->resstats = NULL;
149         view->resquerystats = NULL;
150         view->cacheshared = ISC_FALSE;
151         ISC_LIST_INIT(view->dns64);
152         view->dns64cnt = 0;
153
154         /*
155          * Initialize configuration data with default values.
156          */
157         view->recursion = ISC_TRUE;
158         view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
159         view->additionalfromcache = ISC_TRUE;
160         view->additionalfromauth = ISC_TRUE;
161         view->enablednssec = ISC_TRUE;
162         view->enablevalidation = ISC_TRUE;
163         view->acceptexpired = ISC_FALSE;
164         view->minimalresponses = ISC_FALSE;
165         view->transfer_format = dns_one_answer;
166         view->cacheacl = NULL;
167         view->cacheonacl = NULL;
168         view->queryacl = NULL;
169         view->queryonacl = NULL;
170         view->recursionacl = NULL;
171         view->recursiononacl = NULL;
172         view->sortlist = NULL;
173         view->transferacl = NULL;
174         view->notifyacl = NULL;
175         view->updateacl = NULL;
176         view->upfwdacl = NULL;
177         view->denyansweracl = NULL;
178         view->answeracl_exclude = NULL;
179         view->denyanswernames = NULL;
180         view->answernames_exclude = NULL;
181         view->requestixfr = ISC_TRUE;
182         view->provideixfr = ISC_TRUE;
183         view->maxcachettl = 7 * 24 * 3600;
184         view->maxncachettl = 3 * 3600;
185         view->dstport = 53;
186         view->preferred_glue = 0;
187         view->flush = ISC_FALSE;
188         view->dlv = NULL;
189         view->maxudp = 0;
190         view->v4_aaaa = dns_v4_aaaa_ok;
191         view->v4_aaaa_acl = NULL;
192         dns_fixedname_init(&view->dlv_fixed);
193         view->managed_keys = NULL;
194 #ifdef BIND9
195         view->new_zone_file = NULL;
196         view->new_zone_config = NULL;
197         view->cfg_destroy = NULL;
198
199         result = dns_order_create(view->mctx, &view->order);
200         if (result != ISC_R_SUCCESS)
201                 goto cleanup_dynkeys;
202 #endif
203
204         result = dns_peerlist_new(view->mctx, &view->peers);
205         if (result != ISC_R_SUCCESS)
206                 goto cleanup_order;
207
208         result = dns_aclenv_init(view->mctx, &view->aclenv);
209         if (result != ISC_R_SUCCESS)
210                 goto cleanup_peerlist;
211
212         ISC_LINK_INIT(view, link);
213         ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
214                        DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
215                        view, NULL, NULL, NULL);
216         ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
217                        DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
218                        view, NULL, NULL, NULL);
219         ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
220                        DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
221                        view, NULL, NULL, NULL);
222         view->magic = DNS_VIEW_MAGIC;
223
224         *viewp = view;
225
226         return (ISC_R_SUCCESS);
227
228  cleanup_peerlist:
229         dns_peerlist_detach(&view->peers);
230
231  cleanup_order:
232 #ifdef BIND9
233         dns_order_detach(&view->order);
234
235  cleanup_dynkeys:
236 #endif
237         dns_tsigkeyring_destroy(&view->dynamickeys);
238
239  cleanup_references:
240         isc_refcount_destroy(&view->references);
241
242  cleanup_fwdtable:
243         dns_fwdtable_destroy(&view->fwdtable);
244
245  cleanup_zt:
246 #ifdef BIND9
247         dns_zt_detach(&view->zonetable);
248
249  cleanup_mutex:
250 #endif
251         DESTROYLOCK(&view->lock);
252
253  cleanup_name:
254         isc_mem_free(mctx, view->name);
255
256  cleanup_view:
257         isc_mem_put(mctx, view, sizeof(*view));
258
259         return (result);
260 }
261
262 static inline void
263 destroy(dns_view_t *view) {
264 #ifdef BIND9
265         dns_dns64_t *dns64;
266 #endif
267
268         REQUIRE(!ISC_LINK_LINKED(view, link));
269         REQUIRE(isc_refcount_current(&view->references) == 0);
270         REQUIRE(view->weakrefs == 0);
271         REQUIRE(RESSHUTDOWN(view));
272         REQUIRE(ADBSHUTDOWN(view));
273         REQUIRE(REQSHUTDOWN(view));
274
275 #ifdef BIND9
276         if (view->order != NULL)
277                 dns_order_detach(&view->order);
278 #endif
279         if (view->peers != NULL)
280                 dns_peerlist_detach(&view->peers);
281         if (view->dynamickeys != NULL)
282                 dns_tsigkeyring_destroy(&view->dynamickeys);
283         if (view->statickeys != NULL)
284                 dns_tsigkeyring_destroy(&view->statickeys);
285         if (view->adb != NULL)
286                 dns_adb_detach(&view->adb);
287         if (view->resolver != NULL)
288                 dns_resolver_detach(&view->resolver);
289 #ifdef BIND9
290         if (view->acache != NULL) {
291                 if (view->cachedb != NULL)
292                         dns_acache_putdb(view->acache, view->cachedb);
293                 dns_acache_detach(&view->acache);
294         }
295 #endif
296         if (view->requestmgr != NULL)
297                 dns_requestmgr_detach(&view->requestmgr);
298         if (view->task != NULL)
299                 isc_task_detach(&view->task);
300         if (view->hints != NULL)
301                 dns_db_detach(&view->hints);
302         if (view->dlzdatabase != NULL)
303                 dns_dlzdestroy(&view->dlzdatabase);
304         if (view->cachedb != NULL)
305                 dns_db_detach(&view->cachedb);
306         if (view->cache != NULL)
307                 dns_cache_detach(&view->cache);
308         if (view->matchclients != NULL)
309                 dns_acl_detach(&view->matchclients);
310         if (view->matchdestinations != NULL)
311                 dns_acl_detach(&view->matchdestinations);
312         if (view->cacheacl != NULL)
313                 dns_acl_detach(&view->cacheacl);
314         if (view->cacheonacl != NULL)
315                 dns_acl_detach(&view->cacheonacl);
316         if (view->queryacl != NULL)
317                 dns_acl_detach(&view->queryacl);
318         if (view->queryonacl != NULL)
319                 dns_acl_detach(&view->queryonacl);
320         if (view->recursionacl != NULL)
321                 dns_acl_detach(&view->recursionacl);
322         if (view->recursiononacl != NULL)
323                 dns_acl_detach(&view->recursiononacl);
324         if (view->sortlist != NULL)
325                 dns_acl_detach(&view->sortlist);
326         if (view->transferacl != NULL)
327                 dns_acl_detach(&view->transferacl);
328         if (view->notifyacl != NULL)
329                 dns_acl_detach(&view->notifyacl);
330         if (view->updateacl != NULL)
331                 dns_acl_detach(&view->updateacl);
332         if (view->upfwdacl != NULL)
333                 dns_acl_detach(&view->upfwdacl);
334         if (view->denyansweracl != NULL)
335                 dns_acl_detach(&view->denyansweracl);
336         if (view->v4_aaaa_acl != NULL)
337                 dns_acl_detach(&view->v4_aaaa_acl);
338         if (view->answeracl_exclude != NULL)
339                 dns_rbt_destroy(&view->answeracl_exclude);
340         if (view->denyanswernames != NULL)
341                 dns_rbt_destroy(&view->denyanswernames);
342         if (view->answernames_exclude != NULL)
343                 dns_rbt_destroy(&view->answernames_exclude);
344         if (view->delonly != NULL) {
345                 dns_name_t *name;
346                 int i;
347
348                 for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
349                         name = ISC_LIST_HEAD(view->delonly[i]);
350                         while (name != NULL) {
351                                 ISC_LIST_UNLINK(view->delonly[i], name, link);
352                                 dns_name_free(name, view->mctx);
353                                 isc_mem_put(view->mctx, name, sizeof(*name));
354                                 name = ISC_LIST_HEAD(view->delonly[i]);
355                         }
356                 }
357                 isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
358                             DNS_VIEW_DELONLYHASH);
359                 view->delonly = NULL;
360         }
361         if (view->rootexclude != NULL) {
362                 dns_name_t *name;
363                 int i;
364
365                 for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
366                         name = ISC_LIST_HEAD(view->rootexclude[i]);
367                         while (name != NULL) {
368                                 ISC_LIST_UNLINK(view->rootexclude[i],
369                                                 name, link);
370                                 dns_name_free(name, view->mctx);
371                                 isc_mem_put(view->mctx, name, sizeof(*name));
372                                 name = ISC_LIST_HEAD(view->rootexclude[i]);
373                         }
374                 }
375                 isc_mem_put(view->mctx, view->rootexclude,
376                             sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
377                 view->rootexclude = NULL;
378         }
379         if (view->resstats != NULL)
380                 isc_stats_detach(&view->resstats);
381         if (view->resquerystats != NULL)
382                 dns_stats_detach(&view->resquerystats);
383         if (view->secroots_priv != NULL)
384                 dns_keytable_detach(&view->secroots_priv);
385 #ifdef BIND9
386         for (dns64 = ISC_LIST_HEAD(view->dns64);
387              dns64 != NULL;
388              dns64 = ISC_LIST_HEAD(view->dns64)) {
389                 dns_dns64_unlink(&view->dns64, dns64);
390                 dns_dns64_destroy(&dns64);
391         }
392         if (view->managed_keys != NULL)
393                 dns_zone_detach(&view->managed_keys);
394         dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
395 #endif
396         dns_fwdtable_destroy(&view->fwdtable);
397         dns_aclenv_destroy(&view->aclenv);
398         DESTROYLOCK(&view->lock);
399         isc_refcount_destroy(&view->references);
400         isc_mem_free(view->mctx, view->name);
401         isc_mem_put(view->mctx, view, sizeof(*view));
402 }
403
404 /*
405  * Return true iff 'view' may be freed.
406  * The caller must be holding the view lock.
407  */
408 static isc_boolean_t
409 all_done(dns_view_t *view) {
410
411         if (isc_refcount_current(&view->references) == 0 &&
412             view->weakrefs == 0 &&
413             RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
414                 return (ISC_TRUE);
415
416         return (ISC_FALSE);
417 }
418
419 void
420 dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
421
422         REQUIRE(DNS_VIEW_VALID(source));
423         REQUIRE(targetp != NULL && *targetp == NULL);
424
425         isc_refcount_increment(&source->references, NULL);
426
427         *targetp = source;
428 }
429
430 static void
431 view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
432         dns_view_t *view;
433         unsigned int refs;
434         isc_boolean_t done = ISC_FALSE;
435
436         REQUIRE(viewp != NULL);
437         view = *viewp;
438         REQUIRE(DNS_VIEW_VALID(view));
439
440         if (flush)
441                 view->flush = ISC_TRUE;
442         isc_refcount_decrement(&view->references, &refs);
443         if (refs == 0) {
444                 LOCK(&view->lock);
445                 if (!RESSHUTDOWN(view))
446                         dns_resolver_shutdown(view->resolver);
447                 if (!ADBSHUTDOWN(view))
448                         dns_adb_shutdown(view->adb);
449                 if (!REQSHUTDOWN(view))
450                         dns_requestmgr_shutdown(view->requestmgr);
451 #ifdef BIND9
452                 if (view->acache != NULL)
453                         dns_acache_shutdown(view->acache);
454                 if (view->flush)
455                         dns_zt_flushanddetach(&view->zonetable);
456                 else
457                         dns_zt_detach(&view->zonetable);
458                 if (view->managed_keys != NULL) {
459                         if (view->flush)
460                                 dns_zone_flush(view->managed_keys);
461                         dns_zone_detach(&view->managed_keys);
462                 }
463 #endif
464                 done = all_done(view);
465                 UNLOCK(&view->lock);
466         }
467
468         *viewp = NULL;
469
470         if (done)
471                 destroy(view);
472 }
473
474 void
475 dns_view_flushanddetach(dns_view_t **viewp) {
476         view_flushanddetach(viewp, ISC_TRUE);
477 }
478
479 void
480 dns_view_detach(dns_view_t **viewp) {
481         view_flushanddetach(viewp, ISC_FALSE);
482 }
483
484 #ifdef BIND9
485 static isc_result_t
486 dialup(dns_zone_t *zone, void *dummy) {
487         UNUSED(dummy);
488         dns_zone_dialup(zone);
489         return (ISC_R_SUCCESS);
490 }
491
492 void
493 dns_view_dialup(dns_view_t *view) {
494         REQUIRE(DNS_VIEW_VALID(view));
495         (void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
496 }
497 #endif
498
499 void
500 dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
501
502         REQUIRE(DNS_VIEW_VALID(source));
503         REQUIRE(targetp != NULL && *targetp == NULL);
504
505         LOCK(&source->lock);
506         source->weakrefs++;
507         UNLOCK(&source->lock);
508
509         *targetp = source;
510 }
511
512 void
513 dns_view_weakdetach(dns_view_t **viewp) {
514         dns_view_t *view;
515         isc_boolean_t done = ISC_FALSE;
516
517         REQUIRE(viewp != NULL);
518         view = *viewp;
519         REQUIRE(DNS_VIEW_VALID(view));
520
521         LOCK(&view->lock);
522
523         INSIST(view->weakrefs > 0);
524         view->weakrefs--;
525         done = all_done(view);
526
527         UNLOCK(&view->lock);
528
529         *viewp = NULL;
530
531         if (done)
532                 destroy(view);
533 }
534
535 static void
536 resolver_shutdown(isc_task_t *task, isc_event_t *event) {
537         dns_view_t *view = event->ev_arg;
538         isc_boolean_t done;
539
540         REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
541         REQUIRE(DNS_VIEW_VALID(view));
542         REQUIRE(view->task == task);
543
544         UNUSED(task);
545
546         LOCK(&view->lock);
547
548         view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
549         done = all_done(view);
550
551         UNLOCK(&view->lock);
552
553         isc_event_free(&event);
554
555         if (done)
556                 destroy(view);
557 }
558
559 static void
560 adb_shutdown(isc_task_t *task, isc_event_t *event) {
561         dns_view_t *view = event->ev_arg;
562         isc_boolean_t done;
563
564         REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
565         REQUIRE(DNS_VIEW_VALID(view));
566         REQUIRE(view->task == task);
567
568         UNUSED(task);
569
570         LOCK(&view->lock);
571
572         view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
573         done = all_done(view);
574
575         UNLOCK(&view->lock);
576
577         isc_event_free(&event);
578
579         if (done)
580                 destroy(view);
581 }
582
583 static void
584 req_shutdown(isc_task_t *task, isc_event_t *event) {
585         dns_view_t *view = event->ev_arg;
586         isc_boolean_t done;
587
588         REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
589         REQUIRE(DNS_VIEW_VALID(view));
590         REQUIRE(view->task == task);
591
592         UNUSED(task);
593
594         LOCK(&view->lock);
595
596         view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
597         done = all_done(view);
598
599         UNLOCK(&view->lock);
600
601         isc_event_free(&event);
602
603         if (done)
604                 destroy(view);
605 }
606
607 isc_result_t
608 dns_view_createresolver(dns_view_t *view,
609                         isc_taskmgr_t *taskmgr, unsigned int ntasks,
610                         isc_socketmgr_t *socketmgr,
611                         isc_timermgr_t *timermgr,
612                         unsigned int options,
613                         dns_dispatchmgr_t *dispatchmgr,
614                         dns_dispatch_t *dispatchv4,
615                         dns_dispatch_t *dispatchv6)
616 {
617         isc_result_t result;
618         isc_event_t *event;
619         isc_mem_t *mctx = NULL;
620
621         REQUIRE(DNS_VIEW_VALID(view));
622         REQUIRE(!view->frozen);
623         REQUIRE(view->resolver == NULL);
624
625         result = isc_task_create(taskmgr, 0, &view->task);
626         if (result != ISC_R_SUCCESS)
627                 return (result);
628         isc_task_setname(view->task, "view", view);
629
630         result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
631                                      timermgr, options, dispatchmgr,
632                                      dispatchv4, dispatchv6,
633                                      &view->resolver);
634         if (result != ISC_R_SUCCESS) {
635                 isc_task_detach(&view->task);
636                 return (result);
637         }
638         event = &view->resevent;
639         dns_resolver_whenshutdown(view->resolver, view->task, &event);
640         view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
641
642         result = isc_mem_create(0, 0, &mctx);
643         if (result != ISC_R_SUCCESS) {
644                 dns_resolver_shutdown(view->resolver);
645                 return (result);
646         }
647
648         result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
649         isc_mem_setname(mctx, "ADB", NULL);
650         isc_mem_detach(&mctx);
651         if (result != ISC_R_SUCCESS) {
652                 dns_resolver_shutdown(view->resolver);
653                 return (result);
654         }
655         event = &view->adbevent;
656         dns_adb_whenshutdown(view->adb, view->task, &event);
657         view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
658
659         result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
660                                       dns_resolver_taskmgr(view->resolver),
661                                       dns_resolver_dispatchmgr(view->resolver),
662                                       dns_resolver_dispatchv4(view->resolver),
663                                       dns_resolver_dispatchv6(view->resolver),
664                                       &view->requestmgr);
665         if (result != ISC_R_SUCCESS) {
666                 dns_adb_shutdown(view->adb);
667                 dns_resolver_shutdown(view->resolver);
668                 return (result);
669         }
670         event = &view->reqevent;
671         dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
672         view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
673
674         return (ISC_R_SUCCESS);
675 }
676
677 void
678 dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
679         dns_view_setcache2(view, cache, ISC_FALSE);
680 }
681
682 void
683 dns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) {
684         REQUIRE(DNS_VIEW_VALID(view));
685         REQUIRE(!view->frozen);
686
687         view->cacheshared = shared;
688         if (view->cache != NULL) {
689 #ifdef BIND9
690                 if (view->acache != NULL)
691                         dns_acache_putdb(view->acache, view->cachedb);
692 #endif
693                 dns_db_detach(&view->cachedb);
694                 dns_cache_detach(&view->cache);
695         }
696         dns_cache_attach(cache, &view->cache);
697         dns_cache_attachdb(cache, &view->cachedb);
698         INSIST(DNS_DB_VALID(view->cachedb));
699
700 #ifdef BIND9
701         if (view->acache != NULL)
702                 dns_acache_setdb(view->acache, view->cachedb);
703 #endif
704 }
705
706 isc_boolean_t
707 dns_view_iscacheshared(dns_view_t *view) {
708         REQUIRE(DNS_VIEW_VALID(view));
709
710         return (view->cacheshared);
711 }
712
713 void
714 dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
715         REQUIRE(DNS_VIEW_VALID(view));
716         REQUIRE(!view->frozen);
717         REQUIRE(view->hints == NULL);
718         REQUIRE(dns_db_iszone(hints));
719
720         dns_db_attach(hints, &view->hints);
721 }
722
723 void
724 dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
725         REQUIRE(DNS_VIEW_VALID(view));
726         REQUIRE(ring != NULL);
727         if (view->statickeys != NULL)
728                 dns_tsigkeyring_destroy(&view->statickeys);
729         view->statickeys = ring;
730 }
731
732 void
733 dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
734         REQUIRE(DNS_VIEW_VALID(view));
735         view->dstport = dstport;
736 }
737
738 void
739 dns_view_freeze(dns_view_t *view) {
740         REQUIRE(DNS_VIEW_VALID(view));
741         REQUIRE(!view->frozen);
742
743         if (view->resolver != NULL) {
744                 INSIST(view->cachedb != NULL);
745                 dns_resolver_freeze(view->resolver);
746         }
747         view->frozen = ISC_TRUE;
748 }
749
750 #ifdef BIND9
751 void
752 dns_view_thaw(dns_view_t *view) {
753         REQUIRE(DNS_VIEW_VALID(view));
754         REQUIRE(view->frozen);
755
756         view->frozen = ISC_FALSE;
757 }
758
759 isc_result_t
760 dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
761         isc_result_t result;
762
763         REQUIRE(DNS_VIEW_VALID(view));
764         REQUIRE(!view->frozen);
765
766         result = dns_zt_mount(view->zonetable, zone);
767
768         return (result);
769 }
770 #endif
771
772 #ifdef BIND9
773 isc_result_t
774 dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
775         isc_result_t result;
776
777         REQUIRE(DNS_VIEW_VALID(view));
778
779         result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
780         if (result == DNS_R_PARTIALMATCH) {
781                 dns_zone_detach(zonep);
782                 result = ISC_R_NOTFOUND;
783         }
784
785         return (result);
786 }
787 #endif
788
789 isc_result_t
790 dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
791               isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
792               dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
793               dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
794 {
795         isc_result_t result;
796         dns_db_t *db, *zdb;
797         dns_dbnode_t *node, *znode;
798         isc_boolean_t is_cache;
799         dns_rdataset_t zrdataset, zsigrdataset;
800         dns_zone_t *zone;
801
802 #ifndef BIND9
803         UNUSED(use_hints);
804 #endif
805
806         /*
807          * Find an rdataset whose owner name is 'name', and whose type is
808          * 'type'.
809          */
810
811         REQUIRE(DNS_VIEW_VALID(view));
812         REQUIRE(view->frozen);
813         REQUIRE(type != dns_rdatatype_rrsig);
814         REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
815         REQUIRE(nodep == NULL || *nodep == NULL);
816
817         /*
818          * Initialize.
819          */
820         dns_rdataset_init(&zrdataset);
821         dns_rdataset_init(&zsigrdataset);
822         zdb = NULL;
823         znode = NULL;
824
825         /*
826          * Find a database to answer the query.
827          */
828         zone = NULL;
829         db = NULL;
830         node = NULL;
831 #ifdef BIND9
832         result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
833         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
834                 result = dns_zone_getdb(zone, &db);
835                 if (result != ISC_R_SUCCESS && view->cachedb != NULL)
836                         dns_db_attach(view->cachedb, &db);
837                 else if (result != ISC_R_SUCCESS)
838                         goto cleanup;
839         } else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
840                 dns_db_attach(view->cachedb, &db);
841 #else
842         result = ISC_R_NOTFOUND;
843         if (view->cachedb != NULL)
844                 dns_db_attach(view->cachedb, &db);
845 #endif /* BIND9 */
846         else
847                 goto cleanup;
848
849         is_cache = dns_db_iscache(db);
850
851  db_find:
852         /*
853          * Now look for an answer in the database.
854          */
855         result = dns_db_find(db, name, NULL, type, options,
856                              now, &node, foundname, rdataset, sigrdataset);
857
858         if (result == DNS_R_DELEGATION ||
859             result == ISC_R_NOTFOUND) {
860                 if (dns_rdataset_isassociated(rdataset))
861                         dns_rdataset_disassociate(rdataset);
862                 if (sigrdataset != NULL &&
863                     dns_rdataset_isassociated(sigrdataset))
864                         dns_rdataset_disassociate(sigrdataset);
865                 if (node != NULL)
866                         dns_db_detachnode(db, &node);
867                 if (!is_cache) {
868                         dns_db_detach(&db);
869                         if (view->cachedb != NULL) {
870                                 /*
871                                  * Either the answer is in the cache, or we
872                                  * don't know it.
873                                  */
874                                 is_cache = ISC_TRUE;
875                                 dns_db_attach(view->cachedb, &db);
876                                 goto db_find;
877                         }
878                 } else {
879                         /*
880                          * We don't have the data in the cache.  If we've got
881                          * glue from the zone, use it.
882                          */
883                         if (dns_rdataset_isassociated(&zrdataset)) {
884                                 dns_rdataset_clone(&zrdataset, rdataset);
885                                 if (sigrdataset != NULL &&
886                                     dns_rdataset_isassociated(&zsigrdataset))
887                                         dns_rdataset_clone(&zsigrdataset,
888                                                            sigrdataset);
889                                 result = DNS_R_GLUE;
890                                 if (db != NULL)
891                                         dns_db_detach(&db);
892                                 dns_db_attach(zdb, &db);
893                                 dns_db_attachnode(db, znode, &node);
894                                 goto cleanup;
895                         }
896                 }
897                 /*
898                  * We don't know the answer.
899                  */
900                 result = ISC_R_NOTFOUND;
901         } else if (result == DNS_R_GLUE) {
902                 if (view->cachedb != NULL) {
903                         /*
904                          * We found an answer, but the cache may be better.
905                          * Remember what we've got and go look in the cache.
906                          */
907                         is_cache = ISC_TRUE;
908                         dns_rdataset_clone(rdataset, &zrdataset);
909                         dns_rdataset_disassociate(rdataset);
910                         if (sigrdataset != NULL &&
911                             dns_rdataset_isassociated(sigrdataset)) {
912                                 dns_rdataset_clone(sigrdataset, &zsigrdataset);
913                                 dns_rdataset_disassociate(sigrdataset);
914                         }
915                         dns_db_attach(db, &zdb);
916                         dns_db_attachnode(zdb, node, &znode);
917                         dns_db_detachnode(db, &node);
918                         dns_db_detach(&db);
919                         dns_db_attach(view->cachedb, &db);
920                         goto db_find;
921                 }
922                 /*
923                  * Otherwise, the glue is the best answer.
924                  */
925                 result = ISC_R_SUCCESS;
926         }
927
928 #ifdef BIND9
929         if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
930                 if (dns_rdataset_isassociated(rdataset))
931                         dns_rdataset_disassociate(rdataset);
932                 if (sigrdataset != NULL &&
933                     dns_rdataset_isassociated(sigrdataset))
934                         dns_rdataset_disassociate(sigrdataset);
935                 if (db != NULL) {
936                         if (node != NULL)
937                                 dns_db_detachnode(db, &node);
938                         dns_db_detach(&db);
939                 }
940                 result = dns_db_find(view->hints, name, NULL, type, options,
941                                      now, &node, foundname,
942                                      rdataset, sigrdataset);
943                 if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
944                         /*
945                          * We just used a hint.  Let the resolver know it
946                          * should consider priming.
947                          */
948                         dns_resolver_prime(view->resolver);
949                         dns_db_attach(view->hints, &db);
950                         result = DNS_R_HINT;
951                 } else if (result == DNS_R_NXRRSET) {
952                         dns_db_attach(view->hints, &db);
953                         result = DNS_R_HINTNXRRSET;
954                 } else if (result == DNS_R_NXDOMAIN)
955                         result = ISC_R_NOTFOUND;
956
957                 /*
958                  * Cleanup if non-standard hints are used.
959                  */
960                 if (db == NULL && node != NULL)
961                         dns_db_detachnode(view->hints, &node);
962         }
963 #endif /* BIND9 */
964
965  cleanup:
966         if (dns_rdataset_isassociated(&zrdataset)) {
967                 dns_rdataset_disassociate(&zrdataset);
968                 if (dns_rdataset_isassociated(&zsigrdataset))
969                         dns_rdataset_disassociate(&zsigrdataset);
970         }
971
972         if (zdb != NULL) {
973                 if (znode != NULL)
974                         dns_db_detachnode(zdb, &znode);
975                 dns_db_detach(&zdb);
976         }
977
978         if (db != NULL) {
979                 if (node != NULL) {
980                         if (nodep != NULL)
981                                 *nodep = node;
982                         else
983                                 dns_db_detachnode(db, &node);
984                 }
985                 if (dbp != NULL)
986                         *dbp = db;
987                 else
988                         dns_db_detach(&db);
989         } else
990                 INSIST(node == NULL);
991
992 #ifdef BIND9
993         if (zone != NULL)
994                 dns_zone_detach(&zone);
995 #endif
996
997         return (result);
998 }
999
1000 isc_result_t
1001 dns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
1002                     isc_stdtime_t now, unsigned int options,
1003                     isc_boolean_t use_hints,
1004                     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1005 {
1006         isc_result_t result;
1007         dns_fixedname_t foundname;
1008
1009         dns_fixedname_init(&foundname);
1010         result = dns_view_find(view, name, type, now, options, use_hints,
1011                                NULL, NULL, dns_fixedname_name(&foundname),
1012                                rdataset, sigrdataset);
1013         if (result == DNS_R_NXDOMAIN) {
1014                 /*
1015                  * The rdataset and sigrdataset of the relevant NSEC record
1016                  * may be returned, but the caller cannot use them because
1017                  * foundname is not returned by this simplified API.  We
1018                  * disassociate them here to prevent any misuse by the caller.
1019                  */
1020                 if (dns_rdataset_isassociated(rdataset))
1021                         dns_rdataset_disassociate(rdataset);
1022                 if (sigrdataset != NULL &&
1023                     dns_rdataset_isassociated(sigrdataset))
1024                         dns_rdataset_disassociate(sigrdataset);
1025         } else if (result != ISC_R_SUCCESS &&
1026                    result != DNS_R_GLUE &&
1027                    result != DNS_R_HINT &&
1028                    result != DNS_R_NCACHENXDOMAIN &&
1029                    result != DNS_R_NCACHENXRRSET &&
1030                    result != DNS_R_NXRRSET &&
1031                    result != DNS_R_HINTNXRRSET &&
1032                    result != ISC_R_NOTFOUND) {
1033                 if (dns_rdataset_isassociated(rdataset))
1034                         dns_rdataset_disassociate(rdataset);
1035                 if (sigrdataset != NULL &&
1036                     dns_rdataset_isassociated(sigrdataset))
1037                         dns_rdataset_disassociate(sigrdataset);
1038                 result = ISC_R_NOTFOUND;
1039         }
1040
1041         return (result);
1042 }
1043
1044 isc_result_t
1045 dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1046                      isc_stdtime_t now, unsigned int options,
1047                      isc_boolean_t use_hints,
1048                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1049 {
1050         return(dns_view_findzonecut2(view, name, fname, now, options,
1051                                      use_hints, ISC_TRUE,
1052                                      rdataset, sigrdataset));
1053 }
1054
1055 isc_result_t
1056 dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
1057                       isc_stdtime_t now, unsigned int options,
1058                       isc_boolean_t use_hints,  isc_boolean_t use_cache,
1059                       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1060 {
1061         isc_result_t result;
1062         dns_db_t *db;
1063         isc_boolean_t is_cache, use_zone, try_hints;
1064         dns_zone_t *zone;
1065         dns_name_t *zfname;
1066         dns_rdataset_t zrdataset, zsigrdataset;
1067         dns_fixedname_t zfixedname;
1068
1069         REQUIRE(DNS_VIEW_VALID(view));
1070         REQUIRE(view->frozen);
1071
1072         db = NULL;
1073         zone = NULL;
1074         use_zone = ISC_FALSE;
1075         try_hints = ISC_FALSE;
1076         zfname = NULL;
1077
1078         /*
1079          * Initialize.
1080          */
1081         dns_fixedname_init(&zfixedname);
1082         dns_rdataset_init(&zrdataset);
1083         dns_rdataset_init(&zsigrdataset);
1084
1085         /*
1086          * Find the right database.
1087          */
1088 #ifdef BIND9
1089         result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
1090         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
1091                 result = dns_zone_getdb(zone, &db);
1092 #else
1093         result = ISC_R_NOTFOUND;
1094 #endif
1095         if (result == ISC_R_NOTFOUND) {
1096                 /*
1097                  * We're not directly authoritative for this query name, nor
1098                  * is it a subdomain of any zone for which we're
1099                  * authoritative.
1100                  */
1101                 if (use_cache && view->cachedb != NULL) {
1102                         /*
1103                          * We have a cache; try it.
1104                          */
1105                         dns_db_attach(view->cachedb, &db);
1106                 } else {
1107                         /*
1108                          * Maybe we have hints...
1109                          */
1110                         try_hints = ISC_TRUE;
1111                         goto finish;
1112                 }
1113         } else if (result != ISC_R_SUCCESS) {
1114                 /*
1115                  * Something is broken.
1116                  */
1117                 goto cleanup;
1118         }
1119         is_cache = dns_db_iscache(db);
1120
1121  db_find:
1122         /*
1123          * Look for the zonecut.
1124          */
1125         if (!is_cache) {
1126                 result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
1127                                      now, NULL, fname, rdataset, sigrdataset);
1128                 if (result == DNS_R_DELEGATION)
1129                         result = ISC_R_SUCCESS;
1130                 else if (result != ISC_R_SUCCESS)
1131                         goto cleanup;
1132                 if (use_cache && view->cachedb != NULL && db != view->hints) {
1133                         /*
1134                          * We found an answer, but the cache may be better.
1135                          */
1136                         zfname = dns_fixedname_name(&zfixedname);
1137                         result = dns_name_copy(fname, zfname, NULL);
1138                         if (result != ISC_R_SUCCESS)
1139                                 goto cleanup;
1140                         dns_rdataset_clone(rdataset, &zrdataset);
1141                         dns_rdataset_disassociate(rdataset);
1142                         if (sigrdataset != NULL &&
1143                             dns_rdataset_isassociated(sigrdataset)) {
1144                                 dns_rdataset_clone(sigrdataset, &zsigrdataset);
1145                                 dns_rdataset_disassociate(sigrdataset);
1146                         }
1147                         dns_db_detach(&db);
1148                         dns_db_attach(view->cachedb, &db);
1149                         is_cache = ISC_TRUE;
1150                         goto db_find;
1151                 }
1152         } else {
1153                 result = dns_db_findzonecut(db, name, options, now, NULL,
1154                                             fname, rdataset, sigrdataset);
1155                 if (result == ISC_R_SUCCESS) {
1156                         if (zfname != NULL &&
1157                             !dns_name_issubdomain(fname, zfname)) {
1158                                 /*
1159                                  * We found a zonecut in the cache, but our
1160                                  * zone delegation is better.
1161                                  */
1162                                 use_zone = ISC_TRUE;
1163                         }
1164                 } else if (result == ISC_R_NOTFOUND) {
1165                         if (zfname != NULL) {
1166                                 /*
1167                                  * We didn't find anything in the cache, but we
1168                                  * have a zone delegation, so use it.
1169                                  */
1170                                 use_zone = ISC_TRUE;
1171                         } else {
1172                                 /*
1173                                  * Maybe we have hints...
1174                                  */
1175                                 try_hints = ISC_TRUE;
1176                         }
1177                 } else {
1178                         /*
1179                          * Something bad happened.
1180                          */
1181                         goto cleanup;
1182                 }
1183         }
1184
1185  finish:
1186         if (use_zone) {
1187                 if (dns_rdataset_isassociated(rdataset)) {
1188                         dns_rdataset_disassociate(rdataset);
1189                         if (sigrdataset != NULL &&
1190                             dns_rdataset_isassociated(sigrdataset))
1191                                 dns_rdataset_disassociate(sigrdataset);
1192                 }
1193                 result = dns_name_copy(zfname, fname, NULL);
1194                 if (result != ISC_R_SUCCESS)
1195                         goto cleanup;
1196                 dns_rdataset_clone(&zrdataset, rdataset);
1197                 if (sigrdataset != NULL &&
1198                     dns_rdataset_isassociated(&zrdataset))
1199                         dns_rdataset_clone(&zsigrdataset, sigrdataset);
1200         } else if (try_hints && use_hints && view->hints != NULL) {
1201                 /*
1202                  * We've found nothing so far, but we have hints.
1203                  */
1204                 result = dns_db_find(view->hints, dns_rootname, NULL,
1205                                      dns_rdatatype_ns, 0, now, NULL, fname,
1206                                      rdataset, NULL);
1207                 if (result != ISC_R_SUCCESS) {
1208                         /*
1209                          * We can't even find the hints for the root
1210                          * nameservers!
1211                          */
1212                         if (dns_rdataset_isassociated(rdataset))
1213                                 dns_rdataset_disassociate(rdataset);
1214                         result = ISC_R_NOTFOUND;
1215                 }
1216         }
1217
1218  cleanup:
1219         if (dns_rdataset_isassociated(&zrdataset)) {
1220                 dns_rdataset_disassociate(&zrdataset);
1221                 if (dns_rdataset_isassociated(&zsigrdataset))
1222                         dns_rdataset_disassociate(&zsigrdataset);
1223         }
1224         if (db != NULL)
1225                 dns_db_detach(&db);
1226 #ifdef BIND9
1227         if (zone != NULL)
1228                 dns_zone_detach(&zone);
1229 #endif
1230
1231         return (result);
1232 }
1233
1234 isc_result_t
1235 dns_viewlist_find(dns_viewlist_t *list, const char *name,
1236                   dns_rdataclass_t rdclass, dns_view_t **viewp)
1237 {
1238         dns_view_t *view;
1239
1240         REQUIRE(list != NULL);
1241
1242         for (view = ISC_LIST_HEAD(*list);
1243              view != NULL;
1244              view = ISC_LIST_NEXT(view, link)) {
1245                 if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
1246                         break;
1247         }
1248         if (view == NULL)
1249                 return (ISC_R_NOTFOUND);
1250
1251         dns_view_attach(view, viewp);
1252
1253         return (ISC_R_SUCCESS);
1254 }
1255
1256 #ifdef BIND9
1257 isc_result_t
1258 dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name,
1259                       isc_boolean_t allclasses, dns_rdataclass_t rdclass,
1260                       dns_zone_t **zonep)
1261 {
1262         dns_view_t *view;
1263         isc_result_t result;
1264         dns_zone_t *zone1 = NULL, *zone2 = NULL;
1265         dns_zone_t **zp = NULL;;
1266
1267         REQUIRE(list != NULL);
1268         for (view = ISC_LIST_HEAD(*list);
1269              view != NULL;
1270              view = ISC_LIST_NEXT(view, link)) {
1271                 if (allclasses == ISC_FALSE && view->rdclass != rdclass)
1272                         continue;
1273
1274                 /*
1275                  * If the zone is defined in more than one view,
1276                  * treat it as not found.
1277                  */
1278                 zp = (zone1 == NULL) ? &zone1 : &zone2;
1279                 result = dns_zt_find(view->zonetable, name, 0, NULL, zp);
1280                 INSIST(result == ISC_R_SUCCESS ||
1281                        result == ISC_R_NOTFOUND ||
1282                        result == DNS_R_PARTIALMATCH);
1283
1284                 /* Treat a partial match as no match */
1285                 if (result == DNS_R_PARTIALMATCH) {
1286                         dns_zone_detach(zp);
1287                         result = ISC_R_NOTFOUND;
1288                 }
1289
1290                 if (zone2 != NULL) {
1291                         dns_zone_detach(&zone1);
1292                         dns_zone_detach(&zone2);
1293                         return (ISC_R_NOTFOUND);
1294                 }
1295         }
1296
1297         if (zone1 != NULL) {
1298                 dns_zone_attach(zone1, zonep);
1299                 dns_zone_detach(&zone1);
1300                 return (ISC_R_SUCCESS);
1301         }
1302
1303         return (ISC_R_NOTFOUND);
1304 }
1305
1306 isc_result_t
1307 dns_view_load(dns_view_t *view, isc_boolean_t stop) {
1308
1309         REQUIRE(DNS_VIEW_VALID(view));
1310
1311         return (dns_zt_load(view->zonetable, stop));
1312 }
1313
1314 isc_result_t
1315 dns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
1316
1317         REQUIRE(DNS_VIEW_VALID(view));
1318
1319         return (dns_zt_loadnew(view->zonetable, stop));
1320 }
1321 #endif /* BIND9 */
1322
1323 isc_result_t
1324 dns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp)
1325 {
1326         isc_result_t result;
1327         REQUIRE(keyp != NULL && *keyp == NULL);
1328
1329         result = dns_tsigkey_find(keyp, keyname, NULL,
1330                                   view->statickeys);
1331         if (result == ISC_R_NOTFOUND)
1332                 result = dns_tsigkey_find(keyp, keyname, NULL,
1333                                           view->dynamickeys);
1334         return (result);
1335 }
1336
1337 isc_result_t
1338 dns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
1339                      dns_tsigkey_t **keyp)
1340 {
1341         isc_result_t result;
1342         dns_name_t *keyname = NULL;
1343         dns_peer_t *peer = NULL;
1344
1345         result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
1346         if (result != ISC_R_SUCCESS)
1347                 return (result);
1348
1349         result = dns_peer_getkey(peer, &keyname);
1350         if (result != ISC_R_SUCCESS)
1351                 return (result);
1352
1353         result = dns_view_gettsig(view, keyname, keyp);
1354         return ((result == ISC_R_NOTFOUND) ? ISC_R_FAILURE : result);
1355 }
1356
1357 isc_result_t
1358 dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
1359         REQUIRE(DNS_VIEW_VALID(view));
1360         REQUIRE(source != NULL);
1361
1362         return (dns_tsig_verify(source, msg, view->statickeys,
1363                                 view->dynamickeys));
1364 }
1365
1366 #ifdef BIND9
1367 isc_result_t
1368 dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
1369         isc_result_t result;
1370
1371         REQUIRE(DNS_VIEW_VALID(view));
1372
1373         (void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
1374         result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
1375                                          &dns_master_style_cache, fp);
1376         if (result != ISC_R_SUCCESS)
1377                 return (result);
1378         dns_adb_dump(view->adb, fp);
1379         dns_resolver_printbadcache(view->resolver, fp);
1380         return (ISC_R_SUCCESS);
1381 }
1382 #endif
1383
1384 isc_result_t
1385 dns_view_flushcache(dns_view_t *view) {
1386         return (dns_view_flushcache2(view, ISC_FALSE));
1387 }
1388
1389 isc_result_t
1390 dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) {
1391         isc_result_t result;
1392
1393         REQUIRE(DNS_VIEW_VALID(view));
1394
1395         if (view->cachedb == NULL)
1396                 return (ISC_R_SUCCESS);
1397         if (!fixuponly) {
1398                 result = dns_cache_flush(view->cache);
1399                 if (result != ISC_R_SUCCESS)
1400                         return (result);
1401         }
1402 #ifdef BIND9
1403         if (view->acache != NULL)
1404                 dns_acache_putdb(view->acache, view->cachedb);
1405 #endif
1406         dns_db_detach(&view->cachedb);
1407         dns_cache_attachdb(view->cache, &view->cachedb);
1408 #ifdef BIND9
1409         if (view->acache != NULL)
1410                 dns_acache_setdb(view->acache, view->cachedb);
1411         if (view->resolver != NULL)
1412                 dns_resolver_flushbadcache(view->resolver, NULL);
1413 #endif
1414
1415         dns_adb_flush(view->adb);
1416         return (ISC_R_SUCCESS);
1417 }
1418
1419 isc_result_t
1420 dns_view_flushname(dns_view_t *view, dns_name_t *name) {
1421
1422         REQUIRE(DNS_VIEW_VALID(view));
1423
1424         if (view->adb != NULL)
1425                 dns_adb_flushname(view->adb, name);
1426         if (view->cache == NULL)
1427                 return (ISC_R_SUCCESS);
1428         if (view->resolver != NULL)
1429                 dns_resolver_flushbadcache(view->resolver, name);
1430         return (dns_cache_flushname(view->cache, name));
1431 }
1432
1433 isc_result_t
1434 dns_view_adddelegationonly(dns_view_t *view, dns_name_t *name) {
1435         isc_result_t result;
1436         dns_name_t *new;
1437         isc_uint32_t hash;
1438
1439         REQUIRE(DNS_VIEW_VALID(view));
1440
1441         if (view->delonly == NULL) {
1442                 view->delonly = isc_mem_get(view->mctx,
1443                                             sizeof(dns_namelist_t) *
1444                                             DNS_VIEW_DELONLYHASH);
1445                 if (view->delonly == NULL)
1446                         return (ISC_R_NOMEMORY);
1447                 for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1448                         ISC_LIST_INIT(view->delonly[hash]);
1449         }
1450         hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1451         new = ISC_LIST_HEAD(view->delonly[hash]);
1452         while (new != NULL && !dns_name_equal(new, name))
1453                 new = ISC_LIST_NEXT(new, link);
1454         if (new != NULL)
1455                 return (ISC_R_SUCCESS);
1456         new = isc_mem_get(view->mctx, sizeof(*new));
1457         if (new == NULL)
1458                 return (ISC_R_NOMEMORY);
1459         dns_name_init(new, NULL);
1460         result = dns_name_dup(name, view->mctx, new);
1461         if (result == ISC_R_SUCCESS)
1462                 ISC_LIST_APPEND(view->delonly[hash], new, link);
1463         else
1464                 isc_mem_put(view->mctx, new, sizeof(*new));
1465         return (result);
1466 }
1467
1468 isc_result_t
1469 dns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name) {
1470         isc_result_t result;
1471         dns_name_t *new;
1472         isc_uint32_t hash;
1473
1474         REQUIRE(DNS_VIEW_VALID(view));
1475
1476         if (view->rootexclude == NULL) {
1477                 view->rootexclude = isc_mem_get(view->mctx,
1478                                             sizeof(dns_namelist_t) *
1479                                             DNS_VIEW_DELONLYHASH);
1480                 if (view->rootexclude == NULL)
1481                         return (ISC_R_NOMEMORY);
1482                 for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1483                         ISC_LIST_INIT(view->rootexclude[hash]);
1484         }
1485         hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1486         new = ISC_LIST_HEAD(view->rootexclude[hash]);
1487         while (new != NULL && !dns_name_equal(new, name))
1488                 new = ISC_LIST_NEXT(new, link);
1489         if (new != NULL)
1490                 return (ISC_R_SUCCESS);
1491         new = isc_mem_get(view->mctx, sizeof(*new));
1492         if (new == NULL)
1493                 return (ISC_R_NOMEMORY);
1494         dns_name_init(new, NULL);
1495         result = dns_name_dup(name, view->mctx, new);
1496         if (result == ISC_R_SUCCESS)
1497                 ISC_LIST_APPEND(view->rootexclude[hash], new, link);
1498         else
1499                 isc_mem_put(view->mctx, new, sizeof(*new));
1500         return (result);
1501 }
1502
1503 isc_boolean_t
1504 dns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
1505         dns_name_t *new;
1506         isc_uint32_t hash;
1507
1508         REQUIRE(DNS_VIEW_VALID(view));
1509
1510         if (!view->rootdelonly && view->delonly == NULL)
1511                 return (ISC_FALSE);
1512
1513         hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1514         if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
1515                 if (view->rootexclude == NULL)
1516                         return (ISC_TRUE);
1517                 new = ISC_LIST_HEAD(view->rootexclude[hash]);
1518                 while (new != NULL && !dns_name_equal(new, name))
1519                         new = ISC_LIST_NEXT(new, link);
1520                 if (new == NULL)
1521                         return (ISC_TRUE);
1522         }
1523
1524         if (view->delonly == NULL)
1525                 return (ISC_FALSE);
1526
1527         new = ISC_LIST_HEAD(view->delonly[hash]);
1528         while (new != NULL && !dns_name_equal(new, name))
1529                 new = ISC_LIST_NEXT(new, link);
1530         if (new == NULL)
1531                 return (ISC_FALSE);
1532         return (ISC_TRUE);
1533 }
1534
1535 void
1536 dns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
1537         REQUIRE(DNS_VIEW_VALID(view));
1538         view->rootdelonly = value;
1539 }
1540
1541 isc_boolean_t
1542 dns_view_getrootdelonly(dns_view_t *view) {
1543         REQUIRE(DNS_VIEW_VALID(view));
1544         return (view->rootdelonly);
1545 }
1546
1547 #ifdef BIND9
1548 isc_result_t
1549 dns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
1550         REQUIRE(DNS_VIEW_VALID(view));
1551         return (dns_zt_freezezones(view->zonetable, value));
1552 }
1553 #endif
1554
1555 void
1556 dns_view_setresstats(dns_view_t *view, isc_stats_t *stats) {
1557         REQUIRE(DNS_VIEW_VALID(view));
1558         REQUIRE(!view->frozen);
1559         REQUIRE(view->resstats == NULL);
1560
1561         isc_stats_attach(stats, &view->resstats);
1562 }
1563
1564 void
1565 dns_view_getresstats(dns_view_t *view, isc_stats_t **statsp) {
1566         REQUIRE(DNS_VIEW_VALID(view));
1567         REQUIRE(statsp != NULL && *statsp == NULL);
1568
1569         if (view->resstats != NULL)
1570                 isc_stats_attach(view->resstats, statsp);
1571 }
1572
1573 void
1574 dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats) {
1575         REQUIRE(DNS_VIEW_VALID(view));
1576         REQUIRE(!view->frozen);
1577         REQUIRE(view->resquerystats == NULL);
1578
1579         dns_stats_attach(stats, &view->resquerystats);
1580 }
1581
1582 void
1583 dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) {
1584         REQUIRE(DNS_VIEW_VALID(view));
1585         REQUIRE(statsp != NULL && *statsp == NULL);
1586
1587         if (view->resquerystats != NULL)
1588                 dns_stats_attach(view->resquerystats, statsp);
1589 }
1590
1591 isc_result_t
1592 dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx) {
1593         REQUIRE(DNS_VIEW_VALID(view));
1594         if (view->secroots_priv != NULL)
1595                 dns_keytable_detach(&view->secroots_priv);
1596         return (dns_keytable_create(mctx, &view->secroots_priv));
1597 }
1598
1599 isc_result_t
1600 dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp) {
1601         REQUIRE(DNS_VIEW_VALID(view));
1602         REQUIRE(ktp != NULL && *ktp == NULL);
1603         if (view->secroots_priv == NULL)
1604                 return (ISC_R_NOTFOUND);
1605         dns_keytable_attach(view->secroots_priv, ktp);
1606         return (ISC_R_SUCCESS);
1607 }
1608
1609 isc_result_t
1610 dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
1611                          isc_boolean_t *secure_domain) {
1612         REQUIRE(DNS_VIEW_VALID(view));
1613         return (dns_keytable_issecuredomain(view->secroots_priv, name,
1614                                             secure_domain));
1615 }
1616
1617 void
1618 dns_view_untrust(dns_view_t *view, dns_name_t *keyname,
1619                  dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
1620 {
1621         isc_result_t result;
1622         unsigned char data[4096];
1623         dns_rdata_t rdata = DNS_RDATA_INIT;
1624         isc_buffer_t buffer;
1625         dst_key_t *key = NULL;
1626         dns_keytable_t *sr = NULL;
1627
1628         /*
1629          * Clear the revoke bit, if set, so that the key will match what's
1630          * in secroots now.
1631          */
1632         dnskey->flags &= ~DNS_KEYFLAG_REVOKE;
1633
1634         /* Convert dnskey to DST key. */
1635         isc_buffer_init(&buffer, data, sizeof(data));
1636         dns_rdata_fromstruct(&rdata, dnskey->common.rdclass,
1637                              dns_rdatatype_dnskey, dnskey, &buffer);
1638         result = dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &key);
1639         if (result != ISC_R_SUCCESS)
1640                 return;
1641         result = dns_view_getsecroots(view, &sr);
1642         if (result == ISC_R_SUCCESS) {
1643                 dns_keytable_deletekeynode(sr, key);
1644                 dns_keytable_detach(&sr);
1645         }
1646         dst_key_free(&key);
1647 }
1648
1649 #define NZF ".nzf"
1650
1651 void
1652 dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
1653                      void (*cfg_destroy)(void **))
1654 {
1655         REQUIRE(DNS_VIEW_VALID(view));
1656         REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
1657
1658 #ifdef BIND9
1659         if (view->new_zone_file != NULL) {
1660                 isc_mem_free(view->mctx, view->new_zone_file);
1661                 view->new_zone_file = NULL;
1662         }
1663
1664         if (view->new_zone_config != NULL) {
1665                 view->cfg_destroy(&view->new_zone_config);
1666                 view->cfg_destroy = NULL;
1667         }
1668
1669         if (allow) {
1670                 char buffer[ISC_SHA256_DIGESTSTRINGLENGTH + sizeof(NZF)];
1671                 isc_sha256_data((void *)view->name, strlen(view->name), buffer);
1672                 /* Truncate the hash at 16 chars; full length is overkill */
1673                 isc_string_printf(buffer + 16, sizeof(NZF), "%s", NZF);
1674                 view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
1675                 view->new_zone_config = cfgctx;
1676                 view->cfg_destroy = cfg_destroy;
1677         }
1678 #else
1679         UNUSED(allow);
1680         UNUSED(cfgctx);
1681         UNUSED(cfg_destroy);
1682 #endif
1683 }