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