]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/bind9/lib/dns/view.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / bind9 / lib / dns / view.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: view.c,v 1.126.18.16 2008/06/17 23:46:03 tbox Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <isc/hash.h>
25 #include <isc/task.h>
26 #include <isc/string.h>         /* Required for HP/UX (and others?) */
27 #include <isc/util.h>
28
29 #include <dns/acache.h>
30 #include <dns/acl.h>
31 #include <dns/adb.h>
32 #include <dns/cache.h>
33 #include <dns/db.h>
34 #include <dns/dlz.h>
35 #include <dns/events.h>
36 #include <dns/forward.h>
37 #include <dns/keytable.h>
38 #include <dns/master.h>
39 #include <dns/masterdump.h>
40 #include <dns/order.h>
41 #include <dns/peer.h>
42 #include <dns/rdataset.h>
43 #include <dns/request.h>
44 #include <dns/resolver.h>
45 #include <dns/result.h>
46 #include <dns/tsig.h>
47 #include <dns/zone.h>
48 #include <dns/zt.h>
49
50 #define RESSHUTDOWN(v)  (((v)->attributes & DNS_VIEWATTR_RESSHUTDOWN) != 0)
51 #define ADBSHUTDOWN(v)  (((v)->attributes & DNS_VIEWATTR_ADBSHUTDOWN) != 0)
52 #define REQSHUTDOWN(v)  (((v)->attributes & DNS_VIEWATTR_REQSHUTDOWN) != 0)
53
54 #define DNS_VIEW_DELONLYHASH 111
55
56 static void resolver_shutdown(isc_task_t *task, isc_event_t *event);
57 static void adb_shutdown(isc_task_t *task, isc_event_t *event);
58 static void req_shutdown(isc_task_t *task, isc_event_t *event);
59
60 isc_result_t
61 dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
62                 const char *name, dns_view_t **viewp)
63 {
64         dns_view_t *view;
65         isc_result_t result;
66
67         /*
68          * Create a view.
69          */
70
71         REQUIRE(name != NULL);
72         REQUIRE(viewp != NULL && *viewp == NULL);
73
74         view = isc_mem_get(mctx, sizeof(*view));
75         if (view == NULL)
76                 return (ISC_R_NOMEMORY);
77         view->name = isc_mem_strdup(mctx, name);
78         if (view->name == NULL) {
79                 result = ISC_R_NOMEMORY;
80                 goto cleanup_view;
81         }
82         result = isc_mutex_init(&view->lock);
83         if (result != ISC_R_SUCCESS)
84                 goto cleanup_name;
85
86         view->zonetable = NULL;
87         result = dns_zt_create(mctx, rdclass, &view->zonetable);
88         if (result != ISC_R_SUCCESS) {
89                 UNEXPECTED_ERROR(__FILE__, __LINE__,
90                                  "dns_zt_create() failed: %s",
91                                  isc_result_totext(result));
92                 result = ISC_R_UNEXPECTED;
93                 goto cleanup_mutex;
94         }
95         view->secroots = NULL;
96         result = dns_keytable_create(mctx, &view->secroots);
97         if (result != ISC_R_SUCCESS) {
98                 UNEXPECTED_ERROR(__FILE__, __LINE__,
99                                  "dns_keytable_create() failed: %s",
100                                  isc_result_totext(result));
101                 result = ISC_R_UNEXPECTED;
102                 goto cleanup_zt;
103         }
104         view->trustedkeys = NULL;
105         result = dns_keytable_create(mctx, &view->trustedkeys);
106         if (result != ISC_R_SUCCESS) {
107                 UNEXPECTED_ERROR(__FILE__, __LINE__,
108                                  "dns_keytable_create() failed: %s",
109                                  isc_result_totext(result));
110                 result = ISC_R_UNEXPECTED;
111                 goto cleanup_secroots;
112         }
113         view->fwdtable = NULL;
114         result = dns_fwdtable_create(mctx, &view->fwdtable);
115         if (result != ISC_R_SUCCESS) {
116                 UNEXPECTED_ERROR(__FILE__, __LINE__,
117                                  "dns_fwdtable_create() failed: %s",
118                                  isc_result_totext(result));
119                 result = ISC_R_UNEXPECTED;
120                 goto cleanup_trustedkeys;
121         }
122
123         view->acache = NULL;
124         view->cache = NULL;
125         view->cachedb = NULL;
126         view->dlzdatabase = NULL;
127         view->hints = NULL;
128         view->resolver = NULL;
129         view->adb = NULL;
130         view->requestmgr = NULL;
131         view->mctx = mctx;
132         view->rdclass = rdclass;
133         view->frozen = ISC_FALSE;
134         view->task = NULL;
135         result = isc_refcount_init(&view->references, 1);
136         if (result != ISC_R_SUCCESS)
137                 goto cleanup_fwdtable;
138         view->weakrefs = 0;
139         view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
140                             DNS_VIEWATTR_REQSHUTDOWN);
141         view->statickeys = NULL;
142         view->dynamickeys = NULL;
143         view->matchclients = NULL;
144         view->matchdestinations = NULL;
145         view->matchrecursiveonly = ISC_FALSE;
146         result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
147         if (result != ISC_R_SUCCESS)
148                 goto cleanup_references;
149         view->peers = NULL;
150         view->order = NULL;
151         view->delonly = NULL;
152         view->rootdelonly = ISC_FALSE;
153         view->rootexclude = NULL;
154
155         /*
156          * Initialize configuration data with default values.
157          */
158         view->recursion = ISC_TRUE;
159         view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
160         view->additionalfromcache = ISC_TRUE;
161         view->additionalfromauth = ISC_TRUE;
162         view->enablednssec = ISC_TRUE;
163         view->enablevalidation = ISC_TRUE;
164         view->acceptexpired = ISC_FALSE;
165         view->minimalresponses = ISC_FALSE;
166         view->transfer_format = dns_one_answer;
167         view->queryacl = NULL;
168         view->recursionacl = NULL;
169         view->sortlist = NULL;
170         view->requestixfr = ISC_TRUE;
171         view->provideixfr = ISC_TRUE;
172         view->maxcachettl = 7 * 24 * 3600;
173         view->maxncachettl = 3 * 3600;
174         view->dstport = 53;
175         view->preferred_glue = 0;
176         view->flush = ISC_FALSE;
177         view->dlv = NULL;
178         view->maxudp = 0;
179         dns_fixedname_init(&view->dlv_fixed);
180
181         result = dns_order_create(view->mctx, &view->order);
182         if (result != ISC_R_SUCCESS)
183                 goto cleanup_dynkeys;
184
185         result = dns_peerlist_new(view->mctx, &view->peers);
186         if (result != ISC_R_SUCCESS)
187                 goto cleanup_order;
188
189         result = dns_aclenv_init(view->mctx, &view->aclenv);
190         if (result != ISC_R_SUCCESS)
191                 goto cleanup_peerlist;
192
193         ISC_LINK_INIT(view, link);
194         ISC_EVENT_INIT(&view->resevent, sizeof(view->resevent), 0, NULL,
195                        DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
196                        view, NULL, NULL, NULL);
197         ISC_EVENT_INIT(&view->adbevent, sizeof(view->adbevent), 0, NULL,
198                        DNS_EVENT_VIEWADBSHUTDOWN, adb_shutdown,
199                        view, NULL, NULL, NULL);
200         ISC_EVENT_INIT(&view->reqevent, sizeof(view->reqevent), 0, NULL,
201                        DNS_EVENT_VIEWREQSHUTDOWN, req_shutdown,
202                        view, NULL, NULL, NULL);
203         view->magic = DNS_VIEW_MAGIC;
204
205         *viewp = view;
206
207         return (ISC_R_SUCCESS);
208
209  cleanup_peerlist:
210         dns_peerlist_detach(&view->peers);
211
212  cleanup_order:
213         dns_order_detach(&view->order);
214
215  cleanup_dynkeys:
216         dns_tsigkeyring_destroy(&view->dynamickeys);
217
218  cleanup_references:
219         isc_refcount_destroy(&view->references);
220
221  cleanup_fwdtable:
222         dns_fwdtable_destroy(&view->fwdtable);
223
224  cleanup_trustedkeys:
225         dns_keytable_detach(&view->trustedkeys);
226
227  cleanup_secroots:
228         dns_keytable_detach(&view->secroots);
229
230  cleanup_zt:
231         dns_zt_detach(&view->zonetable);
232
233  cleanup_mutex:
234         DESTROYLOCK(&view->lock);
235
236  cleanup_name:
237         isc_mem_free(mctx, view->name);
238
239  cleanup_view:
240         isc_mem_put(mctx, view, sizeof(*view));
241
242         return (result);
243 }
244
245 static inline void
246 destroy(dns_view_t *view) {
247         REQUIRE(!ISC_LINK_LINKED(view, link));
248         REQUIRE(isc_refcount_current(&view->references) == 0);
249         REQUIRE(view->weakrefs == 0);
250         REQUIRE(RESSHUTDOWN(view));
251         REQUIRE(ADBSHUTDOWN(view));
252         REQUIRE(REQSHUTDOWN(view));
253
254         if (view->order != NULL)
255                 dns_order_detach(&view->order);
256         if (view->peers != NULL)
257                 dns_peerlist_detach(&view->peers);
258         if (view->dynamickeys != NULL)
259                 dns_tsigkeyring_destroy(&view->dynamickeys);
260         if (view->statickeys != NULL)
261                 dns_tsigkeyring_destroy(&view->statickeys);
262         if (view->adb != NULL)
263                 dns_adb_detach(&view->adb);
264         if (view->resolver != NULL)
265                 dns_resolver_detach(&view->resolver);
266         if (view->acache != NULL) {
267                 if (view->cachedb != NULL)
268                         dns_acache_putdb(view->acache, view->cachedb);
269                 dns_acache_detach(&view->acache);
270         }
271         if (view->requestmgr != NULL)
272                 dns_requestmgr_detach(&view->requestmgr);
273         if (view->task != NULL)
274                 isc_task_detach(&view->task);
275         if (view->hints != NULL)
276                 dns_db_detach(&view->hints);
277         if (view->dlzdatabase != NULL)
278                 dns_dlzdestroy(&view->dlzdatabase);
279         if (view->cachedb != NULL)
280                 dns_db_detach(&view->cachedb);
281         if (view->cache != NULL)
282                 dns_cache_detach(&view->cache);
283         if (view->matchclients != NULL)
284                 dns_acl_detach(&view->matchclients);
285         if (view->matchdestinations != NULL)
286                 dns_acl_detach(&view->matchdestinations);
287         if (view->queryacl != NULL)
288                 dns_acl_detach(&view->queryacl);
289         if (view->recursionacl != NULL)
290                 dns_acl_detach(&view->recursionacl);
291         if (view->sortlist != NULL)
292                 dns_acl_detach(&view->sortlist);
293         if (view->delonly != NULL) {
294                 dns_name_t *name;
295                 int i;
296
297                 for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
298                         name = ISC_LIST_HEAD(view->delonly[i]);
299                         while (name != NULL) {
300                                 ISC_LIST_UNLINK(view->delonly[i], name, link);
301                                 dns_name_free(name, view->mctx);
302                                 isc_mem_put(view->mctx, name, sizeof(*name));
303                                 name = ISC_LIST_HEAD(view->delonly[i]);
304                         }
305                 }
306                 isc_mem_put(view->mctx, view->delonly, sizeof(dns_namelist_t) *
307                             DNS_VIEW_DELONLYHASH);
308                 view->delonly = NULL;
309         }
310         if (view->rootexclude != NULL) {
311                 dns_name_t *name;
312                 int i;
313
314                 for (i = 0; i < DNS_VIEW_DELONLYHASH; i++) {
315                         name = ISC_LIST_HEAD(view->rootexclude[i]);
316                         while (name != NULL) {
317                                 ISC_LIST_UNLINK(view->rootexclude[i],
318                                                 name, link);
319                                 dns_name_free(name, view->mctx);
320                                 isc_mem_put(view->mctx, name, sizeof(*name));
321                                 name = ISC_LIST_HEAD(view->rootexclude[i]);
322                         }
323                 }
324                 isc_mem_put(view->mctx, view->rootexclude,
325                             sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH);
326                 view->rootexclude = NULL;
327         }
328         dns_keytable_detach(&view->trustedkeys);
329         dns_keytable_detach(&view->secroots);
330         dns_fwdtable_destroy(&view->fwdtable);
331         dns_aclenv_destroy(&view->aclenv);
332         DESTROYLOCK(&view->lock);
333         isc_refcount_destroy(&view->references);
334         isc_mem_free(view->mctx, view->name);
335         isc_mem_put(view->mctx, view, sizeof(*view));
336 }
337
338 /*
339  * Return true iff 'view' may be freed.
340  * The caller must be holding the view lock.
341  */
342 static isc_boolean_t
343 all_done(dns_view_t *view) {
344
345         if (isc_refcount_current(&view->references) == 0 &&
346             view->weakrefs == 0 &&
347             RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
348                 return (ISC_TRUE);
349
350         return (ISC_FALSE);
351 }
352
353 void
354 dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
355
356         REQUIRE(DNS_VIEW_VALID(source));
357         REQUIRE(targetp != NULL && *targetp == NULL);
358
359         isc_refcount_increment(&source->references, NULL);
360
361         *targetp = source;
362 }
363
364 static void
365 view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
366         dns_view_t *view;
367         unsigned int refs;
368         isc_boolean_t done = ISC_FALSE;
369
370         REQUIRE(viewp != NULL);
371         view = *viewp;
372         REQUIRE(DNS_VIEW_VALID(view));
373
374         if (flush)
375                 view->flush = ISC_TRUE;
376         isc_refcount_decrement(&view->references, &refs);
377         if (refs == 0) {
378                 LOCK(&view->lock);
379                 if (!RESSHUTDOWN(view))
380                         dns_resolver_shutdown(view->resolver);
381                 if (!ADBSHUTDOWN(view))
382                         dns_adb_shutdown(view->adb);
383                 if (!REQSHUTDOWN(view))
384                         dns_requestmgr_shutdown(view->requestmgr);
385                 if (view->acache != NULL)
386                         dns_acache_shutdown(view->acache);
387                 if (view->flush)
388                         dns_zt_flushanddetach(&view->zonetable);
389                 else
390                         dns_zt_detach(&view->zonetable);
391                 done = all_done(view);
392                 UNLOCK(&view->lock);
393         }
394
395         *viewp = NULL;
396
397         if (done)
398                 destroy(view);
399 }
400
401 void
402 dns_view_flushanddetach(dns_view_t **viewp) {
403         view_flushanddetach(viewp, ISC_TRUE);
404 }
405
406 void
407 dns_view_detach(dns_view_t **viewp) {
408         view_flushanddetach(viewp, ISC_FALSE);
409 }
410
411 static isc_result_t
412 dialup(dns_zone_t *zone, void *dummy) {
413         UNUSED(dummy);
414         dns_zone_dialup(zone);
415         return (ISC_R_SUCCESS);
416 }
417
418 void
419 dns_view_dialup(dns_view_t *view) {
420         REQUIRE(DNS_VIEW_VALID(view));
421         (void)dns_zt_apply(view->zonetable, ISC_FALSE, dialup, NULL);
422 }
423
424 void
425 dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
426
427         REQUIRE(DNS_VIEW_VALID(source));
428         REQUIRE(targetp != NULL && *targetp == NULL);
429
430         LOCK(&source->lock);
431         source->weakrefs++;
432         UNLOCK(&source->lock);
433
434         *targetp = source;
435 }
436
437 void
438 dns_view_weakdetach(dns_view_t **viewp) {
439         dns_view_t *view;
440         isc_boolean_t done = ISC_FALSE;
441
442         REQUIRE(viewp != NULL);
443         view = *viewp;
444         REQUIRE(DNS_VIEW_VALID(view));
445
446         LOCK(&view->lock);
447
448         INSIST(view->weakrefs > 0);
449         view->weakrefs--;
450         done = all_done(view);
451
452         UNLOCK(&view->lock);
453
454         *viewp = NULL;
455
456         if (done)
457                 destroy(view);
458 }
459
460 static void
461 resolver_shutdown(isc_task_t *task, isc_event_t *event) {
462         dns_view_t *view = event->ev_arg;
463         isc_boolean_t done;
464
465         REQUIRE(event->ev_type == DNS_EVENT_VIEWRESSHUTDOWN);
466         REQUIRE(DNS_VIEW_VALID(view));
467         REQUIRE(view->task == task);
468
469         UNUSED(task);
470
471         LOCK(&view->lock);
472
473         view->attributes |= DNS_VIEWATTR_RESSHUTDOWN;
474         done = all_done(view);
475
476         UNLOCK(&view->lock);
477
478         isc_event_free(&event);
479
480         if (done)
481                 destroy(view);
482 }
483
484 static void
485 adb_shutdown(isc_task_t *task, isc_event_t *event) {
486         dns_view_t *view = event->ev_arg;
487         isc_boolean_t done;
488
489         REQUIRE(event->ev_type == DNS_EVENT_VIEWADBSHUTDOWN);
490         REQUIRE(DNS_VIEW_VALID(view));
491         REQUIRE(view->task == task);
492
493         UNUSED(task);
494
495         LOCK(&view->lock);
496
497         view->attributes |= DNS_VIEWATTR_ADBSHUTDOWN;
498         done = all_done(view);
499
500         UNLOCK(&view->lock);
501
502         isc_event_free(&event);
503
504         if (done)
505                 destroy(view);
506 }
507
508 static void
509 req_shutdown(isc_task_t *task, isc_event_t *event) {
510         dns_view_t *view = event->ev_arg;
511         isc_boolean_t done;
512
513         REQUIRE(event->ev_type == DNS_EVENT_VIEWREQSHUTDOWN);
514         REQUIRE(DNS_VIEW_VALID(view));
515         REQUIRE(view->task == task);
516
517         UNUSED(task);
518
519         LOCK(&view->lock);
520
521         view->attributes |= DNS_VIEWATTR_REQSHUTDOWN;
522         done = all_done(view);
523
524         UNLOCK(&view->lock);
525
526         isc_event_free(&event);
527
528         if (done)
529                 destroy(view);
530 }
531
532 isc_result_t
533 dns_view_createresolver(dns_view_t *view,
534                         isc_taskmgr_t *taskmgr, unsigned int ntasks,
535                         isc_socketmgr_t *socketmgr,
536                         isc_timermgr_t *timermgr,
537                         unsigned int options,
538                         dns_dispatchmgr_t *dispatchmgr,
539                         dns_dispatch_t *dispatchv4,
540                         dns_dispatch_t *dispatchv6)
541 {
542         isc_result_t result;
543         isc_event_t *event;
544         isc_mem_t *mctx = NULL;
545
546         REQUIRE(DNS_VIEW_VALID(view));
547         REQUIRE(!view->frozen);
548         REQUIRE(view->resolver == NULL);
549
550         result = isc_task_create(taskmgr, 0, &view->task);
551         if (result != ISC_R_SUCCESS)
552                 return (result);
553         isc_task_setname(view->task, "view", view);
554
555         result = dns_resolver_create(view, taskmgr, ntasks, socketmgr,
556                                      timermgr, options, dispatchmgr,
557                                      dispatchv4, dispatchv6,
558                                      &view->resolver);
559         if (result != ISC_R_SUCCESS) {
560                 isc_task_detach(&view->task);
561                 return (result);
562         }
563         event = &view->resevent;
564         dns_resolver_whenshutdown(view->resolver, view->task, &event);
565         view->attributes &= ~DNS_VIEWATTR_RESSHUTDOWN;
566
567         result = isc_mem_create(0, 0, &mctx);
568         if (result != ISC_R_SUCCESS) {
569                 dns_resolver_shutdown(view->resolver);
570                 return (result);
571         }
572
573         result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
574         isc_mem_detach(&mctx);
575         if (result != ISC_R_SUCCESS) {
576                 dns_resolver_shutdown(view->resolver);
577                 return (result);
578         }
579         event = &view->adbevent;
580         dns_adb_whenshutdown(view->adb, view->task, &event);
581         view->attributes &= ~DNS_VIEWATTR_ADBSHUTDOWN;
582
583         result = dns_requestmgr_create(view->mctx, timermgr, socketmgr,
584                                       dns_resolver_taskmgr(view->resolver),
585                                       dns_resolver_dispatchmgr(view->resolver),
586                                       dns_resolver_dispatchv4(view->resolver),
587                                       dns_resolver_dispatchv6(view->resolver),
588                                       &view->requestmgr);
589         if (result != ISC_R_SUCCESS) {
590                 dns_adb_shutdown(view->adb);
591                 dns_resolver_shutdown(view->resolver);
592                 return (result);
593         }
594         event = &view->reqevent;
595         dns_requestmgr_whenshutdown(view->requestmgr, view->task, &event);
596         view->attributes &= ~DNS_VIEWATTR_REQSHUTDOWN;
597
598         return (ISC_R_SUCCESS);
599 }
600
601 void
602 dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
603         REQUIRE(DNS_VIEW_VALID(view));
604         REQUIRE(!view->frozen);
605
606         if (view->cache != NULL) {
607                 if (view->acache != NULL)
608                         dns_acache_putdb(view->acache, view->cachedb);
609                 dns_db_detach(&view->cachedb);
610                 dns_cache_detach(&view->cache);
611         }
612         dns_cache_attach(cache, &view->cache);
613         dns_cache_attachdb(cache, &view->cachedb);
614         INSIST(DNS_DB_VALID(view->cachedb));
615
616         if (view->acache != NULL)
617                 dns_acache_setdb(view->acache, view->cachedb);
618 }
619
620 void
621 dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
622         REQUIRE(DNS_VIEW_VALID(view));
623         REQUIRE(!view->frozen);
624         REQUIRE(view->hints == NULL);
625         REQUIRE(dns_db_iszone(hints));
626
627         dns_db_attach(hints, &view->hints);
628 }
629
630 void
631 dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
632         REQUIRE(DNS_VIEW_VALID(view));
633         REQUIRE(ring != NULL);
634         if (view->statickeys != NULL)
635                 dns_tsigkeyring_destroy(&view->statickeys);
636         view->statickeys = ring;
637 }
638
639 void
640 dns_view_setdstport(dns_view_t *view, in_port_t dstport) {
641         REQUIRE(DNS_VIEW_VALID(view));
642         view->dstport = dstport;
643 }
644
645 isc_result_t
646 dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
647         isc_result_t result;
648
649         REQUIRE(DNS_VIEW_VALID(view));
650         REQUIRE(!view->frozen);
651
652         result = dns_zt_mount(view->zonetable, zone);
653
654         return (result);
655 }
656
657 void
658 dns_view_freeze(dns_view_t *view) {
659         REQUIRE(DNS_VIEW_VALID(view));
660         REQUIRE(!view->frozen);
661
662         if (view->resolver != NULL) {
663                 INSIST(view->cachedb != NULL);
664                 dns_resolver_freeze(view->resolver);
665         }
666         view->frozen = ISC_TRUE;
667 }
668
669 isc_result_t
670 dns_view_findzone(dns_view_t *view, dns_name_t *name, dns_zone_t **zonep) {
671         isc_result_t result;
672
673         REQUIRE(DNS_VIEW_VALID(view));
674
675         result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
676         if (result == DNS_R_PARTIALMATCH) {
677                 dns_zone_detach(zonep);
678                 result = ISC_R_NOTFOUND;
679         }
680
681         return (result);
682 }
683
684 isc_result_t
685 dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
686               isc_stdtime_t now, unsigned int options, isc_boolean_t use_hints,
687               dns_db_t **dbp, dns_dbnode_t **nodep, dns_name_t *foundname,
688               dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
689 {
690         isc_result_t result;
691         dns_db_t *db, *zdb;
692         dns_dbnode_t *node, *znode;
693         isc_boolean_t is_cache;
694         dns_rdataset_t zrdataset, zsigrdataset;
695         dns_zone_t *zone;
696
697         /*
698          * Find an rdataset whose owner name is 'name', and whose type is
699          * 'type'.
700          */
701
702         REQUIRE(DNS_VIEW_VALID(view));
703         REQUIRE(view->frozen);
704         REQUIRE(type != dns_rdatatype_rrsig);
705         REQUIRE(rdataset != NULL);  /* XXXBEW - remove this */
706         REQUIRE(nodep == NULL || *nodep == NULL);
707
708         /*
709          * Initialize.
710          */
711         dns_rdataset_init(&zrdataset);
712         dns_rdataset_init(&zsigrdataset);
713         zdb = NULL;
714         znode = NULL;
715
716         /*
717          * Find a database to answer the query.
718          */
719         zone = NULL;
720         db = NULL;
721         node = NULL;
722         result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
723         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
724                 result = dns_zone_getdb(zone, &db);
725                 if (result != ISC_R_SUCCESS && view->cachedb != NULL)
726                         dns_db_attach(view->cachedb, &db);
727                 else if (result != ISC_R_SUCCESS)
728                         goto cleanup;
729         } else if (result == ISC_R_NOTFOUND && view->cachedb != NULL)
730                 dns_db_attach(view->cachedb, &db);
731         else
732                 goto cleanup;
733
734         is_cache = dns_db_iscache(db);
735
736  db_find:
737         /*
738          * Now look for an answer in the database.
739          */
740         result = dns_db_find(db, name, NULL, type, options,
741                              now, &node, foundname, rdataset, sigrdataset);
742
743         if (result == DNS_R_DELEGATION ||
744             result == ISC_R_NOTFOUND) {
745                 if (dns_rdataset_isassociated(rdataset))
746                         dns_rdataset_disassociate(rdataset);
747                 if (sigrdataset != NULL &&
748                     dns_rdataset_isassociated(sigrdataset))
749                         dns_rdataset_disassociate(sigrdataset);
750                 if (node != NULL)
751                         dns_db_detachnode(db, &node);
752                 if (!is_cache) {
753                         dns_db_detach(&db);
754                         if (view->cachedb != NULL) {
755                                 /*
756                                  * Either the answer is in the cache, or we
757                                  * don't know it.
758                                  */
759                                 is_cache = ISC_TRUE;
760                                 dns_db_attach(view->cachedb, &db);
761                                 goto db_find;
762                         }
763                 } else {
764                         /*
765                          * We don't have the data in the cache.  If we've got
766                          * glue from the zone, use it.
767                          */
768                         if (dns_rdataset_isassociated(&zrdataset)) {
769                                 dns_rdataset_clone(&zrdataset, rdataset);
770                                 if (sigrdataset != NULL &&
771                                     dns_rdataset_isassociated(&zsigrdataset))
772                                         dns_rdataset_clone(&zsigrdataset,
773                                                            sigrdataset);
774                                 result = DNS_R_GLUE;
775                                 if (db != NULL)
776                                         dns_db_detach(&db);
777                                 dns_db_attach(zdb, &db);
778                                 dns_db_attachnode(db, znode, &node);
779                                 goto cleanup;
780                         }
781                 }
782                 /*
783                  * We don't know the answer.
784                  */
785                 result = ISC_R_NOTFOUND;
786         } else if (result == DNS_R_GLUE) {
787                 if (view->cachedb != NULL) {
788                         /*
789                          * We found an answer, but the cache may be better.
790                          * Remember what we've got and go look in the cache.
791                          */
792                         is_cache = ISC_TRUE;
793                         dns_rdataset_clone(rdataset, &zrdataset);
794                         dns_rdataset_disassociate(rdataset);
795                         if (sigrdataset != NULL &&
796                             dns_rdataset_isassociated(sigrdataset)) {
797                                 dns_rdataset_clone(sigrdataset, &zsigrdataset);
798                                 dns_rdataset_disassociate(sigrdataset);
799                         }
800                         dns_db_attach(db, &zdb);
801                         dns_db_attachnode(zdb, node, &znode);
802                         dns_db_detachnode(db, &node);
803                         dns_db_detach(&db);
804                         dns_db_attach(view->cachedb, &db);
805                         goto db_find;
806                 }
807                 /*
808                  * Otherwise, the glue is the best answer.
809                  */
810                 result = ISC_R_SUCCESS;
811         }
812
813         if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) {
814                 if (dns_rdataset_isassociated(rdataset))
815                         dns_rdataset_disassociate(rdataset);
816                 if (sigrdataset != NULL &&
817                     dns_rdataset_isassociated(sigrdataset))
818                         dns_rdataset_disassociate(sigrdataset);
819                 if (db != NULL) {
820                         if (node != NULL)
821                                 dns_db_detachnode(db, &node);
822                         dns_db_detach(&db);
823                 }
824                 result = dns_db_find(view->hints, name, NULL, type, options,
825                                      now, &node, foundname,
826                                      rdataset, sigrdataset);
827                 if (result == ISC_R_SUCCESS || result == DNS_R_GLUE) {
828                         /*
829                          * We just used a hint.  Let the resolver know it
830                          * should consider priming.
831                          */
832                         dns_resolver_prime(view->resolver);
833                         dns_db_attach(view->hints, &db);
834                         result = DNS_R_HINT;
835                 } else if (result == DNS_R_NXRRSET) {
836                         dns_db_attach(view->hints, &db);
837                         result = DNS_R_HINTNXRRSET;
838                 } else if (result == DNS_R_NXDOMAIN)
839                         result = ISC_R_NOTFOUND;
840
841                 /*
842                  * Cleanup if non-standard hints are used.
843                  */
844                 if (db == NULL && node != NULL)
845                         dns_db_detachnode(view->hints, &node);
846         }
847
848  cleanup:
849         if (dns_rdataset_isassociated(&zrdataset)) {
850                 dns_rdataset_disassociate(&zrdataset);
851                 if (dns_rdataset_isassociated(&zsigrdataset))
852                         dns_rdataset_disassociate(&zsigrdataset);
853         }
854
855         if (zdb != NULL) {
856                 if (znode != NULL)
857                         dns_db_detachnode(zdb, &znode);
858                 dns_db_detach(&zdb);
859         }
860
861         if (db != NULL) {
862                 if (node != NULL) {
863                         if (nodep != NULL)
864                                 *nodep = node;
865                         else
866                                 dns_db_detachnode(db, &node);
867                 }
868                 if (dbp != NULL)
869                         *dbp = db;
870                 else
871                         dns_db_detach(&db);
872         } else
873                 INSIST(node == NULL);
874
875         if (zone != NULL)
876                 dns_zone_detach(&zone);
877
878         return (result);
879 }
880
881 isc_result_t
882 dns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
883                     isc_stdtime_t now, unsigned int options,
884                     isc_boolean_t use_hints,
885                     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
886 {
887         isc_result_t result;
888         dns_fixedname_t foundname;
889
890         dns_fixedname_init(&foundname);
891         result = dns_view_find(view, name, type, now, options, use_hints,
892                                NULL, NULL, dns_fixedname_name(&foundname),
893                                rdataset, sigrdataset);
894         if (result == DNS_R_NXDOMAIN) {
895                 /*
896                  * The rdataset and sigrdataset of the relevant NSEC record
897                  * may be returned, but the caller cannot use them because
898                  * foundname is not returned by this simplified API.  We
899                  * disassociate them here to prevent any misuse by the caller.
900                  */
901                 if (dns_rdataset_isassociated(rdataset))
902                         dns_rdataset_disassociate(rdataset);
903                 if (sigrdataset != NULL &&
904                     dns_rdataset_isassociated(sigrdataset))
905                         dns_rdataset_disassociate(sigrdataset);
906         } else if (result != ISC_R_SUCCESS &&
907                    result != DNS_R_GLUE &&
908                    result != DNS_R_HINT &&
909                    result != DNS_R_NCACHENXDOMAIN &&
910                    result != DNS_R_NCACHENXRRSET &&
911                    result != DNS_R_NXRRSET &&
912                    result != DNS_R_HINTNXRRSET &&
913                    result != ISC_R_NOTFOUND) {
914                 if (dns_rdataset_isassociated(rdataset))
915                         dns_rdataset_disassociate(rdataset);
916                 if (sigrdataset != NULL &&
917                     dns_rdataset_isassociated(sigrdataset))
918                         dns_rdataset_disassociate(sigrdataset);
919                 result = ISC_R_NOTFOUND;
920         }
921
922         return (result);
923 }
924
925 isc_result_t
926 dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
927                      isc_stdtime_t now, unsigned int options,
928                      isc_boolean_t use_hints,
929                      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
930 {
931         return(dns_view_findzonecut2(view, name, fname, now, options,
932                                      use_hints, ISC_TRUE,
933                                      rdataset, sigrdataset));
934 }
935
936 isc_result_t
937 dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
938                       isc_stdtime_t now, unsigned int options,
939                       isc_boolean_t use_hints,  isc_boolean_t use_cache,
940                       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
941 {
942         isc_result_t result;
943         dns_db_t *db;
944         isc_boolean_t is_cache, use_zone, try_hints;
945         dns_zone_t *zone;
946         dns_name_t *zfname;
947         dns_rdataset_t zrdataset, zsigrdataset;
948         dns_fixedname_t zfixedname;
949
950         REQUIRE(DNS_VIEW_VALID(view));
951         REQUIRE(view->frozen);
952
953         db = NULL;
954         zone = NULL;
955         use_zone = ISC_FALSE;
956         try_hints = ISC_FALSE;
957         zfname = NULL;
958
959         /*
960          * Initialize.
961          */
962         dns_fixedname_init(&zfixedname);
963         dns_rdataset_init(&zrdataset);
964         dns_rdataset_init(&zsigrdataset);
965
966         /*
967          * Find the right database.
968          */
969         result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
970         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
971                 result = dns_zone_getdb(zone, &db);
972         if (result == ISC_R_NOTFOUND) {
973                 /*
974                  * We're not directly authoritative for this query name, nor
975                  * is it a subdomain of any zone for which we're
976                  * authoritative.
977                  */
978                 if (use_cache && view->cachedb != NULL) {
979                         /*
980                          * We have a cache; try it.
981                          */
982                         dns_db_attach(view->cachedb, &db);
983                 } else {
984                         /*
985                          * Maybe we have hints...
986                          */
987                         try_hints = ISC_TRUE;
988                         goto finish;
989                 }
990         } else if (result != ISC_R_SUCCESS) {
991                 /*
992                  * Something is broken.
993                  */
994                 goto cleanup;
995         }
996         is_cache = dns_db_iscache(db);
997
998  db_find:
999         /*
1000          * Look for the zonecut.
1001          */
1002         if (!is_cache) {
1003                 result = dns_db_find(db, name, NULL, dns_rdatatype_ns, options,
1004                                      now, NULL, fname, rdataset, sigrdataset);
1005                 if (result == DNS_R_DELEGATION)
1006                         result = ISC_R_SUCCESS;
1007                 else if (result != ISC_R_SUCCESS)
1008                         goto cleanup;
1009                 if (use_cache && view->cachedb != NULL && db != view->hints) {
1010                         /*
1011                          * We found an answer, but the cache may be better.
1012                          */
1013                         zfname = dns_fixedname_name(&zfixedname);
1014                         result = dns_name_copy(fname, zfname, NULL);
1015                         if (result != ISC_R_SUCCESS)
1016                                 goto cleanup;
1017                         dns_rdataset_clone(rdataset, &zrdataset);
1018                         dns_rdataset_disassociate(rdataset);
1019                         if (sigrdataset != NULL &&
1020                             dns_rdataset_isassociated(sigrdataset)) {
1021                                 dns_rdataset_clone(sigrdataset, &zsigrdataset);
1022                                 dns_rdataset_disassociate(sigrdataset);
1023                         }
1024                         dns_db_detach(&db);
1025                         dns_db_attach(view->cachedb, &db);
1026                         is_cache = ISC_TRUE;
1027                         goto db_find;
1028                 }
1029         } else {
1030                 result = dns_db_findzonecut(db, name, options, now, NULL,
1031                                             fname, rdataset, sigrdataset);
1032                 if (result == ISC_R_SUCCESS) {
1033                         if (zfname != NULL &&
1034                             !dns_name_issubdomain(fname, zfname)) {
1035                                 /*
1036                                  * We found a zonecut in the cache, but our
1037                                  * zone delegation is better.
1038                                  */
1039                                 use_zone = ISC_TRUE;
1040                         }
1041                 } else if (result == ISC_R_NOTFOUND) {
1042                         if (zfname != NULL) {
1043                                 /*
1044                                  * We didn't find anything in the cache, but we
1045                                  * have a zone delegation, so use it.
1046                                  */
1047                                 use_zone = ISC_TRUE;
1048                         } else {
1049                                 /*
1050                                  * Maybe we have hints...
1051                                  */
1052                                 try_hints = ISC_TRUE;
1053                         }
1054                 } else {
1055                         /*
1056                          * Something bad happened.
1057                          */
1058                         goto cleanup;
1059                 }
1060         }
1061
1062  finish:
1063         if (use_zone) {
1064                 if (dns_rdataset_isassociated(rdataset)) {
1065                         dns_rdataset_disassociate(rdataset);
1066                         if (sigrdataset != NULL &&
1067                             dns_rdataset_isassociated(sigrdataset))
1068                                 dns_rdataset_disassociate(sigrdataset);
1069                 }
1070                 result = dns_name_copy(zfname, fname, NULL);
1071                 if (result != ISC_R_SUCCESS)
1072                         goto cleanup;
1073                 dns_rdataset_clone(&zrdataset, rdataset);
1074                 if (sigrdataset != NULL &&
1075                     dns_rdataset_isassociated(&zrdataset))
1076                         dns_rdataset_clone(&zsigrdataset, sigrdataset);
1077         } else if (try_hints && use_hints && view->hints != NULL) {
1078                 /*
1079                  * We've found nothing so far, but we have hints.
1080                  */
1081                 result = dns_db_find(view->hints, dns_rootname, NULL,
1082                                      dns_rdatatype_ns, 0, now, NULL, fname,
1083                                      rdataset, NULL);
1084                 if (result != ISC_R_SUCCESS) {
1085                         /*
1086                          * We can't even find the hints for the root
1087                          * nameservers!
1088                          */
1089                         if (dns_rdataset_isassociated(rdataset))
1090                                 dns_rdataset_disassociate(rdataset);
1091                         result = ISC_R_NOTFOUND;
1092                 }
1093         }
1094
1095  cleanup:
1096         if (dns_rdataset_isassociated(&zrdataset)) {
1097                 dns_rdataset_disassociate(&zrdataset);
1098                 if (dns_rdataset_isassociated(&zsigrdataset))
1099                         dns_rdataset_disassociate(&zsigrdataset);
1100         }
1101         if (db != NULL)
1102                 dns_db_detach(&db);
1103         if (zone != NULL)
1104                 dns_zone_detach(&zone);
1105
1106         return (result);
1107 }
1108
1109 isc_result_t
1110 dns_viewlist_find(dns_viewlist_t *list, const char *name,
1111                   dns_rdataclass_t rdclass, dns_view_t **viewp)
1112 {
1113         dns_view_t *view;
1114
1115         REQUIRE(list != NULL);
1116
1117         for (view = ISC_LIST_HEAD(*list);
1118              view != NULL;
1119              view = ISC_LIST_NEXT(view, link)) {
1120                 if (strcmp(view->name, name) == 0 && view->rdclass == rdclass)
1121                         break;
1122         }
1123         if (view == NULL)
1124                 return (ISC_R_NOTFOUND);
1125
1126         dns_view_attach(view, viewp);
1127
1128         return (ISC_R_SUCCESS);
1129 }
1130
1131 isc_result_t
1132 dns_view_load(dns_view_t *view, isc_boolean_t stop) {
1133
1134         REQUIRE(DNS_VIEW_VALID(view));
1135
1136         return (dns_zt_load(view->zonetable, stop));
1137 }
1138
1139 isc_result_t
1140 dns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
1141
1142         REQUIRE(DNS_VIEW_VALID(view));
1143
1144         return (dns_zt_loadnew(view->zonetable, stop));
1145 }
1146
1147 isc_result_t
1148 dns_view_gettsig(dns_view_t *view, dns_name_t *keyname, dns_tsigkey_t **keyp)
1149 {
1150         isc_result_t result;
1151         REQUIRE(keyp != NULL && *keyp == NULL);
1152
1153         result = dns_tsigkey_find(keyp, keyname, NULL,
1154                                   view->statickeys);
1155         if (result == ISC_R_NOTFOUND)
1156                 result = dns_tsigkey_find(keyp, keyname, NULL,
1157                                           view->dynamickeys);
1158         return (result);
1159 }
1160
1161 isc_result_t
1162 dns_view_getpeertsig(dns_view_t *view, isc_netaddr_t *peeraddr,
1163                      dns_tsigkey_t **keyp)
1164 {
1165         isc_result_t result;
1166         dns_name_t *keyname = NULL;
1167         dns_peer_t *peer = NULL;
1168
1169         result = dns_peerlist_peerbyaddr(view->peers, peeraddr, &peer);
1170         if (result != ISC_R_SUCCESS)
1171                 return (result);
1172
1173         result = dns_peer_getkey(peer, &keyname);
1174         if (result != ISC_R_SUCCESS)
1175                 return (result);
1176
1177         return (dns_view_gettsig(view, keyname, keyp));
1178 }
1179
1180 isc_result_t
1181 dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
1182         REQUIRE(DNS_VIEW_VALID(view));
1183         REQUIRE(source != NULL);
1184
1185         return (dns_tsig_verify(source, msg, view->statickeys,
1186                                 view->dynamickeys));
1187 }
1188
1189 isc_result_t
1190 dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
1191         isc_result_t result;
1192
1193         REQUIRE(DNS_VIEW_VALID(view));
1194
1195         (void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
1196         result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
1197                                           &dns_master_style_cache, fp);
1198         if (result != ISC_R_SUCCESS)
1199                 return (result);
1200         dns_adb_dump(view->adb, fp);
1201         return (ISC_R_SUCCESS);
1202 }
1203
1204 isc_result_t
1205 dns_view_flushcache(dns_view_t *view) {
1206         isc_result_t result;
1207
1208         REQUIRE(DNS_VIEW_VALID(view));
1209
1210         if (view->cachedb == NULL)
1211                 return (ISC_R_SUCCESS);
1212         result = dns_cache_flush(view->cache);
1213         if (result != ISC_R_SUCCESS)
1214                 return (result);
1215         if (view->acache != NULL)
1216                 dns_acache_putdb(view->acache, view->cachedb);
1217         dns_db_detach(&view->cachedb);
1218         dns_cache_attachdb(view->cache, &view->cachedb);
1219         if (view->acache != NULL)
1220                 dns_acache_setdb(view->acache, view->cachedb);
1221
1222         dns_adb_flush(view->adb);
1223         return (ISC_R_SUCCESS);
1224 }
1225
1226 isc_result_t
1227 dns_view_flushname(dns_view_t *view, dns_name_t *name) {
1228
1229         REQUIRE(DNS_VIEW_VALID(view));
1230
1231         if (view->adb != NULL)
1232                 dns_adb_flushname(view->adb, name);
1233         if (view->cache == NULL)
1234                 return (ISC_R_SUCCESS);
1235         return (dns_cache_flushname(view->cache, name));
1236 }
1237
1238 isc_result_t
1239 dns_view_adddelegationonly(dns_view_t *view, dns_name_t *name) {
1240         isc_result_t result;
1241         dns_name_t *new;
1242         isc_uint32_t hash;
1243
1244         REQUIRE(DNS_VIEW_VALID(view));
1245
1246         if (view->delonly == NULL) {
1247                 view->delonly = isc_mem_get(view->mctx,
1248                                             sizeof(dns_namelist_t) *
1249                                             DNS_VIEW_DELONLYHASH);
1250                 if (view->delonly == NULL)
1251                         return (ISC_R_NOMEMORY);
1252                 for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1253                         ISC_LIST_INIT(view->delonly[hash]);
1254         }
1255         hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1256         new = ISC_LIST_HEAD(view->delonly[hash]);
1257         while (new != NULL && !dns_name_equal(new, name))
1258                 new = ISC_LIST_NEXT(new, link);
1259         if (new != NULL)
1260                 return (ISC_R_SUCCESS);
1261         new = isc_mem_get(view->mctx, sizeof(*new));
1262         if (new == NULL)
1263                 return (ISC_R_NOMEMORY);
1264         dns_name_init(new, NULL);
1265         result = dns_name_dup(name, view->mctx, new);
1266         if (result == ISC_R_SUCCESS)
1267                 ISC_LIST_APPEND(view->delonly[hash], new, link);
1268         else
1269                 isc_mem_put(view->mctx, new, sizeof(*new));
1270         return (result);
1271 }
1272
1273 isc_result_t
1274 dns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name) {
1275         isc_result_t result;
1276         dns_name_t *new;
1277         isc_uint32_t hash;
1278
1279         REQUIRE(DNS_VIEW_VALID(view));
1280
1281         if (view->rootexclude == NULL) {
1282                 view->rootexclude = isc_mem_get(view->mctx,
1283                                             sizeof(dns_namelist_t) *
1284                                             DNS_VIEW_DELONLYHASH);
1285                 if (view->rootexclude == NULL)
1286                         return (ISC_R_NOMEMORY);
1287                 for (hash = 0; hash < DNS_VIEW_DELONLYHASH; hash++)
1288                         ISC_LIST_INIT(view->rootexclude[hash]);
1289         }
1290         hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1291         new = ISC_LIST_HEAD(view->rootexclude[hash]);
1292         while (new != NULL && !dns_name_equal(new, name))
1293                 new = ISC_LIST_NEXT(new, link);
1294         if (new != NULL)
1295                 return (ISC_R_SUCCESS);
1296         new = isc_mem_get(view->mctx, sizeof(*new));
1297         if (new == NULL)
1298                 return (ISC_R_NOMEMORY);
1299         dns_name_init(new, NULL);
1300         result = dns_name_dup(name, view->mctx, new);
1301         if (result == ISC_R_SUCCESS)
1302                 ISC_LIST_APPEND(view->rootexclude[hash], new, link);
1303         else
1304                 isc_mem_put(view->mctx, new, sizeof(*new));
1305         return (result);
1306 }
1307
1308 isc_boolean_t
1309 dns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
1310         dns_name_t *new;
1311         isc_uint32_t hash;
1312
1313         REQUIRE(DNS_VIEW_VALID(view));
1314
1315         if (!view->rootdelonly && view->delonly == NULL)
1316                 return (ISC_FALSE);
1317
1318         hash = dns_name_hash(name, ISC_FALSE) % DNS_VIEW_DELONLYHASH;
1319         if (view->rootdelonly && dns_name_countlabels(name) <= 2) {
1320                 if (view->rootexclude == NULL)
1321                         return (ISC_TRUE);
1322                 new = ISC_LIST_HEAD(view->rootexclude[hash]);
1323                 while (new != NULL && !dns_name_equal(new, name))
1324                         new = ISC_LIST_NEXT(new, link);
1325                 if (new == NULL)
1326                         return (ISC_TRUE);
1327         }
1328
1329         if (view->delonly == NULL)
1330                 return (ISC_FALSE);
1331
1332         new = ISC_LIST_HEAD(view->delonly[hash]);
1333         while (new != NULL && !dns_name_equal(new, name))
1334                 new = ISC_LIST_NEXT(new, link);
1335         if (new == NULL)
1336                 return (ISC_FALSE);
1337         return (ISC_TRUE);
1338 }
1339
1340 void
1341 dns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
1342         REQUIRE(DNS_VIEW_VALID(view));
1343         view->rootdelonly = value;
1344 }
1345
1346 isc_boolean_t
1347 dns_view_getrootdelonly(dns_view_t *view) {
1348         REQUIRE(DNS_VIEW_VALID(view));
1349         return (view->rootdelonly);
1350 }
1351
1352 isc_result_t
1353 dns_view_freezezones(dns_view_t *view, isc_boolean_t value) {
1354         REQUIRE(DNS_VIEW_VALID(view));
1355         return (dns_zt_freezezones(view->zonetable, value));
1356 }