1 /* 2 * services/localzone.c - local zones authority service. 3 * 4 * Copyright (c) 2007, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 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. 18 * 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. 22 * 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. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains functions to enable local zone authority service. 40 */ 41 #include "config.h" 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" 53 54 struct local_zones* 55 local_zones_create(void) 56 { 57 struct local_zones* zones = (struct local_zones*)calloc(1, 58 sizeof(*zones)); 59 if(!zones) 60 return NULL; 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 */ 65 return zones; 66 } 67 68 /** helper traverse to delete zones */ 69 static void 70 lzdel(rbnode_t* n, void* ATTR_UNUSED(arg)) 71 { 72 struct local_zone* z = (struct local_zone*)n->key; 73 local_zone_delete(z); 74 } 75 76 void 77 local_zones_delete(struct local_zones* zones) 78 { 79 if(!zones) 80 return; 81 lock_rw_destroy(&zones->lock); 82 /* walk through zones and delete them all */ 83 traverse_postorder(&zones->ztree, lzdel, NULL); 84 free(zones); 85 } 86 87 void 88 local_zone_delete(struct local_zone* z) 89 { 90 if(!z) 91 return; 92 lock_rw_destroy(&z->lock); 93 regional_destroy(z->region); 94 free(z->name); 95 free(z); 96 } 97 98 int 99 local_zone_cmp(const void* z1, const void* z2) 100 { 101 /* first sort on class, so that hierarchy can be maintained within 102 * a class */ 103 struct local_zone* a = (struct local_zone*)z1; 104 struct local_zone* b = (struct local_zone*)z2; 105 int m; 106 if(a->dclass != b->dclass) { 107 if(a->dclass < b->dclass) 108 return -1; 109 return 1; 110 } 111 return dname_lab_cmp(a->name, a->namelabs, b->name, b->namelabs, &m); 112 } 113 114 int 115 local_data_cmp(const void* d1, const void* d2) 116 { 117 struct local_data* a = (struct local_data*)d1; 118 struct local_data* b = (struct local_data*)d2; 119 int m; 120 return dname_canon_lab_cmp(a->name, a->namelabs, b->name, 121 b->namelabs, &m); 122 } 123 124 /* form wireformat from text format domain name */ 125 int 126 parse_dname(const char* str, uint8_t** res, size_t* len, int* labs) 127 { 128 *res = sldns_str2wire_dname(str, len); 129 *labs = 0; 130 if(!*res) { 131 log_err("cannot parse name %s", str); 132 return 0; 133 } 134 *labs = dname_count_size_labels(*res, len); 135 return 1; 136 } 137 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) 142 { 143 struct local_zone* z = (struct local_zone*)calloc(1, sizeof(*z)); 144 if(!z) { 145 return NULL; 146 } 147 z->node.key = z; 148 z->dclass = dclass; 149 z->type = t; 150 z->name = nm; 151 z->namelen = len; 152 z->namelabs = labs; 153 lock_rw_init(&z->lock); 154 z->region = regional_create(); 155 if(!z->region) { 156 free(z); 157 return NULL; 158 } 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 */ 162 return z; 163 } 164 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) 169 { 170 struct local_zone* z = local_zone_create(nm, len, labs, t, c); 171 if(!z) { 172 log_err("out of memory"); 173 return NULL; 174 } 175 176 /* add to rbtree */ 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); 184 return NULL; 185 } 186 lock_rw_unlock(&zones->lock); 187 return z; 188 } 189 190 /** enter a new zone */ 191 static struct local_zone* 192 lz_enter_zone(struct local_zones* zones, const char* name, const char* type, 193 uint16_t dclass) 194 { 195 struct local_zone* z; 196 enum localzone_type t; 197 uint8_t* nm; 198 size_t len; 199 int labs; 200 if(!parse_dname(name, &nm, &len, &labs)) { 201 log_err("bad zone name %s %s", name, type); 202 return NULL; 203 } 204 if(!local_zone_str2type(type, &t)) { 205 log_err("bad lz_enter_zone type %s %s", name, type); 206 free(nm); 207 return NULL; 208 } 209 if(!(z=lz_enter_zone_dname(zones, nm, len, labs, t, dclass))) { 210 log_err("could not enter zone %s %s", name, type); 211 return NULL; 212 } 213 return z; 214 } 215 216 /** return name and class and rdata of rr; parses string */ 217 static int 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) 221 { 222 size_t dname_len = 0; 223 int e = sldns_str2wire_rr_buf(str, rr, &len, &dname_len, 3600, 224 NULL, 0, NULL, 0); 225 if(e) { 226 log_err("error parsing local-data at %d: '%s': %s", 227 LDNS_WIREPARSE_OFFSET(e), str, 228 sldns_get_errorstr_parse(e)); 229 return 0; 230 } 231 *nm = memdup(rr, dname_len); 232 if(!*nm) { 233 log_err("out of memory"); 234 return 0; 235 } 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; 241 return 1; 242 } 243 244 /** return name and class of rr; parses string */ 245 static int 246 get_rr_nameclass(const char* str, uint8_t** nm, uint16_t* dclass) 247 { 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, 251 NULL, 0, NULL, 0); 252 if(s != 0) { 253 log_err("error parsing local-data at %d '%s': %s", 254 LDNS_WIREPARSE_OFFSET(s), str, 255 sldns_get_errorstr_parse(s)); 256 return 0; 257 } 258 *nm = memdup(rr, dname_len); 259 *dclass = sldns_wirerr_get_class(rr, len, dname_len); 260 if(!*nm) { 261 log_err("out of memory"); 262 return 0; 263 } 264 return 1; 265 } 266 267 /** 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. 272 */ 273 static struct local_rrset* 274 local_data_find_type(struct local_data* data, uint16_t type) 275 { 276 struct local_rrset* p; 277 type = htons(type); 278 for(p = data->rrsets; p; p = p->next) { 279 if(p->rrset->rk.type == type) 280 return p; 281 } 282 return NULL; 283 } 284 285 /** check for RR duplicates */ 286 static int 287 rr_is_duplicate(struct packed_rrset_data* pd, uint8_t* rdata, size_t rdata_len) 288 { 289 size_t i; 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) 293 return 1; 294 } 295 return 0; 296 } 297 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) 302 { 303 struct packed_rrset_data* pd; 304 struct local_rrset* rrset = (struct local_rrset*) 305 regional_alloc_zero(region, sizeof(*rrset)); 306 if(!rrset) { 307 log_err("out of memory"); 308 return NULL; 309 } 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)); 314 if(!rrset->rrset) { 315 log_err("out of memory"); 316 return NULL; 317 } 318 rrset->rrset->entry.key = rrset->rrset; 319 pd = (struct packed_rrset_data*)regional_alloc_zero(region, 320 sizeof(*pd)); 321 if(!pd) { 322 log_err("out of memory"); 323 return NULL; 324 } 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); 332 return rrset; 333 } 334 335 /** insert RR into RRset data structure; Wastes a couple of bytes */ 336 static int 337 insert_rr(struct regional* region, struct packed_rrset_data* pd, 338 uint8_t* rdata, size_t rdata_len, time_t ttl) 339 { 340 size_t* oldlen = pd->rr_len; 341 time_t* oldttl = pd->rr_ttl; 342 uint8_t** olddata = pd->rr_data; 343 344 /* add RR to rrset */ 345 pd->count++; 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"); 351 return 0; 352 } 353 if(pd->count > 1) { 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)); 360 } 361 pd->rr_len[0] = rdata_len; 362 pd->rr_ttl[0] = ttl; 363 pd->rr_data[0] = regional_alloc_init(region, rdata, rdata_len); 364 if(!pd->rr_data[0]) { 365 log_err("out of memory"); 366 return 0; 367 } 368 return 1; 369 } 370 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) 374 { 375 struct local_data key; 376 key.node.key = &key; 377 key.name = nm; 378 key.namelen = nmlen; 379 key.namelabs = nmlabs; 380 return (struct local_data*)rbtree_search(&z->data, &key.node); 381 } 382 383 /** find a node, create it if not and all its empty nonterminal parents */ 384 static int 385 lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen, 386 int nmlabs, struct local_data** res) 387 { 388 struct local_data* ld = lz_find_node(z, nm, nmlen, nmlabs); 389 if(!ld) { 390 /* create a domain name to store rr. */ 391 ld = (struct local_data*)regional_alloc_zero(z->region, 392 sizeof(*ld)); 393 if(!ld) { 394 log_err("out of memory adding local data"); 395 return 0; 396 } 397 ld->node.key = ld; 398 ld->name = regional_alloc_init(z->region, nm, nmlen); 399 if(!ld->name) { 400 log_err("out of memory"); 401 return 0; 402 } 403 ld->namelen = nmlen; 404 ld->namelabs = nmlabs; 405 if(!rbtree_insert(&z->data, &ld->node)) { 406 log_assert(0); /* duplicate name */ 407 } 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)) 412 return 0; 413 } 414 } 415 *res = ld; 416 return 1; 417 } 418 419 /** enter data RR into auth zone */ 420 static int 421 lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr) 422 { 423 uint8_t* nm; 424 size_t nmlen; 425 int nmlabs; 426 struct local_data* node; 427 struct local_rrset* rrset; 428 struct packed_rrset_data* pd; 429 uint16_t rrtype = 0, rrclass = 0; 430 time_t ttl = 0; 431 uint8_t rr[LDNS_RR_BUF_SIZE]; 432 uint8_t* rdata; 433 size_t rdata_len; 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); 437 return 0; 438 } 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); 444 free(nm); 445 return 0; 446 } 447 nmlabs = dname_count_size_labels(nm, &nmlen); 448 if(!lz_find_create_node(z, nm, nmlen, nmlabs, &node)) { 449 free(nm); 450 return 0; 451 } 452 log_assert(node); 453 free(nm); 454 455 rrset = local_data_find_type(node, rrtype); 456 if(!rrset) { 457 rrset = new_local_rrset(z->region, node, rrtype, rrclass); 458 if(!rrset) 459 return 0; 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; 465 } 466 } 467 pd = (struct packed_rrset_data*)rrset->rrset->entry.data; 468 log_assert(rrset && pd); 469 470 /* check for duplicate RR */ 471 if(rr_is_duplicate(pd, rdata, rdata_len)) { 472 verbose(VERB_ALGO, "ignoring duplicate RR: %s", rrstr); 473 return 1; 474 } 475 return insert_rr(z->region, pd, rdata, rdata_len, ttl); 476 } 477 478 /** enter a data RR into auth data; a zone for it must exist */ 479 static int 480 lz_enter_rr_str(struct local_zones* zones, const char* rr) 481 { 482 uint8_t* rr_name; 483 uint16_t rr_class; 484 size_t len; 485 int labs; 486 struct local_zone* z; 487 int r; 488 if(!get_rr_nameclass(rr, &rr_name, &rr_class)) { 489 log_err("bad rr %s", rr); 490 return 0; 491 } 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); 495 if(!z) { 496 lock_rw_unlock(&zones->lock); 497 fatal_exit("internal error: no zone for rr %s", rr); 498 } 499 lock_rw_wrlock(&z->lock); 500 lock_rw_unlock(&zones->lock); 501 free(rr_name); 502 r = lz_enter_rr_into_zone(z, rr); 503 lock_rw_unlock(&z->lock); 504 return r; 505 } 506 507 /** parse local-zone: statements */ 508 static int 509 lz_enter_zones(struct local_zones* zones, struct config_file* cfg) 510 { 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, 515 LDNS_RR_CLASS_IN))) 516 return 0; 517 lock_rw_unlock(&z->lock); 518 } 519 return 1; 520 } 521 522 /** lookup a zone in rbtree; exact match only; SLOW due to parse */ 523 static int 524 lz_exists(struct local_zones* zones, const char* name) 525 { 526 struct local_zone z; 527 z.node.key = &z; 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); 531 return 0; 532 } 533 lock_rw_rdlock(&zones->lock); 534 if(rbtree_search(&zones->ztree, &z.node)) { 535 lock_rw_unlock(&zones->lock); 536 free(z.name); 537 return 1; 538 } 539 lock_rw_unlock(&zones->lock); 540 free(z.name); 541 return 0; 542 } 543 544 /** lookup a zone in cfg->nodefault list */ 545 static int 546 lz_nodefault(struct config_file* cfg, const char* name) 547 { 548 struct config_strlist* p; 549 size_t len = strlen(name); 550 if(len == 0) return 0; 551 if(name[len-1] == '.') len--; 552 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] == '.'))) 558 return 1; 559 } 560 return 0; 561 } 562 563 /** enter AS112 default zone */ 564 static int 565 add_as112_default(struct local_zones* zones, struct config_file* cfg, 566 const char* name) 567 { 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))) 573 return 0; 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); 578 return 0; 579 } 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); 583 return 0; 584 } 585 lock_rw_unlock(&z->lock); 586 return 1; 587 } 588 589 /** enter default zones */ 590 static int 591 lz_enter_defaults(struct local_zones* zones, struct config_file* cfg) 592 { 593 struct local_zone* z; 594 595 /* this list of zones is from RFC 6303 */ 596 597 /* localhost. zone */ 598 if(!lz_exists(zones, "localhost.") && 599 !lz_nodefault(cfg, "localhost.")) { 600 if(!(z=lz_enter_zone(zones, "localhost.", "static", 601 LDNS_RR_CLASS_IN)) || 602 !lz_enter_rr_into_zone(z, 603 "localhost. 10800 IN NS localhost.") || 604 !lz_enter_rr_into_zone(z, 605 "localhost. 10800 IN SOA localhost. nobody.invalid. " 606 "1 3600 1200 604800 10800") || 607 !lz_enter_rr_into_zone(z, 608 "localhost. 10800 IN A 127.0.0.1") || 609 !lz_enter_rr_into_zone(z, 610 "localhost. 10800 IN AAAA ::1")) { 611 log_err("out of memory adding default zone"); 612 if(z) { lock_rw_unlock(&z->lock); } 613 return 0; 614 } 615 lock_rw_unlock(&z->lock); 616 } 617 /* reverse ip4 zone */ 618 if(!lz_exists(zones, "127.in-addr.arpa.") && 619 !lz_nodefault(cfg, "127.in-addr.arpa.")) { 620 if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static", 621 LDNS_RR_CLASS_IN)) || 622 !lz_enter_rr_into_zone(z, 623 "127.in-addr.arpa. 10800 IN NS localhost.") || 624 !lz_enter_rr_into_zone(z, 625 "127.in-addr.arpa. 10800 IN SOA localhost. " 626 "nobody.invalid. 1 3600 1200 604800 10800") || 627 !lz_enter_rr_into_zone(z, 628 "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) { 629 log_err("out of memory adding default zone"); 630 if(z) { lock_rw_unlock(&z->lock); } 631 return 0; 632 } 633 lock_rw_unlock(&z->lock); 634 } 635 /* reverse ip6 zone */ 636 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.") && 637 !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.")) { 638 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", 639 LDNS_RR_CLASS_IN)) || 640 !lz_enter_rr_into_zone(z, 641 "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.") || 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 SOA localhost. " 644 "nobody.invalid. 1 3600 1200 604800 10800") || 645 !lz_enter_rr_into_zone(z, 646 "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.")) { 647 log_err("out of memory adding default zone"); 648 if(z) { lock_rw_unlock(&z->lock); } 649 return 0; 650 } 651 lock_rw_unlock(&z->lock); 652 } 653 if ( !add_as112_default(zones, cfg, "10.in-addr.arpa.") || 654 !add_as112_default(zones, cfg, "16.172.in-addr.arpa.") || 655 !add_as112_default(zones, cfg, "17.172.in-addr.arpa.") || 656 !add_as112_default(zones, cfg, "18.172.in-addr.arpa.") || 657 !add_as112_default(zones, cfg, "19.172.in-addr.arpa.") || 658 !add_as112_default(zones, cfg, "20.172.in-addr.arpa.") || 659 !add_as112_default(zones, cfg, "21.172.in-addr.arpa.") || 660 !add_as112_default(zones, cfg, "22.172.in-addr.arpa.") || 661 !add_as112_default(zones, cfg, "23.172.in-addr.arpa.") || 662 !add_as112_default(zones, cfg, "24.172.in-addr.arpa.") || 663 !add_as112_default(zones, cfg, "25.172.in-addr.arpa.") || 664 !add_as112_default(zones, cfg, "26.172.in-addr.arpa.") || 665 !add_as112_default(zones, cfg, "27.172.in-addr.arpa.") || 666 !add_as112_default(zones, cfg, "28.172.in-addr.arpa.") || 667 !add_as112_default(zones, cfg, "29.172.in-addr.arpa.") || 668 !add_as112_default(zones, cfg, "30.172.in-addr.arpa.") || 669 !add_as112_default(zones, cfg, "31.172.in-addr.arpa.") || 670 !add_as112_default(zones, cfg, "168.192.in-addr.arpa.") || 671 !add_as112_default(zones, cfg, "0.in-addr.arpa.") || 672 !add_as112_default(zones, cfg, "254.169.in-addr.arpa.") || 673 !add_as112_default(zones, cfg, "2.0.192.in-addr.arpa.") || 674 !add_as112_default(zones, cfg, "100.51.198.in-addr.arpa.") || 675 !add_as112_default(zones, cfg, "113.0.203.in-addr.arpa.") || 676 !add_as112_default(zones, cfg, "255.255.255.255.in-addr.arpa.") || 677 !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.") || 678 !add_as112_default(zones, cfg, "d.f.ip6.arpa.") || 679 !add_as112_default(zones, cfg, "8.e.f.ip6.arpa.") || 680 !add_as112_default(zones, cfg, "9.e.f.ip6.arpa.") || 681 !add_as112_default(zones, cfg, "a.e.f.ip6.arpa.") || 682 !add_as112_default(zones, cfg, "b.e.f.ip6.arpa.") || 683 !add_as112_default(zones, cfg, "8.b.d.0.1.0.0.2.ip6.arpa.")) { 684 log_err("out of memory adding default zone"); 685 return 0; 686 } 687 return 1; 688 } 689 690 /** setup parent pointers, so that a lookup can be done for closest match */ 691 static void 692 init_parents(struct local_zones* zones) 693 { 694 struct local_zone* node, *prev = NULL, *p; 695 int m; 696 lock_rw_wrlock(&zones->lock); 697 RBTREE_FOR(node, struct local_zone*, &zones->ztree) { 698 lock_rw_wrlock(&node->lock); 699 node->parent = NULL; 700 if(!prev || prev->dclass != node->dclass) { 701 prev = node; 702 lock_rw_unlock(&node->lock); 703 continue; 704 } 705 (void)dname_lab_cmp(prev->name, prev->namelabs, node->name, 706 node->namelabs, &m); /* we know prev is smaller */ 707 /* sort order like: . com. bla.com. zwb.com. net. */ 708 /* find the previous, or parent-parent-parent */ 709 for(p = prev; p; p = p->parent) 710 /* looking for name with few labels, a parent */ 711 if(p->namelabs <= m) { 712 /* ==: since prev matched m, this is closest*/ 713 /* <: prev matches more, but is not a parent, 714 * this one is a (grand)parent */ 715 node->parent = p; 716 break; 717 } 718 prev = node; 719 lock_rw_unlock(&node->lock); 720 } 721 lock_rw_unlock(&zones->lock); 722 } 723 724 /** enter implicit transparent zone for local-data: without local-zone: */ 725 static int 726 lz_setup_implicit(struct local_zones* zones, struct config_file* cfg) 727 { 728 /* walk over all items that have no parent zone and find 729 * the name that covers them all (could be the root) and 730 * add that as a transparent zone */ 731 struct config_strlist* p; 732 int have_name = 0; 733 int have_other_classes = 0; 734 uint16_t dclass = 0; 735 uint8_t* nm = 0; 736 size_t nmlen = 0; 737 int nmlabs = 0; 738 int match = 0; /* number of labels match count */ 739 740 init_parents(zones); /* to enable local_zones_lookup() */ 741 for(p = cfg->local_data; p; p = p->next) { 742 uint8_t* rr_name; 743 uint16_t rr_class; 744 size_t len; 745 int labs; 746 if(!get_rr_nameclass(p->str, &rr_name, &rr_class)) { 747 log_err("Bad local-data RR %s", p->str); 748 return 0; 749 } 750 labs = dname_count_size_labels(rr_name, &len); 751 lock_rw_rdlock(&zones->lock); 752 if(!local_zones_lookup(zones, rr_name, len, labs, rr_class)) { 753 if(!have_name) { 754 dclass = rr_class; 755 nm = rr_name; 756 nmlen = len; 757 nmlabs = labs; 758 match = labs; 759 have_name = 1; 760 } else { 761 int m; 762 if(rr_class != dclass) { 763 /* process other classes later */ 764 free(rr_name); 765 have_other_classes = 1; 766 lock_rw_unlock(&zones->lock); 767 continue; 768 } 769 /* find smallest shared topdomain */ 770 (void)dname_lab_cmp(nm, nmlabs, 771 rr_name, labs, &m); 772 free(rr_name); 773 if(m < match) 774 match = m; 775 } 776 } else free(rr_name); 777 lock_rw_unlock(&zones->lock); 778 } 779 if(have_name) { 780 uint8_t* n2; 781 struct local_zone* z; 782 /* allocate zone of smallest shared topdomain to contain em */ 783 n2 = nm; 784 dname_remove_labels(&n2, &nmlen, nmlabs - match); 785 n2 = memdup(n2, nmlen); 786 free(nm); 787 if(!n2) { 788 log_err("out of memory"); 789 return 0; 790 } 791 log_nametypeclass(VERB_ALGO, "implicit transparent local-zone", 792 n2, 0, dclass); 793 if(!(z=lz_enter_zone_dname(zones, n2, nmlen, match, 794 local_zone_transparent, dclass))) { 795 return 0; 796 } 797 lock_rw_unlock(&z->lock); 798 } 799 if(have_other_classes) { 800 /* restart to setup other class */ 801 return lz_setup_implicit(zones, cfg); 802 } 803 return 1; 804 } 805 806 /** enter auth data */ 807 static int 808 lz_enter_data(struct local_zones* zones, struct config_file* cfg) 809 { 810 struct config_strlist* p; 811 for(p = cfg->local_data; p; p = p->next) { 812 if(!lz_enter_rr_str(zones, p->str)) 813 return 0; 814 } 815 return 1; 816 } 817 818 /** free memory from config */ 819 static void 820 lz_freeup_cfg(struct config_file* cfg) 821 { 822 config_deldblstrlist(cfg->local_zones); 823 cfg->local_zones = NULL; 824 config_delstrlist(cfg->local_zones_nodefault); 825 cfg->local_zones_nodefault = NULL; 826 config_delstrlist(cfg->local_data); 827 cfg->local_data = NULL; 828 } 829 830 int 831 local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg) 832 { 833 /* create zones from zone statements. */ 834 if(!lz_enter_zones(zones, cfg)) { 835 return 0; 836 } 837 /* apply default zones+content (unless disabled, or overridden) */ 838 if(!lz_enter_defaults(zones, cfg)) { 839 return 0; 840 } 841 /* create implicit transparent zone from data. */ 842 if(!lz_setup_implicit(zones, cfg)) { 843 return 0; 844 } 845 846 /* setup parent ptrs for lookup during data entry */ 847 init_parents(zones); 848 /* insert local data */ 849 if(!lz_enter_data(zones, cfg)) { 850 return 0; 851 } 852 /* freeup memory from cfg struct. */ 853 lz_freeup_cfg(cfg); 854 return 1; 855 } 856 857 struct local_zone* 858 local_zones_lookup(struct local_zones* zones, 859 uint8_t* name, size_t len, int labs, uint16_t dclass) 860 { 861 rbnode_t* res = NULL; 862 struct local_zone *result; 863 struct local_zone key; 864 key.node.key = &key; 865 key.dclass = dclass; 866 key.name = name; 867 key.namelen = len; 868 key.namelabs = labs; 869 if(rbtree_find_less_equal(&zones->ztree, &key, &res)) { 870 /* exact */ 871 return (struct local_zone*)res; 872 } else { 873 /* smaller element (or no element) */ 874 int m; 875 result = (struct local_zone*)res; 876 if(!result || result->dclass != dclass) 877 return NULL; 878 /* count number of labels matched */ 879 (void)dname_lab_cmp(result->name, result->namelabs, key.name, 880 key.namelabs, &m); 881 while(result) { /* go up until qname is subdomain of zone */ 882 if(result->namelabs <= m) 883 break; 884 result = result->parent; 885 } 886 return result; 887 } 888 } 889 890 struct local_zone* 891 local_zones_find(struct local_zones* zones, 892 uint8_t* name, size_t len, int labs, uint16_t dclass) 893 { 894 struct local_zone key; 895 key.node.key = &key; 896 key.dclass = dclass; 897 key.name = name; 898 key.namelen = len; 899 key.namelabs = labs; 900 /* exact */ 901 return (struct local_zone*)rbtree_search(&zones->ztree, &key); 902 } 903 904 /** print all RRsets in local zone */ 905 static void 906 local_zone_out(struct local_zone* z) 907 { 908 struct local_data* d; 909 struct local_rrset* p; 910 RBTREE_FOR(d, struct local_data*, &z->data) { 911 for(p = d->rrsets; p; p = p->next) { 912 log_nametypeclass(0, "rrset", d->name, 913 ntohs(p->rrset->rk.type), 914 ntohs(p->rrset->rk.rrset_class)); 915 } 916 } 917 } 918 919 void local_zones_print(struct local_zones* zones) 920 { 921 struct local_zone* z; 922 lock_rw_rdlock(&zones->lock); 923 log_info("number of auth zones %u", (unsigned)zones->ztree.count); 924 RBTREE_FOR(z, struct local_zone*, &zones->ztree) { 925 lock_rw_rdlock(&z->lock); 926 switch(z->type) { 927 case local_zone_deny: 928 log_nametypeclass(0, "deny zone", 929 z->name, 0, z->dclass); 930 break; 931 case local_zone_refuse: 932 log_nametypeclass(0, "refuse zone", 933 z->name, 0, z->dclass); 934 break; 935 case local_zone_redirect: 936 log_nametypeclass(0, "redirect zone", 937 z->name, 0, z->dclass); 938 break; 939 case local_zone_transparent: 940 log_nametypeclass(0, "transparent zone", 941 z->name, 0, z->dclass); 942 break; 943 case local_zone_typetransparent: 944 log_nametypeclass(0, "typetransparent zone", 945 z->name, 0, z->dclass); 946 break; 947 case local_zone_static: 948 log_nametypeclass(0, "static zone", 949 z->name, 0, z->dclass); 950 break; 951 default: 952 log_nametypeclass(0, "badtyped zone", 953 z->name, 0, z->dclass); 954 break; 955 } 956 local_zone_out(z); 957 lock_rw_unlock(&z->lock); 958 } 959 lock_rw_unlock(&zones->lock); 960 } 961 962 /** encode answer consisting of 1 rrset */ 963 static int 964 local_encode(struct query_info* qinfo, struct edns_data* edns, 965 sldns_buffer* buf, struct regional* temp, 966 struct ub_packed_rrset_key* rrset, int ansec, int rcode) 967 { 968 struct reply_info rep; 969 uint16_t udpsize; 970 /* make answer with time=0 for fixed TTL values */ 971 memset(&rep, 0, sizeof(rep)); 972 rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode); 973 rep.qdcount = 1; 974 if(ansec) 975 rep.an_numrrsets = 1; 976 else rep.ns_numrrsets = 1; 977 rep.rrset_count = 1; 978 rep.rrsets = &rrset; 979 udpsize = edns->udp_size; 980 edns->edns_version = EDNS_ADVERTISED_VERSION; 981 edns->udp_size = EDNS_ADVERTISED_SIZE; 982 edns->ext_rcode = 0; 983 edns->bits &= EDNS_DO; 984 if(!reply_info_answer_encode(qinfo, &rep, 985 *(uint16_t*)sldns_buffer_begin(buf), 986 sldns_buffer_read_u16_at(buf, 2), 987 buf, 0, 0, temp, udpsize, edns, 988 (int)(edns->bits&EDNS_DO), 0)) 989 error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo, 990 *(uint16_t*)sldns_buffer_begin(buf), 991 sldns_buffer_read_u16_at(buf, 2), edns); 992 return 1; 993 } 994 995 /** answer local data match */ 996 static int 997 local_data_answer(struct local_zone* z, struct query_info* qinfo, 998 struct edns_data* edns, sldns_buffer* buf, struct regional* temp, 999 int labs, struct local_data** ldp) 1000 { 1001 struct local_data key; 1002 struct local_data* ld; 1003 struct local_rrset* lr; 1004 key.node.key = &key; 1005 key.name = qinfo->qname; 1006 key.namelen = qinfo->qname_len; 1007 key.namelabs = labs; 1008 if(z->type == local_zone_redirect) { 1009 key.name = z->name; 1010 key.namelen = z->namelen; 1011 key.namelabs = z->namelabs; 1012 } 1013 ld = (struct local_data*)rbtree_search(&z->data, &key.node); 1014 *ldp = ld; 1015 if(!ld) { 1016 return 0; 1017 } 1018 lr = local_data_find_type(ld, qinfo->qtype); 1019 if(!lr) 1020 return 0; 1021 if(z->type == local_zone_redirect) { 1022 /* convert rrset name to query name; like a wildcard */ 1023 struct ub_packed_rrset_key r = *lr->rrset; 1024 r.rk.dname = qinfo->qname; 1025 r.rk.dname_len = qinfo->qname_len; 1026 return local_encode(qinfo, edns, buf, temp, &r, 1, 1027 LDNS_RCODE_NOERROR); 1028 } 1029 return local_encode(qinfo, edns, buf, temp, lr->rrset, 1, 1030 LDNS_RCODE_NOERROR); 1031 } 1032 1033 /** 1034 * answer in case where no exact match is found 1035 * @param z: zone for query 1036 * @param qinfo: query 1037 * @param edns: edns from query 1038 * @param buf: buffer for answer. 1039 * @param temp: temp region for encoding 1040 * @param ld: local data, if NULL, no such name exists in localdata. 1041 * @return 1 if a reply is to be sent, 0 if not. 1042 */ 1043 static int 1044 lz_zone_answer(struct local_zone* z, struct query_info* qinfo, 1045 struct edns_data* edns, sldns_buffer* buf, struct regional* temp, 1046 struct local_data* ld) 1047 { 1048 if(z->type == local_zone_deny) { 1049 /** no reply at all, signal caller by clearing buffer. */ 1050 sldns_buffer_clear(buf); 1051 sldns_buffer_flip(buf); 1052 return 1; 1053 } else if(z->type == local_zone_refuse) { 1054 error_encode(buf, (LDNS_RCODE_REFUSED|BIT_AA), qinfo, 1055 *(uint16_t*)sldns_buffer_begin(buf), 1056 sldns_buffer_read_u16_at(buf, 2), edns); 1057 return 1; 1058 } else if(z->type == local_zone_static || 1059 z->type == local_zone_redirect) { 1060 /* for static, reply nodata or nxdomain 1061 * for redirect, reply nodata */ 1062 /* no additional section processing, 1063 * cname, dname or wildcard processing, 1064 * or using closest match for NSEC. 1065 * or using closest match for returning delegation downwards 1066 */ 1067 int rcode = ld?LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN; 1068 if(z->soa) 1069 return local_encode(qinfo, edns, buf, temp, 1070 z->soa, 0, rcode); 1071 error_encode(buf, (rcode|BIT_AA), qinfo, 1072 *(uint16_t*)sldns_buffer_begin(buf), 1073 sldns_buffer_read_u16_at(buf, 2), edns); 1074 return 1; 1075 } else if(z->type == local_zone_typetransparent) { 1076 /* no NODATA or NXDOMAINS for this zone type */ 1077 return 0; 1078 } 1079 /* else z->type == local_zone_transparent */ 1080 1081 /* if the zone is transparent and the name exists, but the type 1082 * does not, then we should make this noerror/nodata */ 1083 if(ld && ld->rrsets) { 1084 int rcode = LDNS_RCODE_NOERROR; 1085 if(z->soa) 1086 return local_encode(qinfo, edns, buf, temp, 1087 z->soa, 0, rcode); 1088 error_encode(buf, (rcode|BIT_AA), qinfo, 1089 *(uint16_t*)sldns_buffer_begin(buf), 1090 sldns_buffer_read_u16_at(buf, 2), edns); 1091 return 1; 1092 } 1093 1094 /* stop here, and resolve further on */ 1095 return 0; 1096 } 1097 1098 int 1099 local_zones_answer(struct local_zones* zones, struct query_info* qinfo, 1100 struct edns_data* edns, sldns_buffer* buf, struct regional* temp) 1101 { 1102 /* see if query is covered by a zone, 1103 * if so: - try to match (exact) local data 1104 * - look at zone type for negative response. */ 1105 int labs = dname_count_labels(qinfo->qname); 1106 struct local_data* ld; 1107 struct local_zone* z; 1108 int r; 1109 lock_rw_rdlock(&zones->lock); 1110 z = local_zones_lookup(zones, qinfo->qname, 1111 qinfo->qname_len, labs, qinfo->qclass); 1112 if(!z) { 1113 lock_rw_unlock(&zones->lock); 1114 return 0; 1115 } 1116 lock_rw_rdlock(&z->lock); 1117 lock_rw_unlock(&zones->lock); 1118 1119 if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) { 1120 lock_rw_unlock(&z->lock); 1121 return 1; 1122 } 1123 r = lz_zone_answer(z, qinfo, edns, buf, temp, ld); 1124 lock_rw_unlock(&z->lock); 1125 return r; 1126 } 1127 1128 const char* local_zone_type2str(enum localzone_type t) 1129 { 1130 switch(t) { 1131 case local_zone_deny: return "deny"; 1132 case local_zone_refuse: return "refuse"; 1133 case local_zone_redirect: return "redirect"; 1134 case local_zone_transparent: return "transparent"; 1135 case local_zone_typetransparent: return "typetransparent"; 1136 case local_zone_static: return "static"; 1137 case local_zone_nodefault: return "nodefault"; 1138 } 1139 return "badtyped"; 1140 } 1141 1142 int local_zone_str2type(const char* type, enum localzone_type* t) 1143 { 1144 if(strcmp(type, "deny") == 0) 1145 *t = local_zone_deny; 1146 else if(strcmp(type, "refuse") == 0) 1147 *t = local_zone_refuse; 1148 else if(strcmp(type, "static") == 0) 1149 *t = local_zone_static; 1150 else if(strcmp(type, "transparent") == 0) 1151 *t = local_zone_transparent; 1152 else if(strcmp(type, "typetransparent") == 0) 1153 *t = local_zone_typetransparent; 1154 else if(strcmp(type, "redirect") == 0) 1155 *t = local_zone_redirect; 1156 else return 0; 1157 return 1; 1158 } 1159 1160 /** iterate over the kiddies of the given name and set their parent ptr */ 1161 static void 1162 set_kiddo_parents(struct local_zone* z, struct local_zone* match, 1163 struct local_zone* newp) 1164 { 1165 /* both zones and z are locked already */ 1166 /* in the sorted rbtree, the kiddies of z are located after z */ 1167 /* z must be present in the tree */ 1168 struct local_zone* p = z; 1169 p = (struct local_zone*)rbtree_next(&p->node); 1170 while(p!=(struct local_zone*)RBTREE_NULL && 1171 p->dclass == z->dclass && dname_strict_subdomain(p->name, 1172 p->namelabs, z->name, z->namelabs)) { 1173 /* update parent ptr */ 1174 /* only when matches with existing parent pointer, so that 1175 * deeper child structures are not touched, i.e. 1176 * update of x, and a.x, b.x, f.b.x, g.b.x, c.x, y 1177 * gets to update a.x, b.x and c.x */ 1178 lock_rw_wrlock(&p->lock); 1179 if(p->parent == match) 1180 p->parent = newp; 1181 lock_rw_unlock(&p->lock); 1182 p = (struct local_zone*)rbtree_next(&p->node); 1183 } 1184 } 1185 1186 struct local_zone* local_zones_add_zone(struct local_zones* zones, 1187 uint8_t* name, size_t len, int labs, uint16_t dclass, 1188 enum localzone_type tp) 1189 { 1190 /* create */ 1191 struct local_zone* z = local_zone_create(name, len, labs, tp, dclass); 1192 if(!z) return NULL; 1193 lock_rw_wrlock(&z->lock); 1194 1195 /* find the closest parent */ 1196 z->parent = local_zones_find(zones, name, len, labs, dclass); 1197 1198 /* insert into the tree */ 1199 if(!rbtree_insert(&zones->ztree, &z->node)) { 1200 /* duplicate entry! */ 1201 lock_rw_unlock(&z->lock); 1202 local_zone_delete(z); 1203 log_err("internal: duplicate entry in local_zones_add_zone"); 1204 return NULL; 1205 } 1206 1207 /* set parent pointers right */ 1208 set_kiddo_parents(z, z->parent, z); 1209 1210 lock_rw_unlock(&z->lock); 1211 return z; 1212 } 1213 1214 void local_zones_del_zone(struct local_zones* zones, struct local_zone* z) 1215 { 1216 /* fix up parents in tree */ 1217 lock_rw_wrlock(&z->lock); 1218 set_kiddo_parents(z, z, z->parent); 1219 1220 /* remove from tree */ 1221 (void)rbtree_delete(&zones->ztree, z); 1222 1223 /* delete the zone */ 1224 lock_rw_unlock(&z->lock); 1225 local_zone_delete(z); 1226 } 1227 1228 int 1229 local_zones_add_RR(struct local_zones* zones, const char* rr) 1230 { 1231 uint8_t* rr_name; 1232 uint16_t rr_class; 1233 size_t len; 1234 int labs; 1235 struct local_zone* z; 1236 int r; 1237 if(!get_rr_nameclass(rr, &rr_name, &rr_class)) { 1238 return 0; 1239 } 1240 labs = dname_count_size_labels(rr_name, &len); 1241 /* could first try readlock then get writelock if zone does not exist, 1242 * but we do not add enough RRs (from multiple threads) to optimize */ 1243 lock_rw_wrlock(&zones->lock); 1244 z = local_zones_lookup(zones, rr_name, len, labs, rr_class); 1245 if(!z) { 1246 z = local_zones_add_zone(zones, rr_name, len, labs, rr_class, 1247 local_zone_transparent); 1248 if(!z) { 1249 lock_rw_unlock(&zones->lock); 1250 return 0; 1251 } 1252 } else { 1253 free(rr_name); 1254 } 1255 lock_rw_wrlock(&z->lock); 1256 lock_rw_unlock(&zones->lock); 1257 r = lz_enter_rr_into_zone(z, rr); 1258 lock_rw_unlock(&z->lock); 1259 return r; 1260 } 1261 1262 /** returns true if the node is terminal so no deeper domain names exist */ 1263 static int 1264 is_terminal(struct local_data* d) 1265 { 1266 /* for empty nonterminals, the deeper domain names are sorted 1267 * right after them, so simply check the next name in the tree 1268 */ 1269 struct local_data* n = (struct local_data*)rbtree_next(&d->node); 1270 if(n == (struct local_data*)RBTREE_NULL) 1271 return 1; /* last in tree, no deeper node */ 1272 if(dname_strict_subdomain(n->name, n->namelabs, d->name, d->namelabs)) 1273 return 0; /* there is a deeper node */ 1274 return 1; 1275 } 1276 1277 /** delete empty terminals from tree when final data is deleted */ 1278 static void 1279 del_empty_term(struct local_zone* z, struct local_data* d, 1280 uint8_t* name, size_t len, int labs) 1281 { 1282 while(d && d->rrsets == NULL && is_terminal(d)) { 1283 /* is this empty nonterminal? delete */ 1284 /* note, no memory recycling in zone region */ 1285 (void)rbtree_delete(&z->data, d); 1286 1287 /* go up and to the next label */ 1288 if(dname_is_root(name)) 1289 return; 1290 dname_remove_label(&name, &len); 1291 labs--; 1292 d = lz_find_node(z, name, len, labs); 1293 } 1294 } 1295 1296 void local_zones_del_data(struct local_zones* zones, 1297 uint8_t* name, size_t len, int labs, uint16_t dclass) 1298 { 1299 /* find zone */ 1300 struct local_zone* z; 1301 struct local_data* d; 1302 lock_rw_rdlock(&zones->lock); 1303 z = local_zones_lookup(zones, name, len, labs, dclass); 1304 if(!z) { 1305 /* no such zone, we're done */ 1306 lock_rw_unlock(&zones->lock); 1307 return; 1308 } 1309 lock_rw_wrlock(&z->lock); 1310 lock_rw_unlock(&zones->lock); 1311 1312 /* find the domain */ 1313 d = lz_find_node(z, name, len, labs); 1314 if(d) { 1315 /* no memory recycling for zone deletions ... */ 1316 d->rrsets = NULL; 1317 /* did we delete the soa record ? */ 1318 if(query_dname_compare(d->name, z->name) == 0) 1319 z->soa = NULL; 1320 1321 /* cleanup the empty nonterminals for this name */ 1322 del_empty_term(z, d, name, len, labs); 1323 } 1324 1325 lock_rw_unlock(&z->lock); 1326 } 1327