2 * services/localzone.c - local zones authority service.
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * This file contains functions to enable local zone authority service.
42 #include "services/localzone.h"
43 #include "ldns/str2wire.h"
44 #include "ldns/sbuffer.h"
45 #include "util/regional.h"
46 #include "util/config_file.h"
47 #include "util/data/dname.h"
48 #include "util/data/packed_rrset.h"
49 #include "util/data/msgencode.h"
50 #include "util/net_help.h"
51 #include "util/data/msgreply.h"
52 #include "util/data/msgparse.h"
55 local_zones_create(void)
57 struct local_zones
* zones
= (struct local_zones
*)calloc(1,
61 rbtree_init(&zones
->ztree
, &local_zone_cmp
);
62 lock_rw_init(&zones
->lock
);
63 lock_protect(&zones
->lock
, &zones
->ztree
, sizeof(zones
->ztree
));
64 /* also lock protects the rbnode's in struct local_zone */
68 /** helper traverse to delete zones */
70 lzdel(rbnode_t
* n
, void* ATTR_UNUSED(arg
))
72 struct local_zone
* z
= (struct local_zone
*)n
->key
;
77 local_zones_delete(struct local_zones
* zones
)
81 lock_rw_destroy(&zones
->lock
);
82 /* walk through zones and delete them all */
83 traverse_postorder(&zones
->ztree
, lzdel
, NULL
);
88 local_zone_delete(struct local_zone
* z
)
92 lock_rw_destroy(&z
->lock
);
93 regional_destroy(z
->region
);
99 local_zone_cmp(const void* z1
, const void* z2
)
101 /* first sort on class, so that hierarchy can be maintained within
103 struct local_zone
* a
= (struct local_zone
*)z1
;
104 struct local_zone
* b
= (struct local_zone
*)z2
;
106 if(a
->dclass
!= b
->dclass
) {
107 if(a
->dclass
< b
->dclass
)
111 return dname_lab_cmp(a
->name
, a
->namelabs
, b
->name
, b
->namelabs
, &m
);
115 local_data_cmp(const void* d1
, const void* d2
)
117 struct local_data
* a
= (struct local_data
*)d1
;
118 struct local_data
* b
= (struct local_data
*)d2
;
120 return dname_canon_lab_cmp(a
->name
, a
->namelabs
, b
->name
,
124 /* form wireformat from text format domain name */
126 parse_dname(const char* str
, uint8_t** res
, size_t* len
, int* labs
)
128 *res
= sldns_str2wire_dname(str
, len
);
131 log_err("cannot parse name %s", str
);
134 *labs
= dname_count_size_labels(*res
, len
);
138 /** create a new localzone */
139 static struct local_zone
*
140 local_zone_create(uint8_t* nm
, size_t len
, int labs
,
141 enum localzone_type t
, uint16_t dclass
)
143 struct local_zone
* z
= (struct local_zone
*)calloc(1, sizeof(*z
));
153 lock_rw_init(&z
->lock
);
154 z
->region
= regional_create();
159 rbtree_init(&z
->data
, &local_data_cmp
);
160 lock_protect(&z
->lock
, &z
->parent
, sizeof(*z
)-sizeof(rbnode_t
));
161 /* also the zones->lock protects node, parent, name*, class */
165 /** enter a new zone with allocated dname returns with WRlock */
166 static struct local_zone
*
167 lz_enter_zone_dname(struct local_zones
* zones
, uint8_t* nm
, size_t len
,
168 int labs
, enum localzone_type t
, uint16_t c
)
170 struct local_zone
* z
= local_zone_create(nm
, len
, labs
, t
, c
);
172 log_err("out of memory");
177 lock_rw_wrlock(&zones
->lock
);
178 lock_rw_wrlock(&z
->lock
);
179 if(!rbtree_insert(&zones
->ztree
, &z
->node
)) {
180 log_warn("duplicate local-zone");
181 lock_rw_unlock(&z
->lock
);
182 local_zone_delete(z
);
183 lock_rw_unlock(&zones
->lock
);
186 lock_rw_unlock(&zones
->lock
);
190 /** enter a new zone */
191 static struct local_zone
*
192 lz_enter_zone(struct local_zones
* zones
, const char* name
, const char* type
,
195 struct local_zone
* z
;
196 enum localzone_type t
;
200 if(!parse_dname(name
, &nm
, &len
, &labs
)) {
201 log_err("bad zone name %s %s", name
, type
);
204 if(!local_zone_str2type(type
, &t
)) {
205 log_err("bad lz_enter_zone type %s %s", name
, type
);
209 if(!(z
=lz_enter_zone_dname(zones
, nm
, len
, labs
, t
, dclass
))) {
210 log_err("could not enter zone %s %s", name
, type
);
216 /** return name and class and rdata of rr; parses string */
218 get_rr_content(const char* str
, uint8_t** nm
, uint16_t* type
,
219 uint16_t* dclass
, time_t* ttl
, uint8_t* rr
, size_t len
,
220 uint8_t** rdata
, size_t* rdata_len
)
222 size_t dname_len
= 0;
223 int e
= sldns_str2wire_rr_buf(str
, rr
, &len
, &dname_len
, 3600,
226 log_err("error parsing local-data at %d: '%s': %s",
227 LDNS_WIREPARSE_OFFSET(e
), str
,
228 sldns_get_errorstr_parse(e
));
231 *nm
= memdup(rr
, dname_len
);
233 log_err("out of memory");
236 *dclass
= sldns_wirerr_get_class(rr
, len
, dname_len
);
237 *type
= sldns_wirerr_get_type(rr
, len
, dname_len
);
238 *ttl
= (time_t)sldns_wirerr_get_ttl(rr
, len
, dname_len
);
239 *rdata
= sldns_wirerr_get_rdatawl(rr
, len
, dname_len
);
240 *rdata_len
= sldns_wirerr_get_rdatalen(rr
, len
, dname_len
)+2;
244 /** return name and class of rr; parses string */
246 get_rr_nameclass(const char* str
, uint8_t** nm
, uint16_t* dclass
)
248 uint8_t rr
[LDNS_RR_BUF_SIZE
];
249 size_t len
= sizeof(rr
), dname_len
= 0;
250 int s
= sldns_str2wire_rr_buf(str
, rr
, &len
, &dname_len
, 3600,
253 log_err("error parsing local-data at %d '%s': %s",
254 LDNS_WIREPARSE_OFFSET(s
), str
,
255 sldns_get_errorstr_parse(s
));
258 *nm
= memdup(rr
, dname_len
);
259 *dclass
= sldns_wirerr_get_class(rr
, len
, dname_len
);
261 log_err("out of memory");
268 * Find an rrset in local data structure.
269 * @param data: local data domain name structure.
270 * @param type: type to look for (host order).
271 * @return rrset pointer or NULL if not found.
273 static struct local_rrset
*
274 local_data_find_type(struct local_data
* data
, uint16_t type
)
276 struct local_rrset
* p
;
278 for(p
= data
->rrsets
; p
; p
= p
->next
) {
279 if(p
->rrset
->rk
.type
== type
)
285 /** check for RR duplicates */
287 rr_is_duplicate(struct packed_rrset_data
* pd
, uint8_t* rdata
, size_t rdata_len
)
290 for(i
=0; i
<pd
->count
; i
++) {
291 if(pd
->rr_len
[i
] == rdata_len
&&
292 memcmp(pd
->rr_data
[i
], rdata
, rdata_len
) == 0)
298 /** new local_rrset */
299 static struct local_rrset
*
300 new_local_rrset(struct regional
* region
, struct local_data
* node
,
301 uint16_t rrtype
, uint16_t rrclass
)
303 struct packed_rrset_data
* pd
;
304 struct local_rrset
* rrset
= (struct local_rrset
*)
305 regional_alloc_zero(region
, sizeof(*rrset
));
307 log_err("out of memory");
310 rrset
->next
= node
->rrsets
;
311 node
->rrsets
= rrset
;
312 rrset
->rrset
= (struct ub_packed_rrset_key
*)
313 regional_alloc_zero(region
, sizeof(*rrset
->rrset
));
315 log_err("out of memory");
318 rrset
->rrset
->entry
.key
= rrset
->rrset
;
319 pd
= (struct packed_rrset_data
*)regional_alloc_zero(region
,
322 log_err("out of memory");
325 pd
->trust
= rrset_trust_prim_noglue
;
326 pd
->security
= sec_status_insecure
;
327 rrset
->rrset
->entry
.data
= pd
;
328 rrset
->rrset
->rk
.dname
= node
->name
;
329 rrset
->rrset
->rk
.dname_len
= node
->namelen
;
330 rrset
->rrset
->rk
.type
= htons(rrtype
);
331 rrset
->rrset
->rk
.rrset_class
= htons(rrclass
);
335 /** insert RR into RRset data structure; Wastes a couple of bytes */
337 insert_rr(struct regional
* region
, struct packed_rrset_data
* pd
,
338 uint8_t* rdata
, size_t rdata_len
, time_t ttl
)
340 size_t* oldlen
= pd
->rr_len
;
341 time_t* oldttl
= pd
->rr_ttl
;
342 uint8_t** olddata
= pd
->rr_data
;
344 /* add RR to rrset */
346 pd
->rr_len
= regional_alloc(region
, sizeof(*pd
->rr_len
)*pd
->count
);
347 pd
->rr_ttl
= regional_alloc(region
, sizeof(*pd
->rr_ttl
)*pd
->count
);
348 pd
->rr_data
= regional_alloc(region
, sizeof(*pd
->rr_data
)*pd
->count
);
349 if(!pd
->rr_len
|| !pd
->rr_ttl
|| !pd
->rr_data
) {
350 log_err("out of memory");
354 memcpy(pd
->rr_len
+1, oldlen
,
355 sizeof(*pd
->rr_len
)*(pd
->count
-1));
356 memcpy(pd
->rr_ttl
+1, oldttl
,
357 sizeof(*pd
->rr_ttl
)*(pd
->count
-1));
358 memcpy(pd
->rr_data
+1, olddata
,
359 sizeof(*pd
->rr_data
)*(pd
->count
-1));
361 pd
->rr_len
[0] = rdata_len
;
363 pd
->rr_data
[0] = regional_alloc_init(region
, rdata
, rdata_len
);
364 if(!pd
->rr_data
[0]) {
365 log_err("out of memory");
371 /** find a data node by exact name */
372 static struct local_data
*
373 lz_find_node(struct local_zone
* z
, uint8_t* nm
, size_t nmlen
, int nmlabs
)
375 struct local_data key
;
379 key
.namelabs
= nmlabs
;
380 return (struct local_data
*)rbtree_search(&z
->data
, &key
.node
);
383 /** find a node, create it if not and all its empty nonterminal parents */
385 lz_find_create_node(struct local_zone
* z
, uint8_t* nm
, size_t nmlen
,
386 int nmlabs
, struct local_data
** res
)
388 struct local_data
* ld
= lz_find_node(z
, nm
, nmlen
, nmlabs
);
390 /* create a domain name to store rr. */
391 ld
= (struct local_data
*)regional_alloc_zero(z
->region
,
394 log_err("out of memory adding local data");
398 ld
->name
= regional_alloc_init(z
->region
, nm
, nmlen
);
400 log_err("out of memory");
404 ld
->namelabs
= nmlabs
;
405 if(!rbtree_insert(&z
->data
, &ld
->node
)) {
406 log_assert(0); /* duplicate name */
408 /* see if empty nonterminals need to be created */
409 if(nmlabs
> z
->namelabs
) {
410 dname_remove_label(&nm
, &nmlen
);
411 if(!lz_find_create_node(z
, nm
, nmlen
, nmlabs
-1, res
))
419 /** enter data RR into auth zone */
421 lz_enter_rr_into_zone(struct local_zone
* z
, const char* rrstr
)
426 struct local_data
* node
;
427 struct local_rrset
* rrset
;
428 struct packed_rrset_data
* pd
;
429 uint16_t rrtype
= 0, rrclass
= 0;
431 uint8_t rr
[LDNS_RR_BUF_SIZE
];
434 if(!get_rr_content(rrstr
, &nm
, &rrtype
, &rrclass
, &ttl
, rr
, sizeof(rr
),
435 &rdata
, &rdata_len
)) {
436 log_err("bad local-data: %s", rrstr
);
439 log_assert(z
->dclass
== rrclass
);
440 if(z
->type
== local_zone_redirect
&&
441 query_dname_compare(z
->name
, nm
) != 0) {
442 log_err("local-data in redirect zone must reside at top of zone"
443 ", not at %s", rrstr
);
447 nmlabs
= dname_count_size_labels(nm
, &nmlen
);
448 if(!lz_find_create_node(z
, nm
, nmlen
, nmlabs
, &node
)) {
455 rrset
= local_data_find_type(node
, rrtype
);
457 rrset
= new_local_rrset(z
->region
, node
, rrtype
, rrclass
);
460 if(query_dname_compare(node
->name
, z
->name
) == 0) {
461 if(rrtype
== LDNS_RR_TYPE_NSEC
)
462 rrset
->rrset
->rk
.flags
= PACKED_RRSET_NSEC_AT_APEX
;
463 if(rrtype
== LDNS_RR_TYPE_SOA
)
464 z
->soa
= rrset
->rrset
;
467 pd
= (struct packed_rrset_data
*)rrset
->rrset
->entry
.data
;
468 log_assert(rrset
&& pd
);
470 /* check for duplicate RR */
471 if(rr_is_duplicate(pd
, rdata
, rdata_len
)) {
472 verbose(VERB_ALGO
, "ignoring duplicate RR: %s", rrstr
);
475 return insert_rr(z
->region
, pd
, rdata
, rdata_len
, ttl
);
478 /** enter a data RR into auth data; a zone for it must exist */
480 lz_enter_rr_str(struct local_zones
* zones
, const char* rr
)
486 struct local_zone
* z
;
488 if(!get_rr_nameclass(rr
, &rr_name
, &rr_class
)) {
489 log_err("bad rr %s", rr
);
492 labs
= dname_count_size_labels(rr_name
, &len
);
493 lock_rw_rdlock(&zones
->lock
);
494 z
= local_zones_lookup(zones
, rr_name
, len
, labs
, rr_class
);
496 lock_rw_unlock(&zones
->lock
);
497 fatal_exit("internal error: no zone for rr %s", rr
);
499 lock_rw_wrlock(&z
->lock
);
500 lock_rw_unlock(&zones
->lock
);
502 r
= lz_enter_rr_into_zone(z
, rr
);
503 lock_rw_unlock(&z
->lock
);
507 /** parse local-zone: statements */
509 lz_enter_zones(struct local_zones
* zones
, struct config_file
* cfg
)
511 struct config_str2list
* p
;
512 struct local_zone
* z
;
513 for(p
= cfg
->local_zones
; p
; p
= p
->next
) {
514 if(!(z
=lz_enter_zone(zones
, p
->str
, p
->str2
,
517 lock_rw_unlock(&z
->lock
);
522 /** lookup a zone in rbtree; exact match only; SLOW due to parse */
524 lz_exists(struct local_zones
* zones
, const char* name
)
528 z
.dclass
= LDNS_RR_CLASS_IN
;
529 if(!parse_dname(name
, &z
.name
, &z
.namelen
, &z
.namelabs
)) {
530 log_err("bad name %s", name
);
533 lock_rw_rdlock(&zones
->lock
);
534 if(rbtree_search(&zones
->ztree
, &z
.node
)) {
535 lock_rw_unlock(&zones
->lock
);
539 lock_rw_unlock(&zones
->lock
);
544 /** lookup a zone in cfg->nodefault list */
546 lz_nodefault(struct config_file
* cfg
, const char* name
)
548 struct config_strlist
* p
;
549 size_t len
= strlen(name
);
550 if(len
== 0) return 0;
551 if(name
[len
-1] == '.') len
--;
553 for(p
= cfg
->local_zones_nodefault
; p
; p
= p
->next
) {
554 /* compare zone name, lowercase, compare without ending . */
555 if(strncasecmp(p
->str
, name
, len
) == 0 &&
556 (strlen(p
->str
) == len
|| (strlen(p
->str
)==len
+1 &&
557 p
->str
[len
] == '.')))
563 /** enter AS112 default zone */
565 add_as112_default(struct local_zones
* zones
, struct config_file
* cfg
,
568 struct local_zone
* z
;
569 char str
[1024]; /* known long enough */
570 if(lz_exists(zones
, name
) || lz_nodefault(cfg
, name
))
571 return 1; /* do not enter default content */
572 if(!(z
=lz_enter_zone(zones
, name
, "static", LDNS_RR_CLASS_IN
)))
574 snprintf(str
, sizeof(str
), "%s 10800 IN SOA localhost. "
575 "nobody.invalid. 1 3600 1200 604800 10800", name
);
576 if(!lz_enter_rr_into_zone(z
, str
)) {
577 lock_rw_unlock(&z
->lock
);
580 snprintf(str
, sizeof(str
), "%s 10800 IN NS localhost. ", name
);
581 if(!lz_enter_rr_into_zone(z
, str
)) {
582 lock_rw_unlock(&z
->lock
);
585 lock_rw_unlock(&z
->lock
);
589 /** enter default zones */
591 lz_enter_defaults(struct local_zones
* zones
, struct config_file
* cfg
)
593 struct local_zone
* z
;
595 /* this list of zones is from RFC 6303 */
597 /* block localhost level zones, first, later the LAN zones */
599 /* localhost. zone */
600 if(!lz_exists(zones
, "localhost.") &&
601 !lz_nodefault(cfg
, "localhost.")) {
602 if(!(z
=lz_enter_zone(zones
, "localhost.", "static",
603 LDNS_RR_CLASS_IN
)) ||
604 !lz_enter_rr_into_zone(z
,
605 "localhost. 10800 IN NS localhost.") ||
606 !lz_enter_rr_into_zone(z
,
607 "localhost. 10800 IN SOA localhost. nobody.invalid. "
608 "1 3600 1200 604800 10800") ||
609 !lz_enter_rr_into_zone(z
,
610 "localhost. 10800 IN A 127.0.0.1") ||
611 !lz_enter_rr_into_zone(z
,
612 "localhost. 10800 IN AAAA ::1")) {
613 log_err("out of memory adding default zone");
614 if(z
) { lock_rw_unlock(&z
->lock
); }
617 lock_rw_unlock(&z
->lock
);
619 /* reverse ip4 zone */
620 if(!lz_exists(zones
, "127.in-addr.arpa.") &&
621 !lz_nodefault(cfg
, "127.in-addr.arpa.")) {
622 if(!(z
=lz_enter_zone(zones
, "127.in-addr.arpa.", "static",
623 LDNS_RR_CLASS_IN
)) ||
624 !lz_enter_rr_into_zone(z
,
625 "127.in-addr.arpa. 10800 IN NS localhost.") ||
626 !lz_enter_rr_into_zone(z
,
627 "127.in-addr.arpa. 10800 IN SOA localhost. "
628 "nobody.invalid. 1 3600 1200 604800 10800") ||
629 !lz_enter_rr_into_zone(z
,
630 "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
631 log_err("out of memory adding default zone");
632 if(z
) { lock_rw_unlock(&z
->lock
); }
635 lock_rw_unlock(&z
->lock
);
637 /* reverse ip6 zone */
638 if(!lz_exists(zones
, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") &&
639 !lz_nodefault(cfg
, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.")) {
640 if(!(z
=lz_enter_zone(zones
, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", "static",
641 LDNS_RR_CLASS_IN
)) ||
642 !lz_enter_rr_into_zone(z
,
643 "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN NS localhost.") ||
644 !lz_enter_rr_into_zone(z
,
645 "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN SOA localhost. "
646 "nobody.invalid. 1 3600 1200 604800 10800") ||
647 !lz_enter_rr_into_zone(z
,
648 "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN PTR localhost.")) {
649 log_err("out of memory adding default zone");
650 if(z
) { lock_rw_unlock(&z
->lock
); }
653 lock_rw_unlock(&z
->lock
);
656 /* if unblock lan-zones, then do not add the zones below.
657 * we do add the zones above, about 127.0.0.1, because localhost is
659 if(cfg
->unblock_lan_zones
)
662 /* block LAN level zones */
663 if ( !add_as112_default(zones
, cfg
, "10.in-addr.arpa.") ||
664 !add_as112_default(zones
, cfg
, "16.172.in-addr.arpa.") ||
665 !add_as112_default(zones
, cfg
, "17.172.in-addr.arpa.") ||
666 !add_as112_default(zones
, cfg
, "18.172.in-addr.arpa.") ||
667 !add_as112_default(zones
, cfg
, "19.172.in-addr.arpa.") ||
668 !add_as112_default(zones
, cfg
, "20.172.in-addr.arpa.") ||
669 !add_as112_default(zones
, cfg
, "21.172.in-addr.arpa.") ||
670 !add_as112_default(zones
, cfg
, "22.172.in-addr.arpa.") ||
671 !add_as112_default(zones
, cfg
, "23.172.in-addr.arpa.") ||
672 !add_as112_default(zones
, cfg
, "24.172.in-addr.arpa.") ||
673 !add_as112_default(zones
, cfg
, "25.172.in-addr.arpa.") ||
674 !add_as112_default(zones
, cfg
, "26.172.in-addr.arpa.") ||
675 !add_as112_default(zones
, cfg
, "27.172.in-addr.arpa.") ||
676 !add_as112_default(zones
, cfg
, "28.172.in-addr.arpa.") ||
677 !add_as112_default(zones
, cfg
, "29.172.in-addr.arpa.") ||
678 !add_as112_default(zones
, cfg
, "30.172.in-addr.arpa.") ||
679 !add_as112_default(zones
, cfg
, "31.172.in-addr.arpa.") ||
680 !add_as112_default(zones
, cfg
, "168.192.in-addr.arpa.") ||
681 !add_as112_default(zones
, cfg
, "0.in-addr.arpa.") ||
682 !add_as112_default(zones
, cfg
, "64.100.in-addr.arpa.") ||
683 !add_as112_default(zones
, cfg
, "65.100.in-addr.arpa.") ||
684 !add_as112_default(zones
, cfg
, "66.100.in-addr.arpa.") ||
685 !add_as112_default(zones
, cfg
, "67.100.in-addr.arpa.") ||
686 !add_as112_default(zones
, cfg
, "68.100.in-addr.arpa.") ||
687 !add_as112_default(zones
, cfg
, "69.100.in-addr.arpa.") ||
688 !add_as112_default(zones
, cfg
, "70.100.in-addr.arpa.") ||
689 !add_as112_default(zones
, cfg
, "71.100.in-addr.arpa.") ||
690 !add_as112_default(zones
, cfg
, "72.100.in-addr.arpa.") ||
691 !add_as112_default(zones
, cfg
, "73.100.in-addr.arpa.") ||
692 !add_as112_default(zones
, cfg
, "74.100.in-addr.arpa.") ||
693 !add_as112_default(zones
, cfg
, "75.100.in-addr.arpa.") ||
694 !add_as112_default(zones
, cfg
, "76.100.in-addr.arpa.") ||
695 !add_as112_default(zones
, cfg
, "77.100.in-addr.arpa.") ||
696 !add_as112_default(zones
, cfg
, "78.100.in-addr.arpa.") ||
697 !add_as112_default(zones
, cfg
, "79.100.in-addr.arpa.") ||
698 !add_as112_default(zones
, cfg
, "80.100.in-addr.arpa.") ||
699 !add_as112_default(zones
, cfg
, "81.100.in-addr.arpa.") ||
700 !add_as112_default(zones
, cfg
, "82.100.in-addr.arpa.") ||
701 !add_as112_default(zones
, cfg
, "83.100.in-addr.arpa.") ||
702 !add_as112_default(zones
, cfg
, "84.100.in-addr.arpa.") ||
703 !add_as112_default(zones
, cfg
, "85.100.in-addr.arpa.") ||
704 !add_as112_default(zones
, cfg
, "86.100.in-addr.arpa.") ||
705 !add_as112_default(zones
, cfg
, "87.100.in-addr.arpa.") ||
706 !add_as112_default(zones
, cfg
, "88.100.in-addr.arpa.") ||
707 !add_as112_default(zones
, cfg
, "89.100.in-addr.arpa.") ||
708 !add_as112_default(zones
, cfg
, "90.100.in-addr.arpa.") ||
709 !add_as112_default(zones
, cfg
, "91.100.in-addr.arpa.") ||
710 !add_as112_default(zones
, cfg
, "92.100.in-addr.arpa.") ||
711 !add_as112_default(zones
, cfg
, "93.100.in-addr.arpa.") ||
712 !add_as112_default(zones
, cfg
, "94.100.in-addr.arpa.") ||
713 !add_as112_default(zones
, cfg
, "95.100.in-addr.arpa.") ||
714 !add_as112_default(zones
, cfg
, "96.100.in-addr.arpa.") ||
715 !add_as112_default(zones
, cfg
, "97.100.in-addr.arpa.") ||
716 !add_as112_default(zones
, cfg
, "98.100.in-addr.arpa.") ||
717 !add_as112_default(zones
, cfg
, "99.100.in-addr.arpa.") ||
718 !add_as112_default(zones
, cfg
, "100.100.in-addr.arpa.") ||
719 !add_as112_default(zones
, cfg
, "101.100.in-addr.arpa.") ||
720 !add_as112_default(zones
, cfg
, "102.100.in-addr.arpa.") ||
721 !add_as112_default(zones
, cfg
, "103.100.in-addr.arpa.") ||
722 !add_as112_default(zones
, cfg
, "104.100.in-addr.arpa.") ||
723 !add_as112_default(zones
, cfg
, "105.100.in-addr.arpa.") ||
724 !add_as112_default(zones
, cfg
, "106.100.in-addr.arpa.") ||
725 !add_as112_default(zones
, cfg
, "107.100.in-addr.arpa.") ||
726 !add_as112_default(zones
, cfg
, "108.100.in-addr.arpa.") ||
727 !add_as112_default(zones
, cfg
, "109.100.in-addr.arpa.") ||
728 !add_as112_default(zones
, cfg
, "110.100.in-addr.arpa.") ||
729 !add_as112_default(zones
, cfg
, "111.100.in-addr.arpa.") ||
730 !add_as112_default(zones
, cfg
, "112.100.in-addr.arpa.") ||
731 !add_as112_default(zones
, cfg
, "113.100.in-addr.arpa.") ||
732 !add_as112_default(zones
, cfg
, "114.100.in-addr.arpa.") ||
733 !add_as112_default(zones
, cfg
, "115.100.in-addr.arpa.") ||
734 !add_as112_default(zones
, cfg
, "116.100.in-addr.arpa.") ||
735 !add_as112_default(zones
, cfg
, "117.100.in-addr.arpa.") ||
736 !add_as112_default(zones
, cfg
, "118.100.in-addr.arpa.") ||
737 !add_as112_default(zones
, cfg
, "119.100.in-addr.arpa.") ||
738 !add_as112_default(zones
, cfg
, "120.100.in-addr.arpa.") ||
739 !add_as112_default(zones
, cfg
, "121.100.in-addr.arpa.") ||
740 !add_as112_default(zones
, cfg
, "122.100.in-addr.arpa.") ||
741 !add_as112_default(zones
, cfg
, "123.100.in-addr.arpa.") ||
742 !add_as112_default(zones
, cfg
, "124.100.in-addr.arpa.") ||
743 !add_as112_default(zones
, cfg
, "125.100.in-addr.arpa.") ||
744 !add_as112_default(zones
, cfg
, "126.100.in-addr.arpa.") ||
745 !add_as112_default(zones
, cfg
, "127.100.in-addr.arpa.") ||
746 !add_as112_default(zones
, cfg
, "254.169.in-addr.arpa.") ||
747 !add_as112_default(zones
, cfg
, "2.0.192.in-addr.arpa.") ||
748 !add_as112_default(zones
, cfg
, "100.51.198.in-addr.arpa.") ||
749 !add_as112_default(zones
, cfg
, "113.0.203.in-addr.arpa.") ||
750 !add_as112_default(zones
, cfg
, "255.255.255.255.in-addr.arpa.") ||
751 !add_as112_default(zones
, cfg
, "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") ||
752 !add_as112_default(zones
, cfg
, "d.f.ip6.arpa.") ||
753 !add_as112_default(zones
, cfg
, "8.e.f.ip6.arpa.") ||
754 !add_as112_default(zones
, cfg
, "9.e.f.ip6.arpa.") ||
755 !add_as112_default(zones
, cfg
, "a.e.f.ip6.arpa.") ||
756 !add_as112_default(zones
, cfg
, "b.e.f.ip6.arpa.") ||
757 !add_as112_default(zones
, cfg
, "8.b.d.0.1.0.0.2.ip6.arpa.")) {
758 log_err("out of memory adding default zone");
764 /** setup parent pointers, so that a lookup can be done for closest match */
766 init_parents(struct local_zones
* zones
)
768 struct local_zone
* node
, *prev
= NULL
, *p
;
770 lock_rw_wrlock(&zones
->lock
);
771 RBTREE_FOR(node
, struct local_zone
*, &zones
->ztree
) {
772 lock_rw_wrlock(&node
->lock
);
774 if(!prev
|| prev
->dclass
!= node
->dclass
) {
776 lock_rw_unlock(&node
->lock
);
779 (void)dname_lab_cmp(prev
->name
, prev
->namelabs
, node
->name
,
780 node
->namelabs
, &m
); /* we know prev is smaller */
781 /* sort order like: . com. bla.com. zwb.com. net. */
782 /* find the previous, or parent-parent-parent */
783 for(p
= prev
; p
; p
= p
->parent
)
784 /* looking for name with few labels, a parent */
785 if(p
->namelabs
<= m
) {
786 /* ==: since prev matched m, this is closest*/
787 /* <: prev matches more, but is not a parent,
788 * this one is a (grand)parent */
793 lock_rw_unlock(&node
->lock
);
795 lock_rw_unlock(&zones
->lock
);
798 /** enter implicit transparent zone for local-data: without local-zone: */
800 lz_setup_implicit(struct local_zones
* zones
, struct config_file
* cfg
)
802 /* walk over all items that have no parent zone and find
803 * the name that covers them all (could be the root) and
804 * add that as a transparent zone */
805 struct config_strlist
* p
;
807 int have_other_classes
= 0;
812 int match
= 0; /* number of labels match count */
814 init_parents(zones
); /* to enable local_zones_lookup() */
815 for(p
= cfg
->local_data
; p
; p
= p
->next
) {
820 if(!get_rr_nameclass(p
->str
, &rr_name
, &rr_class
)) {
821 log_err("Bad local-data RR %s", p
->str
);
824 labs
= dname_count_size_labels(rr_name
, &len
);
825 lock_rw_rdlock(&zones
->lock
);
826 if(!local_zones_lookup(zones
, rr_name
, len
, labs
, rr_class
)) {
836 if(rr_class
!= dclass
) {
837 /* process other classes later */
839 have_other_classes
= 1;
840 lock_rw_unlock(&zones
->lock
);
843 /* find smallest shared topdomain */
844 (void)dname_lab_cmp(nm
, nmlabs
,
850 } else free(rr_name
);
851 lock_rw_unlock(&zones
->lock
);
855 struct local_zone
* z
;
856 /* allocate zone of smallest shared topdomain to contain em */
858 dname_remove_labels(&n2
, &nmlen
, nmlabs
- match
);
859 n2
= memdup(n2
, nmlen
);
862 log_err("out of memory");
865 log_nametypeclass(VERB_ALGO
, "implicit transparent local-zone",
867 if(!(z
=lz_enter_zone_dname(zones
, n2
, nmlen
, match
,
868 local_zone_transparent
, dclass
))) {
871 lock_rw_unlock(&z
->lock
);
873 if(have_other_classes
) {
874 /* restart to setup other class */
875 return lz_setup_implicit(zones
, cfg
);
880 /** enter auth data */
882 lz_enter_data(struct local_zones
* zones
, struct config_file
* cfg
)
884 struct config_strlist
* p
;
885 for(p
= cfg
->local_data
; p
; p
= p
->next
) {
886 if(!lz_enter_rr_str(zones
, p
->str
))
892 /** free memory from config */
894 lz_freeup_cfg(struct config_file
* cfg
)
896 config_deldblstrlist(cfg
->local_zones
);
897 cfg
->local_zones
= NULL
;
898 config_delstrlist(cfg
->local_zones_nodefault
);
899 cfg
->local_zones_nodefault
= NULL
;
900 config_delstrlist(cfg
->local_data
);
901 cfg
->local_data
= NULL
;
905 local_zones_apply_cfg(struct local_zones
* zones
, struct config_file
* cfg
)
907 /* create zones from zone statements. */
908 if(!lz_enter_zones(zones
, cfg
)) {
911 /* apply default zones+content (unless disabled, or overridden) */
912 if(!lz_enter_defaults(zones
, cfg
)) {
915 /* create implicit transparent zone from data. */
916 if(!lz_setup_implicit(zones
, cfg
)) {
920 /* setup parent ptrs for lookup during data entry */
922 /* insert local data */
923 if(!lz_enter_data(zones
, cfg
)) {
926 /* freeup memory from cfg struct. */
932 local_zones_lookup(struct local_zones
* zones
,
933 uint8_t* name
, size_t len
, int labs
, uint16_t dclass
)
935 rbnode_t
* res
= NULL
;
936 struct local_zone
*result
;
937 struct local_zone key
;
943 if(rbtree_find_less_equal(&zones
->ztree
, &key
, &res
)) {
945 return (struct local_zone
*)res
;
947 /* smaller element (or no element) */
949 result
= (struct local_zone
*)res
;
950 if(!result
|| result
->dclass
!= dclass
)
952 /* count number of labels matched */
953 (void)dname_lab_cmp(result
->name
, result
->namelabs
, key
.name
,
955 while(result
) { /* go up until qname is subdomain of zone */
956 if(result
->namelabs
<= m
)
958 result
= result
->parent
;
965 local_zones_find(struct local_zones
* zones
,
966 uint8_t* name
, size_t len
, int labs
, uint16_t dclass
)
968 struct local_zone key
;
975 return (struct local_zone
*)rbtree_search(&zones
->ztree
, &key
);
978 /** print all RRsets in local zone */
980 local_zone_out(struct local_zone
* z
)
982 struct local_data
* d
;
983 struct local_rrset
* p
;
984 RBTREE_FOR(d
, struct local_data
*, &z
->data
) {
985 for(p
= d
->rrsets
; p
; p
= p
->next
) {
986 log_nametypeclass(0, "rrset", d
->name
,
987 ntohs(p
->rrset
->rk
.type
),
988 ntohs(p
->rrset
->rk
.rrset_class
));
993 void local_zones_print(struct local_zones
* zones
)
995 struct local_zone
* z
;
996 lock_rw_rdlock(&zones
->lock
);
997 log_info("number of auth zones %u", (unsigned)zones
->ztree
.count
);
998 RBTREE_FOR(z
, struct local_zone
*, &zones
->ztree
) {
999 lock_rw_rdlock(&z
->lock
);
1001 case local_zone_deny
:
1002 log_nametypeclass(0, "deny zone",
1003 z
->name
, 0, z
->dclass
);
1005 case local_zone_refuse
:
1006 log_nametypeclass(0, "refuse zone",
1007 z
->name
, 0, z
->dclass
);
1009 case local_zone_redirect
:
1010 log_nametypeclass(0, "redirect zone",
1011 z
->name
, 0, z
->dclass
);
1013 case local_zone_transparent
:
1014 log_nametypeclass(0, "transparent zone",
1015 z
->name
, 0, z
->dclass
);
1017 case local_zone_typetransparent
:
1018 log_nametypeclass(0, "typetransparent zone",
1019 z
->name
, 0, z
->dclass
);
1021 case local_zone_static
:
1022 log_nametypeclass(0, "static zone",
1023 z
->name
, 0, z
->dclass
);
1026 log_nametypeclass(0, "badtyped zone",
1027 z
->name
, 0, z
->dclass
);
1031 lock_rw_unlock(&z
->lock
);
1033 lock_rw_unlock(&zones
->lock
);
1036 /** encode answer consisting of 1 rrset */
1038 local_encode(struct query_info
* qinfo
, struct edns_data
* edns
,
1039 sldns_buffer
* buf
, struct regional
* temp
,
1040 struct ub_packed_rrset_key
* rrset
, int ansec
, int rcode
)
1042 struct reply_info rep
;
1044 /* make answer with time=0 for fixed TTL values */
1045 memset(&rep
, 0, sizeof(rep
));
1046 rep
.flags
= (uint16_t)((BIT_QR
| BIT_AA
| BIT_RA
) | rcode
);
1049 rep
.an_numrrsets
= 1;
1050 else rep
.ns_numrrsets
= 1;
1051 rep
.rrset_count
= 1;
1052 rep
.rrsets
= &rrset
;
1053 udpsize
= edns
->udp_size
;
1054 edns
->edns_version
= EDNS_ADVERTISED_VERSION
;
1055 edns
->udp_size
= EDNS_ADVERTISED_SIZE
;
1056 edns
->ext_rcode
= 0;
1057 edns
->bits
&= EDNS_DO
;
1058 if(!reply_info_answer_encode(qinfo
, &rep
,
1059 *(uint16_t*)sldns_buffer_begin(buf
),
1060 sldns_buffer_read_u16_at(buf
, 2),
1061 buf
, 0, 0, temp
, udpsize
, edns
,
1062 (int)(edns
->bits
&EDNS_DO
), 0))
1063 error_encode(buf
, (LDNS_RCODE_SERVFAIL
|BIT_AA
), qinfo
,
1064 *(uint16_t*)sldns_buffer_begin(buf
),
1065 sldns_buffer_read_u16_at(buf
, 2), edns
);
1069 /** answer local data match */
1071 local_data_answer(struct local_zone
* z
, struct query_info
* qinfo
,
1072 struct edns_data
* edns
, sldns_buffer
* buf
, struct regional
* temp
,
1073 int labs
, struct local_data
** ldp
)
1075 struct local_data key
;
1076 struct local_data
* ld
;
1077 struct local_rrset
* lr
;
1078 key
.node
.key
= &key
;
1079 key
.name
= qinfo
->qname
;
1080 key
.namelen
= qinfo
->qname_len
;
1081 key
.namelabs
= labs
;
1082 if(z
->type
== local_zone_redirect
) {
1084 key
.namelen
= z
->namelen
;
1085 key
.namelabs
= z
->namelabs
;
1087 ld
= (struct local_data
*)rbtree_search(&z
->data
, &key
.node
);
1092 lr
= local_data_find_type(ld
, qinfo
->qtype
);
1095 if(z
->type
== local_zone_redirect
) {
1096 /* convert rrset name to query name; like a wildcard */
1097 struct ub_packed_rrset_key r
= *lr
->rrset
;
1098 r
.rk
.dname
= qinfo
->qname
;
1099 r
.rk
.dname_len
= qinfo
->qname_len
;
1100 return local_encode(qinfo
, edns
, buf
, temp
, &r
, 1,
1101 LDNS_RCODE_NOERROR
);
1103 return local_encode(qinfo
, edns
, buf
, temp
, lr
->rrset
, 1,
1104 LDNS_RCODE_NOERROR
);
1108 * answer in case where no exact match is found
1109 * @param z: zone for query
1110 * @param qinfo: query
1111 * @param edns: edns from query
1112 * @param buf: buffer for answer.
1113 * @param temp: temp region for encoding
1114 * @param ld: local data, if NULL, no such name exists in localdata.
1115 * @return 1 if a reply is to be sent, 0 if not.
1118 lz_zone_answer(struct local_zone
* z
, struct query_info
* qinfo
,
1119 struct edns_data
* edns
, sldns_buffer
* buf
, struct regional
* temp
,
1120 struct local_data
* ld
)
1122 if(z
->type
== local_zone_deny
) {
1123 /** no reply at all, signal caller by clearing buffer. */
1124 sldns_buffer_clear(buf
);
1125 sldns_buffer_flip(buf
);
1127 } else if(z
->type
== local_zone_refuse
) {
1128 error_encode(buf
, (LDNS_RCODE_REFUSED
|BIT_AA
), qinfo
,
1129 *(uint16_t*)sldns_buffer_begin(buf
),
1130 sldns_buffer_read_u16_at(buf
, 2), edns
);
1132 } else if(z
->type
== local_zone_static
||
1133 z
->type
== local_zone_redirect
) {
1134 /* for static, reply nodata or nxdomain
1135 * for redirect, reply nodata */
1136 /* no additional section processing,
1137 * cname, dname or wildcard processing,
1138 * or using closest match for NSEC.
1139 * or using closest match for returning delegation downwards
1141 int rcode
= ld
?LDNS_RCODE_NOERROR
:LDNS_RCODE_NXDOMAIN
;
1143 return local_encode(qinfo
, edns
, buf
, temp
,
1145 error_encode(buf
, (rcode
|BIT_AA
), qinfo
,
1146 *(uint16_t*)sldns_buffer_begin(buf
),
1147 sldns_buffer_read_u16_at(buf
, 2), edns
);
1149 } else if(z
->type
== local_zone_typetransparent
) {
1150 /* no NODATA or NXDOMAINS for this zone type */
1153 /* else z->type == local_zone_transparent */
1155 /* if the zone is transparent and the name exists, but the type
1156 * does not, then we should make this noerror/nodata */
1157 if(ld
&& ld
->rrsets
) {
1158 int rcode
= LDNS_RCODE_NOERROR
;
1160 return local_encode(qinfo
, edns
, buf
, temp
,
1162 error_encode(buf
, (rcode
|BIT_AA
), qinfo
,
1163 *(uint16_t*)sldns_buffer_begin(buf
),
1164 sldns_buffer_read_u16_at(buf
, 2), edns
);
1168 /* stop here, and resolve further on */
1173 local_zones_answer(struct local_zones
* zones
, struct query_info
* qinfo
,
1174 struct edns_data
* edns
, sldns_buffer
* buf
, struct regional
* temp
)
1176 /* see if query is covered by a zone,
1177 * if so: - try to match (exact) local data
1178 * - look at zone type for negative response. */
1179 int labs
= dname_count_labels(qinfo
->qname
);
1180 struct local_data
* ld
;
1181 struct local_zone
* z
;
1183 lock_rw_rdlock(&zones
->lock
);
1184 z
= local_zones_lookup(zones
, qinfo
->qname
,
1185 qinfo
->qname_len
, labs
, qinfo
->qclass
);
1187 lock_rw_unlock(&zones
->lock
);
1190 lock_rw_rdlock(&z
->lock
);
1191 lock_rw_unlock(&zones
->lock
);
1193 if(local_data_answer(z
, qinfo
, edns
, buf
, temp
, labs
, &ld
)) {
1194 lock_rw_unlock(&z
->lock
);
1197 r
= lz_zone_answer(z
, qinfo
, edns
, buf
, temp
, ld
);
1198 lock_rw_unlock(&z
->lock
);
1202 const char* local_zone_type2str(enum localzone_type t
)
1205 case local_zone_deny
: return "deny";
1206 case local_zone_refuse
: return "refuse";
1207 case local_zone_redirect
: return "redirect";
1208 case local_zone_transparent
: return "transparent";
1209 case local_zone_typetransparent
: return "typetransparent";
1210 case local_zone_static
: return "static";
1211 case local_zone_nodefault
: return "nodefault";
1216 int local_zone_str2type(const char* type
, enum localzone_type
* t
)
1218 if(strcmp(type
, "deny") == 0)
1219 *t
= local_zone_deny
;
1220 else if(strcmp(type
, "refuse") == 0)
1221 *t
= local_zone_refuse
;
1222 else if(strcmp(type
, "static") == 0)
1223 *t
= local_zone_static
;
1224 else if(strcmp(type
, "transparent") == 0)
1225 *t
= local_zone_transparent
;
1226 else if(strcmp(type
, "typetransparent") == 0)
1227 *t
= local_zone_typetransparent
;
1228 else if(strcmp(type
, "redirect") == 0)
1229 *t
= local_zone_redirect
;
1234 /** iterate over the kiddies of the given name and set their parent ptr */
1236 set_kiddo_parents(struct local_zone
* z
, struct local_zone
* match
,
1237 struct local_zone
* newp
)
1239 /* both zones and z are locked already */
1240 /* in the sorted rbtree, the kiddies of z are located after z */
1241 /* z must be present in the tree */
1242 struct local_zone
* p
= z
;
1243 p
= (struct local_zone
*)rbtree_next(&p
->node
);
1244 while(p
!=(struct local_zone
*)RBTREE_NULL
&&
1245 p
->dclass
== z
->dclass
&& dname_strict_subdomain(p
->name
,
1246 p
->namelabs
, z
->name
, z
->namelabs
)) {
1247 /* update parent ptr */
1248 /* only when matches with existing parent pointer, so that
1249 * deeper child structures are not touched, i.e.
1250 * update of x, and a.x, b.x, f.b.x, g.b.x, c.x, y
1251 * gets to update a.x, b.x and c.x */
1252 lock_rw_wrlock(&p
->lock
);
1253 if(p
->parent
== match
)
1255 lock_rw_unlock(&p
->lock
);
1256 p
= (struct local_zone
*)rbtree_next(&p
->node
);
1260 struct local_zone
* local_zones_add_zone(struct local_zones
* zones
,
1261 uint8_t* name
, size_t len
, int labs
, uint16_t dclass
,
1262 enum localzone_type tp
)
1265 struct local_zone
* z
= local_zone_create(name
, len
, labs
, tp
, dclass
);
1267 lock_rw_wrlock(&z
->lock
);
1269 /* find the closest parent */
1270 z
->parent
= local_zones_find(zones
, name
, len
, labs
, dclass
);
1272 /* insert into the tree */
1273 if(!rbtree_insert(&zones
->ztree
, &z
->node
)) {
1274 /* duplicate entry! */
1275 lock_rw_unlock(&z
->lock
);
1276 local_zone_delete(z
);
1277 log_err("internal: duplicate entry in local_zones_add_zone");
1281 /* set parent pointers right */
1282 set_kiddo_parents(z
, z
->parent
, z
);
1284 lock_rw_unlock(&z
->lock
);
1288 void local_zones_del_zone(struct local_zones
* zones
, struct local_zone
* z
)
1290 /* fix up parents in tree */
1291 lock_rw_wrlock(&z
->lock
);
1292 set_kiddo_parents(z
, z
, z
->parent
);
1294 /* remove from tree */
1295 (void)rbtree_delete(&zones
->ztree
, z
);
1297 /* delete the zone */
1298 lock_rw_unlock(&z
->lock
);
1299 local_zone_delete(z
);
1303 local_zones_add_RR(struct local_zones
* zones
, const char* rr
)
1309 struct local_zone
* z
;
1311 if(!get_rr_nameclass(rr
, &rr_name
, &rr_class
)) {
1314 labs
= dname_count_size_labels(rr_name
, &len
);
1315 /* could first try readlock then get writelock if zone does not exist,
1316 * but we do not add enough RRs (from multiple threads) to optimize */
1317 lock_rw_wrlock(&zones
->lock
);
1318 z
= local_zones_lookup(zones
, rr_name
, len
, labs
, rr_class
);
1320 z
= local_zones_add_zone(zones
, rr_name
, len
, labs
, rr_class
,
1321 local_zone_transparent
);
1323 lock_rw_unlock(&zones
->lock
);
1329 lock_rw_wrlock(&z
->lock
);
1330 lock_rw_unlock(&zones
->lock
);
1331 r
= lz_enter_rr_into_zone(z
, rr
);
1332 lock_rw_unlock(&z
->lock
);
1336 /** returns true if the node is terminal so no deeper domain names exist */
1338 is_terminal(struct local_data
* d
)
1340 /* for empty nonterminals, the deeper domain names are sorted
1341 * right after them, so simply check the next name in the tree
1343 struct local_data
* n
= (struct local_data
*)rbtree_next(&d
->node
);
1344 if(n
== (struct local_data
*)RBTREE_NULL
)
1345 return 1; /* last in tree, no deeper node */
1346 if(dname_strict_subdomain(n
->name
, n
->namelabs
, d
->name
, d
->namelabs
))
1347 return 0; /* there is a deeper node */
1351 /** delete empty terminals from tree when final data is deleted */
1353 del_empty_term(struct local_zone
* z
, struct local_data
* d
,
1354 uint8_t* name
, size_t len
, int labs
)
1356 while(d
&& d
->rrsets
== NULL
&& is_terminal(d
)) {
1357 /* is this empty nonterminal? delete */
1358 /* note, no memory recycling in zone region */
1359 (void)rbtree_delete(&z
->data
, d
);
1361 /* go up and to the next label */
1362 if(dname_is_root(name
))
1364 dname_remove_label(&name
, &len
);
1366 d
= lz_find_node(z
, name
, len
, labs
);
1370 void local_zones_del_data(struct local_zones
* zones
,
1371 uint8_t* name
, size_t len
, int labs
, uint16_t dclass
)
1374 struct local_zone
* z
;
1375 struct local_data
* d
;
1376 lock_rw_rdlock(&zones
->lock
);
1377 z
= local_zones_lookup(zones
, name
, len
, labs
, dclass
);
1379 /* no such zone, we're done */
1380 lock_rw_unlock(&zones
->lock
);
1383 lock_rw_wrlock(&z
->lock
);
1384 lock_rw_unlock(&zones
->lock
);
1386 /* find the domain */
1387 d
= lz_find_node(z
, name
, len
, labs
);
1389 /* no memory recycling for zone deletions ... */
1391 /* did we delete the soa record ? */
1392 if(query_dname_compare(d
->name
, z
->name
) == 0)
1395 /* cleanup the empty nonterminals for this name */
1396 del_empty_term(z
, d
, name
, len
, labs
);
1399 lock_rw_unlock(&z
->lock
);