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 */ 599 600 /* block localhost level zones, first, 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 659 /* block AS112 zones, unless asked not to */ 660 if(!cfg->unblock_lan_zones) { 661 for(zstr = as112_zones; *zstr; zstr++) { 662 if(!add_as112_default(zones, cfg, *zstr)) { 663 log_err("out of memory adding default zone"); 664 return 0; 665 } 666 } 667 } 668 return 1; 669 } 670 671 /** setup parent pointers, so that a lookup can be done for closest match */ 672 static void 673 init_parents(struct local_zones* zones) 674 { 675 struct local_zone* node, *prev = NULL, *p; 676 int m; 677 lock_rw_wrlock(&zones->lock); 678 RBTREE_FOR(node, struct local_zone*, &zones->ztree) { 679 lock_rw_wrlock(&node->lock); 680 node->parent = NULL; 681 if(!prev || prev->dclass != node->dclass) { 682 prev = node; 683 lock_rw_unlock(&node->lock); 684 continue; 685 } 686 (void)dname_lab_cmp(prev->name, prev->namelabs, node->name, 687 node->namelabs, &m); /* we know prev is smaller */ 688 /* sort order like: . com. bla.com. zwb.com. net. */ 689 /* find the previous, or parent-parent-parent */ 690 for(p = prev; p; p = p->parent) 691 /* looking for name with few labels, a parent */ 692 if(p->namelabs <= m) { 693 /* ==: since prev matched m, this is closest*/ 694 /* <: prev matches more, but is not a parent, 695 * this one is a (grand)parent */ 696 node->parent = p; 697 break; 698 } 699 prev = node; 700 lock_rw_unlock(&node->lock); 701 } 702 lock_rw_unlock(&zones->lock); 703 } 704 705 /** enter implicit transparent zone for local-data: without local-zone: */ 706 static int 707 lz_setup_implicit(struct local_zones* zones, struct config_file* cfg) 708 { 709 /* walk over all items that have no parent zone and find 710 * the name that covers them all (could be the root) and 711 * add that as a transparent zone */ 712 struct config_strlist* p; 713 int have_name = 0; 714 int have_other_classes = 0; 715 uint16_t dclass = 0; 716 uint8_t* nm = 0; 717 size_t nmlen = 0; 718 int nmlabs = 0; 719 int match = 0; /* number of labels match count */ 720 721 init_parents(zones); /* to enable local_zones_lookup() */ 722 for(p = cfg->local_data; p; p = p->next) { 723 uint8_t* rr_name; 724 uint16_t rr_class; 725 size_t len; 726 int labs; 727 if(!get_rr_nameclass(p->str, &rr_name, &rr_class)) { 728 log_err("Bad local-data RR %s", p->str); 729 return 0; 730 } 731 labs = dname_count_size_labels(rr_name, &len); 732 lock_rw_rdlock(&zones->lock); 733 if(!local_zones_lookup(zones, rr_name, len, labs, rr_class)) { 734 if(!have_name) { 735 dclass = rr_class; 736 nm = rr_name; 737 nmlen = len; 738 nmlabs = labs; 739 match = labs; 740 have_name = 1; 741 } else { 742 int m; 743 if(rr_class != dclass) { 744 /* process other classes later */ 745 free(rr_name); 746 have_other_classes = 1; 747 lock_rw_unlock(&zones->lock); 748 continue; 749 } 750 /* find smallest shared topdomain */ 751 (void)dname_lab_cmp(nm, nmlabs, 752 rr_name, labs, &m); 753 free(rr_name); 754 if(m < match) 755 match = m; 756 } 757 } else free(rr_name); 758 lock_rw_unlock(&zones->lock); 759 } 760 if(have_name) { 761 uint8_t* n2; 762 struct local_zone* z; 763 /* allocate zone of smallest shared topdomain to contain em */ 764 n2 = nm; 765 dname_remove_labels(&n2, &nmlen, nmlabs - match); 766 n2 = memdup(n2, nmlen); 767 free(nm); 768 if(!n2) { 769 log_err("out of memory"); 770 return 0; 771 } 772 log_nametypeclass(VERB_ALGO, "implicit transparent local-zone", 773 n2, 0, dclass); 774 if(!(z=lz_enter_zone_dname(zones, n2, nmlen, match, 775 local_zone_transparent, dclass))) { 776 return 0; 777 } 778 lock_rw_unlock(&z->lock); 779 } 780 if(have_other_classes) { 781 /* restart to setup other class */ 782 return lz_setup_implicit(zones, cfg); 783 } 784 return 1; 785 } 786 787 /** enter auth data */ 788 static int 789 lz_enter_data(struct local_zones* zones, struct config_file* cfg) 790 { 791 struct config_strlist* p; 792 for(p = cfg->local_data; p; p = p->next) { 793 if(!lz_enter_rr_str(zones, p->str)) 794 return 0; 795 } 796 return 1; 797 } 798 799 /** free memory from config */ 800 static void 801 lz_freeup_cfg(struct config_file* cfg) 802 { 803 config_deldblstrlist(cfg->local_zones); 804 cfg->local_zones = NULL; 805 config_delstrlist(cfg->local_zones_nodefault); 806 cfg->local_zones_nodefault = NULL; 807 config_delstrlist(cfg->local_data); 808 cfg->local_data = NULL; 809 } 810 811 int 812 local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg) 813 { 814 /* create zones from zone statements. */ 815 if(!lz_enter_zones(zones, cfg)) { 816 return 0; 817 } 818 /* apply default zones+content (unless disabled, or overridden) */ 819 if(!lz_enter_defaults(zones, cfg)) { 820 return 0; 821 } 822 /* create implicit transparent zone from data. */ 823 if(!lz_setup_implicit(zones, cfg)) { 824 return 0; 825 } 826 827 /* setup parent ptrs for lookup during data entry */ 828 init_parents(zones); 829 /* insert local data */ 830 if(!lz_enter_data(zones, cfg)) { 831 return 0; 832 } 833 /* freeup memory from cfg struct. */ 834 lz_freeup_cfg(cfg); 835 return 1; 836 } 837 838 struct local_zone* 839 local_zones_lookup(struct local_zones* zones, 840 uint8_t* name, size_t len, int labs, uint16_t dclass) 841 { 842 rbnode_t* res = NULL; 843 struct local_zone *result; 844 struct local_zone key; 845 key.node.key = &key; 846 key.dclass = dclass; 847 key.name = name; 848 key.namelen = len; 849 key.namelabs = labs; 850 if(rbtree_find_less_equal(&zones->ztree, &key, &res)) { 851 /* exact */ 852 return (struct local_zone*)res; 853 } else { 854 /* smaller element (or no element) */ 855 int m; 856 result = (struct local_zone*)res; 857 if(!result || result->dclass != dclass) 858 return NULL; 859 /* count number of labels matched */ 860 (void)dname_lab_cmp(result->name, result->namelabs, key.name, 861 key.namelabs, &m); 862 while(result) { /* go up until qname is subdomain of zone */ 863 if(result->namelabs <= m) 864 break; 865 result = result->parent; 866 } 867 return result; 868 } 869 } 870 871 struct local_zone* 872 local_zones_find(struct local_zones* zones, 873 uint8_t* name, size_t len, int labs, uint16_t dclass) 874 { 875 struct local_zone key; 876 key.node.key = &key; 877 key.dclass = dclass; 878 key.name = name; 879 key.namelen = len; 880 key.namelabs = labs; 881 /* exact */ 882 return (struct local_zone*)rbtree_search(&zones->ztree, &key); 883 } 884 885 /** print all RRsets in local zone */ 886 static void 887 local_zone_out(struct local_zone* z) 888 { 889 struct local_data* d; 890 struct local_rrset* p; 891 RBTREE_FOR(d, struct local_data*, &z->data) { 892 for(p = d->rrsets; p; p = p->next) { 893 log_nametypeclass(0, "rrset", d->name, 894 ntohs(p->rrset->rk.type), 895 ntohs(p->rrset->rk.rrset_class)); 896 } 897 } 898 } 899 900 void local_zones_print(struct local_zones* zones) 901 { 902 struct local_zone* z; 903 lock_rw_rdlock(&zones->lock); 904 log_info("number of auth zones %u", (unsigned)zones->ztree.count); 905 RBTREE_FOR(z, struct local_zone*, &zones->ztree) { 906 lock_rw_rdlock(&z->lock); 907 switch(z->type) { 908 case local_zone_deny: 909 log_nametypeclass(0, "deny zone", 910 z->name, 0, z->dclass); 911 break; 912 case local_zone_refuse: 913 log_nametypeclass(0, "refuse zone", 914 z->name, 0, z->dclass); 915 break; 916 case local_zone_redirect: 917 log_nametypeclass(0, "redirect zone", 918 z->name, 0, z->dclass); 919 break; 920 case local_zone_transparent: 921 log_nametypeclass(0, "transparent zone", 922 z->name, 0, z->dclass); 923 break; 924 case local_zone_typetransparent: 925 log_nametypeclass(0, "typetransparent zone", 926 z->name, 0, z->dclass); 927 break; 928 case local_zone_static: 929 log_nametypeclass(0, "static zone", 930 z->name, 0, z->dclass); 931 break; 932 case local_zone_inform: 933 log_nametypeclass(0, "inform zone", 934 z->name, 0, z->dclass); 935 break; 936 case local_zone_inform_deny: 937 log_nametypeclass(0, "inform_deny zone", 938 z->name, 0, z->dclass); 939 break; 940 default: 941 log_nametypeclass(0, "badtyped zone", 942 z->name, 0, z->dclass); 943 break; 944 } 945 local_zone_out(z); 946 lock_rw_unlock(&z->lock); 947 } 948 lock_rw_unlock(&zones->lock); 949 } 950 951 /** encode answer consisting of 1 rrset */ 952 static int 953 local_encode(struct query_info* qinfo, struct edns_data* edns, 954 sldns_buffer* buf, struct regional* temp, 955 struct ub_packed_rrset_key* rrset, int ansec, int rcode) 956 { 957 struct reply_info rep; 958 uint16_t udpsize; 959 /* make answer with time=0 for fixed TTL values */ 960 memset(&rep, 0, sizeof(rep)); 961 rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode); 962 rep.qdcount = 1; 963 if(ansec) 964 rep.an_numrrsets = 1; 965 else rep.ns_numrrsets = 1; 966 rep.rrset_count = 1; 967 rep.rrsets = &rrset; 968 udpsize = edns->udp_size; 969 edns->edns_version = EDNS_ADVERTISED_VERSION; 970 edns->udp_size = EDNS_ADVERTISED_SIZE; 971 edns->ext_rcode = 0; 972 edns->bits &= EDNS_DO; 973 if(!reply_info_answer_encode(qinfo, &rep, 974 *(uint16_t*)sldns_buffer_begin(buf), 975 sldns_buffer_read_u16_at(buf, 2), 976 buf, 0, 0, temp, udpsize, edns, 977 (int)(edns->bits&EDNS_DO), 0)) 978 error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo, 979 *(uint16_t*)sldns_buffer_begin(buf), 980 sldns_buffer_read_u16_at(buf, 2), edns); 981 return 1; 982 } 983 984 /** answer local data match */ 985 static int 986 local_data_answer(struct local_zone* z, struct query_info* qinfo, 987 struct edns_data* edns, sldns_buffer* buf, struct regional* temp, 988 int labs, struct local_data** ldp) 989 { 990 struct local_data key; 991 struct local_data* ld; 992 struct local_rrset* lr; 993 key.node.key = &key; 994 key.name = qinfo->qname; 995 key.namelen = qinfo->qname_len; 996 key.namelabs = labs; 997 if(z->type == local_zone_redirect) { 998 key.name = z->name; 999 key.namelen = z->namelen; 1000 key.namelabs = z->namelabs; 1001 } 1002 ld = (struct local_data*)rbtree_search(&z->data, &key.node); 1003 *ldp = ld; 1004 if(!ld) { 1005 return 0; 1006 } 1007 lr = local_data_find_type(ld, qinfo->qtype); 1008 if(!lr) 1009 return 0; 1010 if(z->type == local_zone_redirect) { 1011 /* convert rrset name to query name; like a wildcard */ 1012 struct ub_packed_rrset_key r = *lr->rrset; 1013 r.rk.dname = qinfo->qname; 1014 r.rk.dname_len = qinfo->qname_len; 1015 return local_encode(qinfo, edns, buf, temp, &r, 1, 1016 LDNS_RCODE_NOERROR); 1017 } 1018 return local_encode(qinfo, edns, buf, temp, lr->rrset, 1, 1019 LDNS_RCODE_NOERROR); 1020 } 1021 1022 /** 1023 * answer in case where no exact match is found 1024 * @param z: zone for query 1025 * @param qinfo: query 1026 * @param edns: edns from query 1027 * @param buf: buffer for answer. 1028 * @param temp: temp region for encoding 1029 * @param ld: local data, if NULL, no such name exists in localdata. 1030 * @return 1 if a reply is to be sent, 0 if not. 1031 */ 1032 static int 1033 lz_zone_answer(struct local_zone* z, struct query_info* qinfo, 1034 struct edns_data* edns, sldns_buffer* buf, struct regional* temp, 1035 struct local_data* ld) 1036 { 1037 if(z->type == local_zone_deny || z->type == local_zone_inform_deny) { 1038 /** no reply at all, signal caller by clearing buffer. */ 1039 sldns_buffer_clear(buf); 1040 sldns_buffer_flip(buf); 1041 return 1; 1042 } else if(z->type == local_zone_refuse) { 1043 error_encode(buf, (LDNS_RCODE_REFUSED|BIT_AA), qinfo, 1044 *(uint16_t*)sldns_buffer_begin(buf), 1045 sldns_buffer_read_u16_at(buf, 2), edns); 1046 return 1; 1047 } else if(z->type == local_zone_static || 1048 z->type == local_zone_redirect) { 1049 /* for static, reply nodata or nxdomain 1050 * for redirect, reply nodata */ 1051 /* no additional section processing, 1052 * cname, dname or wildcard processing, 1053 * or using closest match for NSEC. 1054 * or using closest match for returning delegation downwards 1055 */ 1056 int rcode = ld?LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN; 1057 if(z->soa) 1058 return local_encode(qinfo, edns, buf, temp, 1059 z->soa, 0, rcode); 1060 error_encode(buf, (rcode|BIT_AA), qinfo, 1061 *(uint16_t*)sldns_buffer_begin(buf), 1062 sldns_buffer_read_u16_at(buf, 2), edns); 1063 return 1; 1064 } else if(z->type == local_zone_typetransparent) { 1065 /* no NODATA or NXDOMAINS for this zone type */ 1066 return 0; 1067 } 1068 /* else z->type == local_zone_transparent */ 1069 1070 /* if the zone is transparent and the name exists, but the type 1071 * does not, then we should make this noerror/nodata */ 1072 if(ld && ld->rrsets) { 1073 int rcode = LDNS_RCODE_NOERROR; 1074 if(z->soa) 1075 return local_encode(qinfo, edns, buf, temp, 1076 z->soa, 0, rcode); 1077 error_encode(buf, (rcode|BIT_AA), qinfo, 1078 *(uint16_t*)sldns_buffer_begin(buf), 1079 sldns_buffer_read_u16_at(buf, 2), edns); 1080 return 1; 1081 } 1082 1083 /* stop here, and resolve further on */ 1084 return 0; 1085 } 1086 1087 /** print log information for an inform zone query */ 1088 static void 1089 lz_inform_print(struct local_zone* z, struct query_info* qinfo, 1090 struct comm_reply* repinfo) 1091 { 1092 char ip[128], txt[512]; 1093 char zname[LDNS_MAX_DOMAINLEN+1]; 1094 uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port); 1095 dname_str(z->name, zname); 1096 addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); 1097 snprintf(txt, sizeof(txt), "%s inform %s@%u", zname, ip, 1098 (unsigned)port); 1099 log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass); 1100 } 1101 1102 int 1103 local_zones_answer(struct local_zones* zones, struct query_info* qinfo, 1104 struct edns_data* edns, sldns_buffer* buf, struct regional* temp, 1105 struct comm_reply* repinfo) 1106 { 1107 /* see if query is covered by a zone, 1108 * if so: - try to match (exact) local data 1109 * - look at zone type for negative response. */ 1110 int labs = dname_count_labels(qinfo->qname); 1111 struct local_data* ld; 1112 struct local_zone* z; 1113 int r; 1114 lock_rw_rdlock(&zones->lock); 1115 z = local_zones_lookup(zones, qinfo->qname, 1116 qinfo->qname_len, labs, qinfo->qclass); 1117 if(!z) { 1118 lock_rw_unlock(&zones->lock); 1119 return 0; 1120 } 1121 lock_rw_rdlock(&z->lock); 1122 lock_rw_unlock(&zones->lock); 1123 1124 if((z->type == local_zone_inform || z->type == local_zone_inform_deny) 1125 && repinfo) 1126 lz_inform_print(z, qinfo, repinfo); 1127 1128 if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) { 1129 lock_rw_unlock(&z->lock); 1130 return 1; 1131 } 1132 r = lz_zone_answer(z, qinfo, edns, buf, temp, ld); 1133 lock_rw_unlock(&z->lock); 1134 return r; 1135 } 1136 1137 const char* local_zone_type2str(enum localzone_type t) 1138 { 1139 switch(t) { 1140 case local_zone_deny: return "deny"; 1141 case local_zone_refuse: return "refuse"; 1142 case local_zone_redirect: return "redirect"; 1143 case local_zone_transparent: return "transparent"; 1144 case local_zone_typetransparent: return "typetransparent"; 1145 case local_zone_static: return "static"; 1146 case local_zone_nodefault: return "nodefault"; 1147 case local_zone_inform: return "inform"; 1148 case local_zone_inform_deny: return "inform_deny"; 1149 } 1150 return "badtyped"; 1151 } 1152 1153 int local_zone_str2type(const char* type, enum localzone_type* t) 1154 { 1155 if(strcmp(type, "deny") == 0) 1156 *t = local_zone_deny; 1157 else if(strcmp(type, "refuse") == 0) 1158 *t = local_zone_refuse; 1159 else if(strcmp(type, "static") == 0) 1160 *t = local_zone_static; 1161 else if(strcmp(type, "transparent") == 0) 1162 *t = local_zone_transparent; 1163 else if(strcmp(type, "typetransparent") == 0) 1164 *t = local_zone_typetransparent; 1165 else if(strcmp(type, "redirect") == 0) 1166 *t = local_zone_redirect; 1167 else if(strcmp(type, "inform") == 0) 1168 *t = local_zone_inform; 1169 else if(strcmp(type, "inform_deny") == 0) 1170 *t = local_zone_inform_deny; 1171 else return 0; 1172 return 1; 1173 } 1174 1175 /** iterate over the kiddies of the given name and set their parent ptr */ 1176 static void 1177 set_kiddo_parents(struct local_zone* z, struct local_zone* match, 1178 struct local_zone* newp) 1179 { 1180 /* both zones and z are locked already */ 1181 /* in the sorted rbtree, the kiddies of z are located after z */ 1182 /* z must be present in the tree */ 1183 struct local_zone* p = z; 1184 p = (struct local_zone*)rbtree_next(&p->node); 1185 while(p!=(struct local_zone*)RBTREE_NULL && 1186 p->dclass == z->dclass && dname_strict_subdomain(p->name, 1187 p->namelabs, z->name, z->namelabs)) { 1188 /* update parent ptr */ 1189 /* only when matches with existing parent pointer, so that 1190 * deeper child structures are not touched, i.e. 1191 * update of x, and a.x, b.x, f.b.x, g.b.x, c.x, y 1192 * gets to update a.x, b.x and c.x */ 1193 lock_rw_wrlock(&p->lock); 1194 if(p->parent == match) 1195 p->parent = newp; 1196 lock_rw_unlock(&p->lock); 1197 p = (struct local_zone*)rbtree_next(&p->node); 1198 } 1199 } 1200 1201 struct local_zone* local_zones_add_zone(struct local_zones* zones, 1202 uint8_t* name, size_t len, int labs, uint16_t dclass, 1203 enum localzone_type tp) 1204 { 1205 /* create */ 1206 struct local_zone* z = local_zone_create(name, len, labs, tp, dclass); 1207 if(!z) return NULL; 1208 lock_rw_wrlock(&z->lock); 1209 1210 /* find the closest parent */ 1211 z->parent = local_zones_find(zones, name, len, labs, dclass); 1212 1213 /* insert into the tree */ 1214 if(!rbtree_insert(&zones->ztree, &z->node)) { 1215 /* duplicate entry! */ 1216 lock_rw_unlock(&z->lock); 1217 local_zone_delete(z); 1218 log_err("internal: duplicate entry in local_zones_add_zone"); 1219 return NULL; 1220 } 1221 1222 /* set parent pointers right */ 1223 set_kiddo_parents(z, z->parent, z); 1224 1225 lock_rw_unlock(&z->lock); 1226 return z; 1227 } 1228 1229 void local_zones_del_zone(struct local_zones* zones, struct local_zone* z) 1230 { 1231 /* fix up parents in tree */ 1232 lock_rw_wrlock(&z->lock); 1233 set_kiddo_parents(z, z, z->parent); 1234 1235 /* remove from tree */ 1236 (void)rbtree_delete(&zones->ztree, z); 1237 1238 /* delete the zone */ 1239 lock_rw_unlock(&z->lock); 1240 local_zone_delete(z); 1241 } 1242 1243 int 1244 local_zones_add_RR(struct local_zones* zones, const char* rr) 1245 { 1246 uint8_t* rr_name; 1247 uint16_t rr_class; 1248 size_t len; 1249 int labs; 1250 struct local_zone* z; 1251 int r; 1252 if(!get_rr_nameclass(rr, &rr_name, &rr_class)) { 1253 return 0; 1254 } 1255 labs = dname_count_size_labels(rr_name, &len); 1256 /* could first try readlock then get writelock if zone does not exist, 1257 * but we do not add enough RRs (from multiple threads) to optimize */ 1258 lock_rw_wrlock(&zones->lock); 1259 z = local_zones_lookup(zones, rr_name, len, labs, rr_class); 1260 if(!z) { 1261 z = local_zones_add_zone(zones, rr_name, len, labs, rr_class, 1262 local_zone_transparent); 1263 if(!z) { 1264 lock_rw_unlock(&zones->lock); 1265 return 0; 1266 } 1267 } else { 1268 free(rr_name); 1269 } 1270 lock_rw_wrlock(&z->lock); 1271 lock_rw_unlock(&zones->lock); 1272 r = lz_enter_rr_into_zone(z, rr); 1273 lock_rw_unlock(&z->lock); 1274 return r; 1275 } 1276 1277 /** returns true if the node is terminal so no deeper domain names exist */ 1278 static int 1279 is_terminal(struct local_data* d) 1280 { 1281 /* for empty nonterminals, the deeper domain names are sorted 1282 * right after them, so simply check the next name in the tree 1283 */ 1284 struct local_data* n = (struct local_data*)rbtree_next(&d->node); 1285 if(n == (struct local_data*)RBTREE_NULL) 1286 return 1; /* last in tree, no deeper node */ 1287 if(dname_strict_subdomain(n->name, n->namelabs, d->name, d->namelabs)) 1288 return 0; /* there is a deeper node */ 1289 return 1; 1290 } 1291 1292 /** delete empty terminals from tree when final data is deleted */ 1293 static void 1294 del_empty_term(struct local_zone* z, struct local_data* d, 1295 uint8_t* name, size_t len, int labs) 1296 { 1297 while(d && d->rrsets == NULL && is_terminal(d)) { 1298 /* is this empty nonterminal? delete */ 1299 /* note, no memory recycling in zone region */ 1300 (void)rbtree_delete(&z->data, d); 1301 1302 /* go up and to the next label */ 1303 if(dname_is_root(name)) 1304 return; 1305 dname_remove_label(&name, &len); 1306 labs--; 1307 d = lz_find_node(z, name, len, labs); 1308 } 1309 } 1310 1311 void local_zones_del_data(struct local_zones* zones, 1312 uint8_t* name, size_t len, int labs, uint16_t dclass) 1313 { 1314 /* find zone */ 1315 struct local_zone* z; 1316 struct local_data* d; 1317 lock_rw_rdlock(&zones->lock); 1318 z = local_zones_lookup(zones, name, len, labs, dclass); 1319 if(!z) { 1320 /* no such zone, we're done */ 1321 lock_rw_unlock(&zones->lock); 1322 return; 1323 } 1324 lock_rw_wrlock(&z->lock); 1325 lock_rw_unlock(&zones->lock); 1326 1327 /* find the domain */ 1328 d = lz_find_node(z, name, len, labs); 1329 if(d) { 1330 /* no memory recycling for zone deletions ... */ 1331 d->rrsets = NULL; 1332 /* did we delete the soa record ? */ 1333 if(query_dname_compare(d->name, z->name) == 0) 1334 z->soa = NULL; 1335 1336 /* cleanup the empty nonterminals for this name */ 1337 del_empty_term(z, d, name, len, labs); 1338 } 1339 1340 lock_rw_unlock(&z->lock); 1341 } 1342