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