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 LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
39 * This file contains functions to enable local zone authority service.
42 #include <ldns/dname.h>
43 #include <ldns/host2wire.h>
44 #include "services/localzone.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_quick_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_quick_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)
132 rdf = ldns_dname_new_frm_str(str);
134 log_err("cannot parse name %s", str);
137 *res = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf));
138 ldns_rdf_deep_free(rdf);
140 log_err("out of memory");
143 *labs = dname_count_size_labels(*res, len);
147 /** create a new localzone */
148 static struct local_zone*
149 local_zone_create(uint8_t* nm, size_t len, int labs,
150 enum localzone_type t, uint16_t dclass)
152 struct local_zone* z = (struct local_zone*)calloc(1, sizeof(*z));
162 lock_rw_init(&z->lock);
163 z->region = regional_create();
168 rbtree_init(&z->data, &local_data_cmp);
169 lock_protect(&z->lock, &z->parent, sizeof(*z)-sizeof(rbnode_t));
170 /* also the zones->lock protects node, parent, name*, class */
174 /** enter a new zone with allocated dname returns with WRlock */
175 static struct local_zone*
176 lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
177 int labs, enum localzone_type t, uint16_t c)
179 struct local_zone* z = local_zone_create(nm, len, labs, t, c);
181 log_err("out of memory");
186 lock_quick_lock(&zones->lock);
187 lock_rw_wrlock(&z->lock);
188 if(!rbtree_insert(&zones->ztree, &z->node)) {
189 log_warn("duplicate local-zone");
190 lock_rw_unlock(&z->lock);
191 local_zone_delete(z);
192 lock_quick_unlock(&zones->lock);
195 lock_quick_unlock(&zones->lock);
199 /** enter a new zone */
200 static struct local_zone*
201 lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
204 struct local_zone* z;
205 enum localzone_type t;
209 if(!parse_dname(name, &nm, &len, &labs)) {
210 log_err("bad zone name %s %s", name, type);
213 if(!local_zone_str2type(type, &t)) {
214 log_err("bad lz_enter_zone type %s %s", name, type);
218 if(!(z=lz_enter_zone_dname(zones, nm, len, labs, t, dclass))) {
219 log_err("could not enter zone %s %s", name, type);
225 /** return name and class and rdata of rr; parses string */
227 get_rr_content(const char* str, uint8_t** nm, uint16_t* type,
228 uint16_t* dclass, uint32_t* ttl, ldns_buffer* rdata)
231 ldns_status status = ldns_rr_new_frm_str(&rr, str, 3600, NULL, NULL);
232 if(status != LDNS_STATUS_OK) {
233 log_err("error parsing local-data '%s': %s",
234 str, ldns_get_errorstr_by_id(status));
238 *nm = memdup(ldns_rdf_data(ldns_rr_owner(rr)),
239 ldns_rdf_size(ldns_rr_owner(rr)));
241 log_err("out of memory");
245 *dclass = ldns_rr_get_class(rr);
246 *type = ldns_rr_get_type(rr);
247 *ttl = (uint32_t)ldns_rr_ttl(rr);
248 ldns_buffer_clear(rdata);
249 ldns_buffer_skip(rdata, 2);
250 status = ldns_rr_rdata2buffer_wire(rdata, rr);
252 if(status != LDNS_STATUS_OK) {
253 log_err("error converting RR '%s' to wireformat: %s",
254 str, ldns_get_errorstr_by_id(status));
259 ldns_buffer_flip(rdata);
260 ldns_buffer_write_u16_at(rdata, 0, ldns_buffer_limit(rdata) - 2);
264 /** return name and class of rr; parses string */
266 get_rr_nameclass(const char* str, uint8_t** nm, uint16_t* dclass)
269 ldns_status status = ldns_rr_new_frm_str(&rr, str, 3600, NULL, NULL);
270 if(status != LDNS_STATUS_OK) {
271 log_err("error parsing local-data '%s': %s",
272 str, ldns_get_errorstr_by_id(status));
276 *nm = memdup(ldns_rdf_data(ldns_rr_owner(rr)),
277 ldns_rdf_size(ldns_rr_owner(rr)));
278 *dclass = ldns_rr_get_class(rr);
281 log_err("out of memory");
288 * Find an rrset in local data structure.
289 * @param data: local data domain name structure.
290 * @param type: type to look for (host order).
291 * @return rrset pointer or NULL if not found.
293 static struct local_rrset*
294 local_data_find_type(struct local_data* data, uint16_t type)
296 struct local_rrset* p;
298 for(p = data->rrsets; p; p = p->next) {
299 if(p->rrset->rk.type == type)
305 /** check for RR duplicates */
307 rr_is_duplicate(struct packed_rrset_data* pd, ldns_buffer* buf)
310 for(i=0; i<pd->count; i++) {
311 if(ldns_buffer_limit(buf) == pd->rr_len[i] &&
312 memcmp(ldns_buffer_begin(buf), pd->rr_data[i],
313 ldns_buffer_limit(buf)) == 0)
319 /** new local_rrset */
320 static struct local_rrset*
321 new_local_rrset(struct regional* region, struct local_data* node,
322 uint16_t rrtype, uint16_t rrclass)
324 struct packed_rrset_data* pd;
325 struct local_rrset* rrset = (struct local_rrset*)
326 regional_alloc_zero(region, sizeof(*rrset));
328 log_err("out of memory");
331 rrset->next = node->rrsets;
332 node->rrsets = rrset;
333 rrset->rrset = (struct ub_packed_rrset_key*)
334 regional_alloc_zero(region, sizeof(*rrset->rrset));
336 log_err("out of memory");
339 rrset->rrset->entry.key = rrset->rrset;
340 pd = (struct packed_rrset_data*)regional_alloc_zero(region,
343 log_err("out of memory");
346 pd->trust = rrset_trust_prim_noglue;
347 pd->security = sec_status_insecure;
348 rrset->rrset->entry.data = pd;
349 rrset->rrset->rk.dname = node->name;
350 rrset->rrset->rk.dname_len = node->namelen;
351 rrset->rrset->rk.type = htons(rrtype);
352 rrset->rrset->rk.rrset_class = htons(rrclass);
356 /** insert RR into RRset data structure; Wastes a couple of bytes */
358 insert_rr(struct regional* region, struct packed_rrset_data* pd,
359 ldns_buffer* buf, uint32_t ttl)
361 size_t* oldlen = pd->rr_len;
362 uint32_t* oldttl = pd->rr_ttl;
363 uint8_t** olddata = pd->rr_data;
365 /* add RR to rrset */
367 pd->rr_len = regional_alloc(region, sizeof(*pd->rr_len)*pd->count);
368 pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count);
369 pd->rr_data = regional_alloc(region, sizeof(*pd->rr_data)*pd->count);
370 if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) {
371 log_err("out of memory");
375 memcpy(pd->rr_len+1, oldlen,
376 sizeof(*pd->rr_len)*(pd->count-1));
377 memcpy(pd->rr_ttl+1, oldttl,
378 sizeof(*pd->rr_ttl)*(pd->count-1));
379 memcpy(pd->rr_data+1, olddata,
380 sizeof(*pd->rr_data)*(pd->count-1));
382 pd->rr_len[0] = ldns_buffer_limit(buf);
384 pd->rr_data[0] = regional_alloc_init(region,
385 ldns_buffer_begin(buf), ldns_buffer_limit(buf));
386 if(!pd->rr_data[0]) {
387 log_err("out of memory");
393 /** find a data node by exact name */
394 static struct local_data*
395 lz_find_node(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs)
397 struct local_data key;
401 key.namelabs = nmlabs;
402 return (struct local_data*)rbtree_search(&z->data, &key.node);
405 /** find a node, create it if not and all its empty nonterminal parents */
407 lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
408 int nmlabs, struct local_data** res)
410 struct local_data* ld = lz_find_node(z, nm, nmlen, nmlabs);
412 /* create a domain name to store rr. */
413 ld = (struct local_data*)regional_alloc_zero(z->region,
416 log_err("out of memory adding local data");
420 ld->name = regional_alloc_init(z->region, nm, nmlen);
422 log_err("out of memory");
426 ld->namelabs = nmlabs;
427 if(!rbtree_insert(&z->data, &ld->node)) {
428 log_assert(0); /* duplicate name */
430 /* see if empty nonterminals need to be created */
431 if(nmlabs > z->namelabs) {
432 dname_remove_label(&nm, &nmlen);
433 if(!lz_find_create_node(z, nm, nmlen, nmlabs-1, res))
441 /** enter data RR into auth zone */
443 lz_enter_rr_into_zone(struct local_zone* z, ldns_buffer* buf,
449 struct local_data* node;
450 struct local_rrset* rrset;
451 struct packed_rrset_data* pd;
452 uint16_t rrtype = 0, rrclass = 0;
454 if(!get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, buf)) {
455 log_err("bad local-data: %s", rrstr);
458 log_assert(z->dclass == rrclass);
459 if(z->type == local_zone_redirect &&
460 query_dname_compare(z->name, nm) != 0) {
461 log_err("local-data in redirect zone must reside at top of zone"
462 ", not at %s", rrstr);
466 nmlabs = dname_count_size_labels(nm, &nmlen);
467 if(!lz_find_create_node(z, nm, nmlen, nmlabs, &node)) {
474 rrset = local_data_find_type(node, rrtype);
476 rrset = new_local_rrset(z->region, node, rrtype, rrclass);
479 if(query_dname_compare(node->name, z->name) == 0) {
480 if(rrtype == LDNS_RR_TYPE_NSEC)
481 rrset->rrset->rk.flags = PACKED_RRSET_NSEC_AT_APEX;
482 if(rrtype == LDNS_RR_TYPE_SOA)
483 z->soa = rrset->rrset;
486 pd = (struct packed_rrset_data*)rrset->rrset->entry.data;
487 log_assert(rrset && pd);
489 /* check for duplicate RR */
490 if(rr_is_duplicate(pd, buf)) {
491 verbose(VERB_ALGO, "ignoring duplicate RR: %s", rrstr);
494 return insert_rr(z->region, pd, buf, ttl);
497 /** enter a data RR into auth data; a zone for it must exist */
499 lz_enter_rr_str(struct local_zones* zones, const char* rr, ldns_buffer* buf)
505 struct local_zone* z;
507 if(!get_rr_nameclass(rr, &rr_name, &rr_class)) {
508 log_err("bad rr %s", rr);
511 labs = dname_count_size_labels(rr_name, &len);
512 lock_quick_lock(&zones->lock);
513 z = local_zones_lookup(zones, rr_name, len, labs, rr_class);
515 lock_quick_unlock(&zones->lock);
516 fatal_exit("internal error: no zone for rr %s", rr);
518 lock_rw_wrlock(&z->lock);
519 lock_quick_unlock(&zones->lock);
521 r = lz_enter_rr_into_zone(z, buf, rr);
522 lock_rw_unlock(&z->lock);
526 /** parse local-zone: statements */
528 lz_enter_zones(struct local_zones* zones, struct config_file* cfg)
530 struct config_str2list* p;
531 struct local_zone* z;
532 for(p = cfg->local_zones; p; p = p->next) {
533 if(!(z=lz_enter_zone(zones, p->str, p->str2,
536 lock_rw_unlock(&z->lock);
541 /** lookup a zone in rbtree; exact match only; SLOW due to parse */
543 lz_exists(struct local_zones* zones, const char* name)
547 z.dclass = LDNS_RR_CLASS_IN;
548 if(!parse_dname(name, &z.name, &z.namelen, &z.namelabs)) {
549 log_err("bad name %s", name);
552 lock_quick_lock(&zones->lock);
553 if(rbtree_search(&zones->ztree, &z.node)) {
554 lock_quick_unlock(&zones->lock);
558 lock_quick_unlock(&zones->lock);
563 /** lookup a zone in cfg->nodefault list */
565 lz_nodefault(struct config_file* cfg, const char* name)
567 struct config_strlist* p;
568 size_t len = strlen(name);
569 if(len == 0) return 0;
570 if(name[len-1] == '.') len--;
572 for(p = cfg->local_zones_nodefault; p; p = p->next) {
573 /* compare zone name, lowercase, compare without ending . */
574 if(strncasecmp(p->str, name, len) == 0 &&
575 (strlen(p->str) == len || (strlen(p->str)==len+1 &&
576 p->str[len] == '.')))
582 /** enter AS112 default zone */
584 add_as112_default(struct local_zones* zones, struct config_file* cfg,
585 ldns_buffer* buf, const char* name)
587 struct local_zone* z;
588 char str[1024]; /* known long enough */
589 if(lz_exists(zones, name) || lz_nodefault(cfg, name))
590 return 1; /* do not enter default content */
591 if(!(z=lz_enter_zone(zones, name, "static", LDNS_RR_CLASS_IN)))
593 snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. "
594 "nobody.invalid. 1 3600 1200 604800 10800", name);
595 if(!lz_enter_rr_into_zone(z, buf, str)) {
596 lock_rw_unlock(&z->lock);
599 snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name);
600 if(!lz_enter_rr_into_zone(z, buf, str)) {
601 lock_rw_unlock(&z->lock);
604 lock_rw_unlock(&z->lock);
608 /** enter default zones */
610 lz_enter_defaults(struct local_zones* zones, struct config_file* cfg,
613 struct local_zone* z;
615 /* this list of zones is from RFC 6303 */
617 /* localhost. zone */
618 if(!lz_exists(zones, "localhost.") &&
619 !lz_nodefault(cfg, "localhost.")) {
620 if(!(z=lz_enter_zone(zones, "localhost.", "static",
621 LDNS_RR_CLASS_IN)) ||
622 !lz_enter_rr_into_zone(z, buf,
623 "localhost. 10800 IN NS localhost.") ||
624 !lz_enter_rr_into_zone(z, buf,
625 "localhost. 10800 IN SOA localhost. nobody.invalid. "
626 "1 3600 1200 604800 10800") ||
627 !lz_enter_rr_into_zone(z, buf,
628 "localhost. 10800 IN A 127.0.0.1") ||
629 !lz_enter_rr_into_zone(z, buf,
630 "localhost. 10800 IN AAAA ::1")) {
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 ip4 zone */
638 if(!lz_exists(zones, "127.in-addr.arpa.") &&
639 !lz_nodefault(cfg, "127.in-addr.arpa.")) {
640 if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static",
641 LDNS_RR_CLASS_IN)) ||
642 !lz_enter_rr_into_zone(z, buf,
643 "127.in-addr.arpa. 10800 IN NS localhost.") ||
644 !lz_enter_rr_into_zone(z, buf,
645 "127.in-addr.arpa. 10800 IN SOA localhost. "
646 "nobody.invalid. 1 3600 1200 604800 10800") ||
647 !lz_enter_rr_into_zone(z, buf,
648 "1.0.0.127.in-addr.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);
655 /* reverse ip6 zone */
656 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.") &&
657 !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.")) {
658 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",
659 LDNS_RR_CLASS_IN)) ||
660 !lz_enter_rr_into_zone(z, buf,
661 "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.") ||
662 !lz_enter_rr_into_zone(z, buf,
663 "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. "
664 "nobody.invalid. 1 3600 1200 604800 10800") ||
665 !lz_enter_rr_into_zone(z, buf,
666 "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.")) {
667 log_err("out of memory adding default zone");
668 if(z) { lock_rw_unlock(&z->lock); }
671 lock_rw_unlock(&z->lock);
673 if ( !add_as112_default(zones, cfg, buf, "10.in-addr.arpa.") ||
674 !add_as112_default(zones, cfg, buf, "16.172.in-addr.arpa.") ||
675 !add_as112_default(zones, cfg, buf, "17.172.in-addr.arpa.") ||
676 !add_as112_default(zones, cfg, buf, "18.172.in-addr.arpa.") ||
677 !add_as112_default(zones, cfg, buf, "19.172.in-addr.arpa.") ||
678 !add_as112_default(zones, cfg, buf, "20.172.in-addr.arpa.") ||
679 !add_as112_default(zones, cfg, buf, "21.172.in-addr.arpa.") ||
680 !add_as112_default(zones, cfg, buf, "22.172.in-addr.arpa.") ||
681 !add_as112_default(zones, cfg, buf, "23.172.in-addr.arpa.") ||
682 !add_as112_default(zones, cfg, buf, "24.172.in-addr.arpa.") ||
683 !add_as112_default(zones, cfg, buf, "25.172.in-addr.arpa.") ||
684 !add_as112_default(zones, cfg, buf, "26.172.in-addr.arpa.") ||
685 !add_as112_default(zones, cfg, buf, "27.172.in-addr.arpa.") ||
686 !add_as112_default(zones, cfg, buf, "28.172.in-addr.arpa.") ||
687 !add_as112_default(zones, cfg, buf, "29.172.in-addr.arpa.") ||
688 !add_as112_default(zones, cfg, buf, "30.172.in-addr.arpa.") ||
689 !add_as112_default(zones, cfg, buf, "31.172.in-addr.arpa.") ||
690 !add_as112_default(zones, cfg, buf, "168.192.in-addr.arpa.") ||
691 !add_as112_default(zones, cfg, buf, "0.in-addr.arpa.") ||
692 !add_as112_default(zones, cfg, buf, "254.169.in-addr.arpa.") ||
693 !add_as112_default(zones, cfg, buf, "2.0.192.in-addr.arpa.") ||
694 !add_as112_default(zones, cfg, buf, "100.51.198.in-addr.arpa.") ||
695 !add_as112_default(zones, cfg, buf, "113.0.203.in-addr.arpa.") ||
696 !add_as112_default(zones, cfg, buf, "255.255.255.255.in-addr.arpa.") ||
697 !add_as112_default(zones, cfg, buf, "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.") ||
698 !add_as112_default(zones, cfg, buf, "d.f.ip6.arpa.") ||
699 !add_as112_default(zones, cfg, buf, "8.e.f.ip6.arpa.") ||
700 !add_as112_default(zones, cfg, buf, "9.e.f.ip6.arpa.") ||
701 !add_as112_default(zones, cfg, buf, "a.e.f.ip6.arpa.") ||
702 !add_as112_default(zones, cfg, buf, "b.e.f.ip6.arpa.") ||
703 !add_as112_default(zones, cfg, buf, "8.b.d.0.1.0.0.2.ip6.arpa.")) {
704 log_err("out of memory adding default zone");
710 /** setup parent pointers, so that a lookup can be done for closest match */
712 init_parents(struct local_zones* zones)
714 struct local_zone* node, *prev = NULL, *p;
716 lock_quick_lock(&zones->lock);
717 RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
718 lock_rw_wrlock(&node->lock);
720 if(!prev || prev->dclass != node->dclass) {
722 lock_rw_unlock(&node->lock);
725 (void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
726 node->namelabs, &m); /* we know prev is smaller */
727 /* sort order like: . com. bla.com. zwb.com. net. */
728 /* find the previous, or parent-parent-parent */
729 for(p = prev; p; p = p->parent)
730 /* looking for name with few labels, a parent */
731 if(p->namelabs <= m) {
732 /* ==: since prev matched m, this is closest*/
733 /* <: prev matches more, but is not a parent,
734 * this one is a (grand)parent */
739 lock_rw_unlock(&node->lock);
741 lock_quick_unlock(&zones->lock);
744 /** enter implicit transparent zone for local-data: without local-zone: */
746 lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
748 /* walk over all items that have no parent zone and find
749 * the name that covers them all (could be the root) and
750 * add that as a transparent zone */
751 struct config_strlist* p;
753 int have_other_classes = 0;
758 int match = 0; /* number of labels match count */
760 init_parents(zones); /* to enable local_zones_lookup() */
761 for(p = cfg->local_data; p; p = p->next) {
766 if(!get_rr_nameclass(p->str, &rr_name, &rr_class)) {
767 log_err("Bad local-data RR %s", p->str);
770 labs = dname_count_size_labels(rr_name, &len);
771 lock_quick_lock(&zones->lock);
772 if(!local_zones_lookup(zones, rr_name, len, labs, rr_class)) {
782 if(rr_class != dclass) {
783 /* process other classes later */
785 have_other_classes = 1;
786 lock_quick_unlock(&zones->lock);
789 /* find smallest shared topdomain */
790 (void)dname_lab_cmp(nm, nmlabs,
796 } else free(rr_name);
797 lock_quick_unlock(&zones->lock);
801 struct local_zone* z;
802 /* allocate zone of smallest shared topdomain to contain em */
804 dname_remove_labels(&n2, &nmlen, nmlabs - match);
805 n2 = memdup(n2, nmlen);
808 log_err("out of memory");
811 log_nametypeclass(VERB_ALGO, "implicit transparent local-zone",
813 if(!(z=lz_enter_zone_dname(zones, n2, nmlen, match,
814 local_zone_transparent, dclass))) {
817 lock_rw_unlock(&z->lock);
819 if(have_other_classes) {
820 /* restart to setup other class */
821 return lz_setup_implicit(zones, cfg);
826 /** enter auth data */
828 lz_enter_data(struct local_zones* zones, struct config_file* cfg,
831 struct config_strlist* p;
832 for(p = cfg->local_data; p; p = p->next) {
833 if(!lz_enter_rr_str(zones, p->str, buf))
839 /** free memory from config */
841 lz_freeup_cfg(struct config_file* cfg)
843 config_deldblstrlist(cfg->local_zones);
844 cfg->local_zones = NULL;
845 config_delstrlist(cfg->local_zones_nodefault);
846 cfg->local_zones_nodefault = NULL;
847 config_delstrlist(cfg->local_data);
848 cfg->local_data = NULL;
852 local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg)
854 ldns_buffer* buf = ldns_buffer_new(65535);
855 if(!buf) fatal_exit("cannot create temporary buffer");
857 /* create zones from zone statements. */
858 if(!lz_enter_zones(zones, cfg)) {
859 ldns_buffer_free(buf);
862 /* apply default zones+content (unless disabled, or overridden) */
863 if(!lz_enter_defaults(zones, cfg, buf)) {
864 ldns_buffer_free(buf);
867 /* create implicit transparent zone from data. */
868 if(!lz_setup_implicit(zones, cfg)) {
869 ldns_buffer_free(buf);
873 /* setup parent ptrs for lookup during data entry */
875 /* insert local data */
876 if(!lz_enter_data(zones, cfg, buf)) {
877 ldns_buffer_free(buf);
880 /* freeup memory from cfg struct. */
882 ldns_buffer_free(buf);
887 local_zones_lookup(struct local_zones* zones,
888 uint8_t* name, size_t len, int labs, uint16_t dclass)
890 rbnode_t* res = NULL;
891 struct local_zone *result;
892 struct local_zone key;
898 if(rbtree_find_less_equal(&zones->ztree, &key, &res)) {
900 return (struct local_zone*)res;
902 /* smaller element (or no element) */
904 result = (struct local_zone*)res;
905 if(!result || result->dclass != dclass)
907 /* count number of labels matched */
908 (void)dname_lab_cmp(result->name, result->namelabs, key.name,
910 while(result) { /* go up until qname is subdomain of zone */
911 if(result->namelabs <= m)
913 result = result->parent;
920 local_zones_find(struct local_zones* zones,
921 uint8_t* name, size_t len, int labs, uint16_t dclass)
923 struct local_zone key;
930 return (struct local_zone*)rbtree_search(&zones->ztree, &key);
933 /** print all RRsets in local zone */
935 local_zone_out(struct local_zone* z)
937 struct local_data* d;
938 struct local_rrset* p;
939 RBTREE_FOR(d, struct local_data*, &z->data) {
940 for(p = d->rrsets; p; p = p->next) {
941 log_nametypeclass(0, "rrset", d->name,
942 ntohs(p->rrset->rk.type),
943 ntohs(p->rrset->rk.rrset_class));
948 void local_zones_print(struct local_zones* zones)
950 struct local_zone* z;
951 lock_quick_lock(&zones->lock);
952 log_info("number of auth zones %u", (unsigned)zones->ztree.count);
953 RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
954 lock_rw_rdlock(&z->lock);
956 case local_zone_deny:
957 log_nametypeclass(0, "deny zone",
958 z->name, 0, z->dclass);
960 case local_zone_refuse:
961 log_nametypeclass(0, "refuse zone",
962 z->name, 0, z->dclass);
964 case local_zone_redirect:
965 log_nametypeclass(0, "redirect zone",
966 z->name, 0, z->dclass);
968 case local_zone_transparent:
969 log_nametypeclass(0, "transparent zone",
970 z->name, 0, z->dclass);
972 case local_zone_typetransparent:
973 log_nametypeclass(0, "typetransparent zone",
974 z->name, 0, z->dclass);
976 case local_zone_static:
977 log_nametypeclass(0, "static zone",
978 z->name, 0, z->dclass);
981 log_nametypeclass(0, "badtyped zone",
982 z->name, 0, z->dclass);
986 lock_rw_unlock(&z->lock);
988 lock_quick_unlock(&zones->lock);
991 /** encode answer consisting of 1 rrset */
993 local_encode(struct query_info* qinfo, struct edns_data* edns,
994 ldns_buffer* buf, struct regional* temp,
995 struct ub_packed_rrset_key* rrset, int ansec, int rcode)
997 struct reply_info rep;
999 /* make answer with time=0 for fixed TTL values */
1000 memset(&rep, 0, sizeof(rep));
1001 rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode);
1004 rep.an_numrrsets = 1;
1005 else rep.ns_numrrsets = 1;
1006 rep.rrset_count = 1;
1007 rep.rrsets = &rrset;
1008 udpsize = edns->udp_size;
1009 edns->edns_version = EDNS_ADVERTISED_VERSION;
1010 edns->udp_size = EDNS_ADVERTISED_SIZE;
1011 edns->ext_rcode = 0;
1012 edns->bits &= EDNS_DO;
1013 if(!reply_info_answer_encode(qinfo, &rep,
1014 *(uint16_t*)ldns_buffer_begin(buf),
1015 ldns_buffer_read_u16_at(buf, 2),
1016 buf, 0, 0, temp, udpsize, edns,
1017 (int)(edns->bits&EDNS_DO), 0))
1018 error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
1019 *(uint16_t*)ldns_buffer_begin(buf),
1020 ldns_buffer_read_u16_at(buf, 2), edns);
1024 /** answer local data match */
1026 local_data_answer(struct local_zone* z, struct query_info* qinfo,
1027 struct edns_data* edns, ldns_buffer* buf, struct regional* temp,
1028 int labs, struct local_data** ldp)
1030 struct local_data key;
1031 struct local_data* ld;
1032 struct local_rrset* lr;
1033 key.node.key = &key;
1034 key.name = qinfo->qname;
1035 key.namelen = qinfo->qname_len;
1036 key.namelabs = labs;
1037 if(z->type == local_zone_redirect) {
1039 key.namelen = z->namelen;
1040 key.namelabs = z->namelabs;
1042 ld = (struct local_data*)rbtree_search(&z->data, &key.node);
1047 lr = local_data_find_type(ld, qinfo->qtype);
1050 if(z->type == local_zone_redirect) {
1051 /* convert rrset name to query name; like a wildcard */
1052 struct ub_packed_rrset_key r = *lr->rrset;
1053 r.rk.dname = qinfo->qname;
1054 r.rk.dname_len = qinfo->qname_len;
1055 return local_encode(qinfo, edns, buf, temp, &r, 1,
1056 LDNS_RCODE_NOERROR);
1058 return local_encode(qinfo, edns, buf, temp, lr->rrset, 1,
1059 LDNS_RCODE_NOERROR);
1063 * answer in case where no exact match is found
1064 * @param z: zone for query
1065 * @param qinfo: query
1066 * @param edns: edns from query
1067 * @param buf: buffer for answer.
1068 * @param temp: temp region for encoding
1069 * @param ld: local data, if NULL, no such name exists in localdata.
1070 * @return 1 if a reply is to be sent, 0 if not.
1073 lz_zone_answer(struct local_zone* z, struct query_info* qinfo,
1074 struct edns_data* edns, ldns_buffer* buf, struct regional* temp,
1075 struct local_data* ld)
1077 if(z->type == local_zone_deny) {
1078 /** no reply at all, signal caller by clearing buffer. */
1079 ldns_buffer_clear(buf);
1080 ldns_buffer_flip(buf);
1082 } else if(z->type == local_zone_refuse) {
1083 error_encode(buf, (LDNS_RCODE_REFUSED|BIT_AA), qinfo,
1084 *(uint16_t*)ldns_buffer_begin(buf),
1085 ldns_buffer_read_u16_at(buf, 2), edns);
1087 } else if(z->type == local_zone_static ||
1088 z->type == local_zone_redirect) {
1089 /* for static, reply nodata or nxdomain
1090 * for redirect, reply nodata */
1091 /* no additional section processing,
1092 * cname, dname or wildcard processing,
1093 * or using closest match for NSEC.
1094 * or using closest match for returning delegation downwards
1096 int rcode = ld?LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
1098 return local_encode(qinfo, edns, buf, temp,
1100 error_encode(buf, (rcode|BIT_AA), qinfo,
1101 *(uint16_t*)ldns_buffer_begin(buf),
1102 ldns_buffer_read_u16_at(buf, 2), edns);
1104 } else if(z->type == local_zone_typetransparent) {
1105 /* no NODATA or NXDOMAINS for this zone type */
1108 /* else z->type == local_zone_transparent */
1110 /* if the zone is transparent and the name exists, but the type
1111 * does not, then we should make this noerror/nodata */
1112 if(ld && ld->rrsets) {
1113 int rcode = LDNS_RCODE_NOERROR;
1115 return local_encode(qinfo, edns, buf, temp,
1117 error_encode(buf, (rcode|BIT_AA), qinfo,
1118 *(uint16_t*)ldns_buffer_begin(buf),
1119 ldns_buffer_read_u16_at(buf, 2), edns);
1123 /* stop here, and resolve further on */
1128 local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
1129 struct edns_data* edns, ldns_buffer* buf, struct regional* temp)
1131 /* see if query is covered by a zone,
1132 * if so: - try to match (exact) local data
1133 * - look at zone type for negative response. */
1134 int labs = dname_count_labels(qinfo->qname);
1135 struct local_data* ld;
1136 struct local_zone* z;
1138 lock_quick_lock(&zones->lock);
1139 z = local_zones_lookup(zones, qinfo->qname,
1140 qinfo->qname_len, labs, qinfo->qclass);
1142 lock_quick_unlock(&zones->lock);
1145 lock_rw_rdlock(&z->lock);
1146 lock_quick_unlock(&zones->lock);
1148 if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) {
1149 lock_rw_unlock(&z->lock);
1152 r = lz_zone_answer(z, qinfo, edns, buf, temp, ld);
1153 lock_rw_unlock(&z->lock);
1157 const char* local_zone_type2str(enum localzone_type t)
1160 case local_zone_deny: return "deny";
1161 case local_zone_refuse: return "refuse";
1162 case local_zone_redirect: return "redirect";
1163 case local_zone_transparent: return "transparent";
1164 case local_zone_typetransparent: return "typetransparent";
1165 case local_zone_static: return "static";
1166 case local_zone_nodefault: return "nodefault";
1171 int local_zone_str2type(const char* type, enum localzone_type* t)
1173 if(strcmp(type, "deny") == 0)
1174 *t = local_zone_deny;
1175 else if(strcmp(type, "refuse") == 0)
1176 *t = local_zone_refuse;
1177 else if(strcmp(type, "static") == 0)
1178 *t = local_zone_static;
1179 else if(strcmp(type, "transparent") == 0)
1180 *t = local_zone_transparent;
1181 else if(strcmp(type, "typetransparent") == 0)
1182 *t = local_zone_typetransparent;
1183 else if(strcmp(type, "redirect") == 0)
1184 *t = local_zone_redirect;
1189 /** iterate over the kiddies of the given name and set their parent ptr */
1191 set_kiddo_parents(struct local_zone* z, struct local_zone* match,
1192 struct local_zone* newp)
1194 /* both zones and z are locked already */
1195 /* in the sorted rbtree, the kiddies of z are located after z */
1196 /* z must be present in the tree */
1197 struct local_zone* p = z;
1198 p = (struct local_zone*)rbtree_next(&p->node);
1199 while(p!=(struct local_zone*)RBTREE_NULL &&
1200 p->dclass == z->dclass && dname_strict_subdomain(p->name,
1201 p->namelabs, z->name, z->namelabs)) {
1202 /* update parent ptr */
1203 /* only when matches with existing parent pointer, so that
1204 * deeper child structures are not touched, i.e.
1205 * update of x, and a.x, b.x, f.b.x, g.b.x, c.x, y
1206 * gets to update a.x, b.x and c.x */
1207 lock_rw_wrlock(&p->lock);
1208 if(p->parent == match)
1210 lock_rw_unlock(&p->lock);
1211 p = (struct local_zone*)rbtree_next(&p->node);
1215 struct local_zone* local_zones_add_zone(struct local_zones* zones,
1216 uint8_t* name, size_t len, int labs, uint16_t dclass,
1217 enum localzone_type tp)
1220 struct local_zone* z = local_zone_create(name, len, labs, tp, dclass);
1222 lock_rw_wrlock(&z->lock);
1224 /* find the closest parent */
1225 z->parent = local_zones_find(zones, name, len, labs, dclass);
1227 /* insert into the tree */
1228 if(!rbtree_insert(&zones->ztree, &z->node)) {
1229 /* duplicate entry! */
1230 lock_rw_unlock(&z->lock);
1231 local_zone_delete(z);
1232 log_err("internal: duplicate entry in local_zones_add_zone");
1236 /* set parent pointers right */
1237 set_kiddo_parents(z, z->parent, z);
1239 lock_rw_unlock(&z->lock);
1243 void local_zones_del_zone(struct local_zones* zones, struct local_zone* z)
1245 /* fix up parents in tree */
1246 lock_rw_wrlock(&z->lock);
1247 set_kiddo_parents(z, z, z->parent);
1249 /* remove from tree */
1250 (void)rbtree_delete(&zones->ztree, z);
1252 /* delete the zone */
1253 lock_rw_unlock(&z->lock);
1254 local_zone_delete(z);
1258 local_zones_add_RR(struct local_zones* zones, const char* rr, ldns_buffer* buf)
1264 struct local_zone* z;
1266 if(!get_rr_nameclass(rr, &rr_name, &rr_class)) {
1269 labs = dname_count_size_labels(rr_name, &len);
1270 lock_quick_lock(&zones->lock);
1271 z = local_zones_lookup(zones, rr_name, len, labs, rr_class);
1273 z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
1274 local_zone_transparent);
1276 lock_quick_unlock(&zones->lock);
1282 lock_rw_wrlock(&z->lock);
1283 lock_quick_unlock(&zones->lock);
1284 r = lz_enter_rr_into_zone(z, buf, rr);
1285 lock_rw_unlock(&z->lock);
1289 /** returns true if the node is terminal so no deeper domain names exist */
1291 is_terminal(struct local_data* d)
1293 /* for empty nonterminals, the deeper domain names are sorted
1294 * right after them, so simply check the next name in the tree
1296 struct local_data* n = (struct local_data*)rbtree_next(&d->node);
1297 if(n == (struct local_data*)RBTREE_NULL)
1298 return 1; /* last in tree, no deeper node */
1299 if(dname_strict_subdomain(n->name, n->namelabs, d->name, d->namelabs))
1300 return 0; /* there is a deeper node */
1304 /** delete empty terminals from tree when final data is deleted */
1306 del_empty_term(struct local_zone* z, struct local_data* d,
1307 uint8_t* name, size_t len, int labs)
1309 while(d && d->rrsets == NULL && is_terminal(d)) {
1310 /* is this empty nonterminal? delete */
1311 /* note, no memory recycling in zone region */
1312 (void)rbtree_delete(&z->data, d);
1314 /* go up and to the next label */
1315 if(dname_is_root(name))
1317 dname_remove_label(&name, &len);
1319 d = lz_find_node(z, name, len, labs);
1323 void local_zones_del_data(struct local_zones* zones,
1324 uint8_t* name, size_t len, int labs, uint16_t dclass)
1327 struct local_zone* z;
1328 struct local_data* d;
1329 lock_quick_lock(&zones->lock);
1330 z = local_zones_lookup(zones, name, len, labs, dclass);
1332 /* no such zone, we're done */
1333 lock_quick_unlock(&zones->lock);
1336 lock_rw_wrlock(&z->lock);
1337 lock_quick_unlock(&zones->lock);
1339 /* find the domain */
1340 d = lz_find_node(z, name, len, labs);
1342 /* no memory recycling for zone deletions ... */
1344 /* did we delete the soa record ? */
1345 if(query_dname_compare(d->name, z->name) == 0)
1348 /* cleanup the empty nonterminals for this name */
1349 del_empty_term(z, d, name, len, labs);
1352 lock_rw_unlock(&z->lock);