1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * services/localzone.c - local zones authority service. 3b7579f77SDag-Erling Smørgrav * 4b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5b7579f77SDag-Erling Smørgrav * 6b7579f77SDag-Erling Smørgrav * This software is open source. 7b7579f77SDag-Erling Smørgrav * 8b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10b7579f77SDag-Erling Smørgrav * are met: 11b7579f77SDag-Erling Smørgrav * 12b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14b7579f77SDag-Erling Smørgrav * 15b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18b7579f77SDag-Erling Smørgrav * 19b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21b7579f77SDag-Erling Smørgrav * specific prior written permission. 22b7579f77SDag-Erling Smørgrav * 23b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2417d15b25SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2517d15b25SDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2617d15b25SDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2717d15b25SDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2817d15b25SDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2917d15b25SDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 3017d15b25SDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3117d15b25SDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3217d15b25SDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3317d15b25SDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34b7579f77SDag-Erling Smørgrav */ 35b7579f77SDag-Erling Smørgrav 36b7579f77SDag-Erling Smørgrav /** 37b7579f77SDag-Erling Smørgrav * \file 38b7579f77SDag-Erling Smørgrav * 39b7579f77SDag-Erling Smørgrav * This file contains functions to enable local zone authority service. 40b7579f77SDag-Erling Smørgrav */ 41b7579f77SDag-Erling Smørgrav #include "config.h" 42b7579f77SDag-Erling Smørgrav #include "services/localzone.h" 4309a3aaf3SDag-Erling Smørgrav #include "sldns/str2wire.h" 44b7579f77SDag-Erling Smørgrav #include "util/regional.h" 45b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 46b7579f77SDag-Erling Smørgrav #include "util/data/dname.h" 47b7579f77SDag-Erling Smørgrav #include "util/data/packed_rrset.h" 48b7579f77SDag-Erling Smørgrav #include "util/data/msgencode.h" 49b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 506480faa8SDag-Erling Smørgrav #include "util/netevent.h" 51b7579f77SDag-Erling Smørgrav #include "util/data/msgreply.h" 52b7579f77SDag-Erling Smørgrav #include "util/data/msgparse.h" 530de4f1bfSDag-Erling Smørgrav #include "util/as112.h" 54bc892140SDag-Erling Smørgrav 55bc892140SDag-Erling Smørgrav /* maximum RRs in an RRset, to cap possible 'endless' list RRs. 56bc892140SDag-Erling Smørgrav * with 16 bytes for an A record, a 64K packet has about 4000 max */ 57bc892140SDag-Erling Smørgrav #define LOCALZONE_RRSET_COUNT_MAX 4096 58b7579f77SDag-Erling Smørgrav 599cf5bc93SCy Schubert /** print all RRsets in local zone */ 609cf5bc93SCy Schubert static void 619cf5bc93SCy Schubert local_zone_out(struct local_zone* z) 629cf5bc93SCy Schubert { 639cf5bc93SCy Schubert struct local_data* d; 649cf5bc93SCy Schubert struct local_rrset* p; 659cf5bc93SCy Schubert RBTREE_FOR(d, struct local_data*, &z->data) { 669cf5bc93SCy Schubert for(p = d->rrsets; p; p = p->next) { 679cf5bc93SCy Schubert log_nametypeclass(NO_VERBOSE, "rrset", d->name, 689cf5bc93SCy Schubert ntohs(p->rrset->rk.type), 699cf5bc93SCy Schubert ntohs(p->rrset->rk.rrset_class)); 709cf5bc93SCy Schubert } 719cf5bc93SCy Schubert } 729cf5bc93SCy Schubert } 739cf5bc93SCy Schubert 749cf5bc93SCy Schubert static void 759cf5bc93SCy Schubert local_zone_print(struct local_zone* z) 769cf5bc93SCy Schubert { 779cf5bc93SCy Schubert char buf[64]; 789cf5bc93SCy Schubert lock_rw_rdlock(&z->lock); 799cf5bc93SCy Schubert snprintf(buf, sizeof(buf), "%s zone", 809cf5bc93SCy Schubert local_zone_type2str(z->type)); 819cf5bc93SCy Schubert log_nametypeclass(NO_VERBOSE, buf, z->name, 0, z->dclass); 829cf5bc93SCy Schubert local_zone_out(z); 839cf5bc93SCy Schubert lock_rw_unlock(&z->lock); 849cf5bc93SCy Schubert } 859cf5bc93SCy Schubert 869cf5bc93SCy Schubert void local_zones_print(struct local_zones* zones) 879cf5bc93SCy Schubert { 889cf5bc93SCy Schubert struct local_zone* z; 899cf5bc93SCy Schubert lock_rw_rdlock(&zones->lock); 909cf5bc93SCy Schubert log_info("number of auth zones %u", (unsigned)zones->ztree.count); 919cf5bc93SCy Schubert RBTREE_FOR(z, struct local_zone*, &zones->ztree) { 929cf5bc93SCy Schubert local_zone_print(z); 939cf5bc93SCy Schubert } 949cf5bc93SCy Schubert lock_rw_unlock(&zones->lock); 959cf5bc93SCy Schubert } 969cf5bc93SCy Schubert 97b7579f77SDag-Erling Smørgrav struct local_zones* 98b7579f77SDag-Erling Smørgrav local_zones_create(void) 99b7579f77SDag-Erling Smørgrav { 100b7579f77SDag-Erling Smørgrav struct local_zones* zones = (struct local_zones*)calloc(1, 101b7579f77SDag-Erling Smørgrav sizeof(*zones)); 102b7579f77SDag-Erling Smørgrav if(!zones) 103b7579f77SDag-Erling Smørgrav return NULL; 104b7579f77SDag-Erling Smørgrav rbtree_init(&zones->ztree, &local_zone_cmp); 10517d15b25SDag-Erling Smørgrav lock_rw_init(&zones->lock); 106b7579f77SDag-Erling Smørgrav lock_protect(&zones->lock, &zones->ztree, sizeof(zones->ztree)); 107b7579f77SDag-Erling Smørgrav /* also lock protects the rbnode's in struct local_zone */ 108b7579f77SDag-Erling Smørgrav return zones; 109b7579f77SDag-Erling Smørgrav } 110b7579f77SDag-Erling Smørgrav 111b7579f77SDag-Erling Smørgrav /** helper traverse to delete zones */ 112b7579f77SDag-Erling Smørgrav static void 1133005e0a3SDag-Erling Smørgrav lzdel(rbnode_type* n, void* ATTR_UNUSED(arg)) 114b7579f77SDag-Erling Smørgrav { 115b7579f77SDag-Erling Smørgrav struct local_zone* z = (struct local_zone*)n->key; 116b7579f77SDag-Erling Smørgrav local_zone_delete(z); 117b7579f77SDag-Erling Smørgrav } 118b7579f77SDag-Erling Smørgrav 119b7579f77SDag-Erling Smørgrav void 120b7579f77SDag-Erling Smørgrav local_zones_delete(struct local_zones* zones) 121b7579f77SDag-Erling Smørgrav { 122b7579f77SDag-Erling Smørgrav if(!zones) 123b7579f77SDag-Erling Smørgrav return; 12417d15b25SDag-Erling Smørgrav lock_rw_destroy(&zones->lock); 125b7579f77SDag-Erling Smørgrav /* walk through zones and delete them all */ 126b7579f77SDag-Erling Smørgrav traverse_postorder(&zones->ztree, lzdel, NULL); 127b7579f77SDag-Erling Smørgrav free(zones); 128b7579f77SDag-Erling Smørgrav } 129b7579f77SDag-Erling Smørgrav 130b7579f77SDag-Erling Smørgrav void 131b7579f77SDag-Erling Smørgrav local_zone_delete(struct local_zone* z) 132b7579f77SDag-Erling Smørgrav { 133b7579f77SDag-Erling Smørgrav if(!z) 134b7579f77SDag-Erling Smørgrav return; 135b7579f77SDag-Erling Smørgrav lock_rw_destroy(&z->lock); 136b7579f77SDag-Erling Smørgrav regional_destroy(z->region); 137b7579f77SDag-Erling Smørgrav free(z->name); 138e2d15004SDag-Erling Smørgrav free(z->taglist); 139b7579f77SDag-Erling Smørgrav free(z); 140b7579f77SDag-Erling Smørgrav } 141b7579f77SDag-Erling Smørgrav 142b7579f77SDag-Erling Smørgrav int 143b7579f77SDag-Erling Smørgrav local_zone_cmp(const void* z1, const void* z2) 144b7579f77SDag-Erling Smørgrav { 145b7579f77SDag-Erling Smørgrav /* first sort on class, so that hierarchy can be maintained within 146b7579f77SDag-Erling Smørgrav * a class */ 147b7579f77SDag-Erling Smørgrav struct local_zone* a = (struct local_zone*)z1; 148b7579f77SDag-Erling Smørgrav struct local_zone* b = (struct local_zone*)z2; 149b7579f77SDag-Erling Smørgrav int m; 150b7579f77SDag-Erling Smørgrav if(a->dclass != b->dclass) { 151b7579f77SDag-Erling Smørgrav if(a->dclass < b->dclass) 152b7579f77SDag-Erling Smørgrav return -1; 153b7579f77SDag-Erling Smørgrav return 1; 154b7579f77SDag-Erling Smørgrav } 155b7579f77SDag-Erling Smørgrav return dname_lab_cmp(a->name, a->namelabs, b->name, b->namelabs, &m); 156b7579f77SDag-Erling Smørgrav } 157b7579f77SDag-Erling Smørgrav 158b7579f77SDag-Erling Smørgrav int 159b7579f77SDag-Erling Smørgrav local_data_cmp(const void* d1, const void* d2) 160b7579f77SDag-Erling Smørgrav { 161b7579f77SDag-Erling Smørgrav struct local_data* a = (struct local_data*)d1; 162b7579f77SDag-Erling Smørgrav struct local_data* b = (struct local_data*)d2; 163b7579f77SDag-Erling Smørgrav int m; 164b7579f77SDag-Erling Smørgrav return dname_canon_lab_cmp(a->name, a->namelabs, b->name, 165b7579f77SDag-Erling Smørgrav b->namelabs, &m); 166b7579f77SDag-Erling Smørgrav } 167b7579f77SDag-Erling Smørgrav 168b7579f77SDag-Erling Smørgrav /* form wireformat from text format domain name */ 169b7579f77SDag-Erling Smørgrav int 170b7579f77SDag-Erling Smørgrav parse_dname(const char* str, uint8_t** res, size_t* len, int* labs) 171b7579f77SDag-Erling Smørgrav { 17217d15b25SDag-Erling Smørgrav *res = sldns_str2wire_dname(str, len); 173b7579f77SDag-Erling Smørgrav *labs = 0; 174b7579f77SDag-Erling Smørgrav if(!*res) { 17517d15b25SDag-Erling Smørgrav log_err("cannot parse name %s", str); 176b7579f77SDag-Erling Smørgrav return 0; 177b7579f77SDag-Erling Smørgrav } 178b7579f77SDag-Erling Smørgrav *labs = dname_count_size_labels(*res, len); 179b7579f77SDag-Erling Smørgrav return 1; 180b7579f77SDag-Erling Smørgrav } 181b7579f77SDag-Erling Smørgrav 182b7579f77SDag-Erling Smørgrav /** create a new localzone */ 183b7579f77SDag-Erling Smørgrav static struct local_zone* 184b7579f77SDag-Erling Smørgrav local_zone_create(uint8_t* nm, size_t len, int labs, 185b7579f77SDag-Erling Smørgrav enum localzone_type t, uint16_t dclass) 186b7579f77SDag-Erling Smørgrav { 187b7579f77SDag-Erling Smørgrav struct local_zone* z = (struct local_zone*)calloc(1, sizeof(*z)); 188b7579f77SDag-Erling Smørgrav if(!z) { 189b7579f77SDag-Erling Smørgrav return NULL; 190b7579f77SDag-Erling Smørgrav } 191b7579f77SDag-Erling Smørgrav z->node.key = z; 192b7579f77SDag-Erling Smørgrav z->dclass = dclass; 193b7579f77SDag-Erling Smørgrav z->type = t; 194b7579f77SDag-Erling Smørgrav z->name = nm; 195b7579f77SDag-Erling Smørgrav z->namelen = len; 196b7579f77SDag-Erling Smørgrav z->namelabs = labs; 197b7579f77SDag-Erling Smørgrav lock_rw_init(&z->lock); 198369c6923SCy Schubert z->region = regional_create_nochunk(sizeof(struct regional)); 199b7579f77SDag-Erling Smørgrav if(!z->region) { 200b7579f77SDag-Erling Smørgrav free(z); 201b7579f77SDag-Erling Smørgrav return NULL; 202b7579f77SDag-Erling Smørgrav } 203b7579f77SDag-Erling Smørgrav rbtree_init(&z->data, &local_data_cmp); 2043005e0a3SDag-Erling Smørgrav lock_protect(&z->lock, &z->parent, sizeof(*z)-sizeof(rbnode_type)); 205b7579f77SDag-Erling Smørgrav /* also the zones->lock protects node, parent, name*, class */ 206b7579f77SDag-Erling Smørgrav return z; 207b7579f77SDag-Erling Smørgrav } 208b7579f77SDag-Erling Smørgrav 209b7579f77SDag-Erling Smørgrav /** enter a new zone with allocated dname returns with WRlock */ 210b7579f77SDag-Erling Smørgrav static struct local_zone* 211b7579f77SDag-Erling Smørgrav lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len, 212b7579f77SDag-Erling Smørgrav int labs, enum localzone_type t, uint16_t c) 213b7579f77SDag-Erling Smørgrav { 214b7579f77SDag-Erling Smørgrav struct local_zone* z = local_zone_create(nm, len, labs, t, c); 215b7579f77SDag-Erling Smørgrav if(!z) { 216e2d15004SDag-Erling Smørgrav free(nm); 217b7579f77SDag-Erling Smørgrav log_err("out of memory"); 218b7579f77SDag-Erling Smørgrav return NULL; 219b7579f77SDag-Erling Smørgrav } 220b7579f77SDag-Erling Smørgrav 221b7579f77SDag-Erling Smørgrav /* add to rbtree */ 22217d15b25SDag-Erling Smørgrav lock_rw_wrlock(&zones->lock); 223b7579f77SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 224b7579f77SDag-Erling Smørgrav if(!rbtree_insert(&zones->ztree, &z->node)) { 225bc892140SDag-Erling Smørgrav struct local_zone* oldz; 226*be771a7bSCy Schubert char str[LDNS_MAX_DOMAINLEN]; 227c7f4d7adSDag-Erling Smørgrav dname_str(nm, str); 228c7f4d7adSDag-Erling Smørgrav log_warn("duplicate local-zone %s", str); 229b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 230bc892140SDag-Erling Smørgrav /* save zone name locally before deallocation, 231bc892140SDag-Erling Smørgrav * otherwise, nm is gone if we zone_delete now. */ 232bc892140SDag-Erling Smørgrav oldz = z; 233b5663de9SDag-Erling Smørgrav /* find the correct zone, so not an error for duplicate */ 234b5663de9SDag-Erling Smørgrav z = local_zones_find(zones, nm, len, labs, c); 235b5663de9SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 23617d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 237bc892140SDag-Erling Smørgrav local_zone_delete(oldz); 238b5663de9SDag-Erling Smørgrav return z; 239b7579f77SDag-Erling Smørgrav } 24017d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 241b7579f77SDag-Erling Smørgrav return z; 242b7579f77SDag-Erling Smørgrav } 243b7579f77SDag-Erling Smørgrav 244b7579f77SDag-Erling Smørgrav /** enter a new zone */ 24556850988SCy Schubert struct local_zone* 246b7579f77SDag-Erling Smørgrav lz_enter_zone(struct local_zones* zones, const char* name, const char* type, 247b7579f77SDag-Erling Smørgrav uint16_t dclass) 248b7579f77SDag-Erling Smørgrav { 249b7579f77SDag-Erling Smørgrav struct local_zone* z; 250b7579f77SDag-Erling Smørgrav enum localzone_type t; 251b7579f77SDag-Erling Smørgrav uint8_t* nm; 252b7579f77SDag-Erling Smørgrav size_t len; 253b7579f77SDag-Erling Smørgrav int labs; 254b7579f77SDag-Erling Smørgrav if(!parse_dname(name, &nm, &len, &labs)) { 255b7579f77SDag-Erling Smørgrav log_err("bad zone name %s %s", name, type); 256b7579f77SDag-Erling Smørgrav return NULL; 257b7579f77SDag-Erling Smørgrav } 258b7579f77SDag-Erling Smørgrav if(!local_zone_str2type(type, &t)) { 259b7579f77SDag-Erling Smørgrav log_err("bad lz_enter_zone type %s %s", name, type); 260b7579f77SDag-Erling Smørgrav free(nm); 261b7579f77SDag-Erling Smørgrav return NULL; 262b7579f77SDag-Erling Smørgrav } 263b7579f77SDag-Erling Smørgrav if(!(z=lz_enter_zone_dname(zones, nm, len, labs, t, dclass))) { 264b7579f77SDag-Erling Smørgrav log_err("could not enter zone %s %s", name, type); 265b7579f77SDag-Erling Smørgrav return NULL; 266b7579f77SDag-Erling Smørgrav } 267b7579f77SDag-Erling Smørgrav return z; 268b7579f77SDag-Erling Smørgrav } 269b7579f77SDag-Erling Smørgrav 27065b390aaSDag-Erling Smørgrav int 27165b390aaSDag-Erling Smørgrav rrstr_get_rr_content(const char* str, uint8_t** nm, uint16_t* type, 27217d15b25SDag-Erling Smørgrav uint16_t* dclass, time_t* ttl, uint8_t* rr, size_t len, 27317d15b25SDag-Erling Smørgrav uint8_t** rdata, size_t* rdata_len) 274b7579f77SDag-Erling Smørgrav { 27517d15b25SDag-Erling Smørgrav size_t dname_len = 0; 27617d15b25SDag-Erling Smørgrav int e = sldns_str2wire_rr_buf(str, rr, &len, &dname_len, 3600, 27717d15b25SDag-Erling Smørgrav NULL, 0, NULL, 0); 27817d15b25SDag-Erling Smørgrav if(e) { 27917d15b25SDag-Erling Smørgrav log_err("error parsing local-data at %d: '%s': %s", 28017d15b25SDag-Erling Smørgrav LDNS_WIREPARSE_OFFSET(e), str, 28117d15b25SDag-Erling Smørgrav sldns_get_errorstr_parse(e)); 282b7579f77SDag-Erling Smørgrav return 0; 283b7579f77SDag-Erling Smørgrav } 28417d15b25SDag-Erling Smørgrav *nm = memdup(rr, dname_len); 285b7579f77SDag-Erling Smørgrav if(!*nm) { 286b7579f77SDag-Erling Smørgrav log_err("out of memory"); 287b7579f77SDag-Erling Smørgrav return 0; 288b7579f77SDag-Erling Smørgrav } 28917d15b25SDag-Erling Smørgrav *dclass = sldns_wirerr_get_class(rr, len, dname_len); 29017d15b25SDag-Erling Smørgrav *type = sldns_wirerr_get_type(rr, len, dname_len); 29117d15b25SDag-Erling Smørgrav *ttl = (time_t)sldns_wirerr_get_ttl(rr, len, dname_len); 29217d15b25SDag-Erling Smørgrav *rdata = sldns_wirerr_get_rdatawl(rr, len, dname_len); 29317d15b25SDag-Erling Smørgrav *rdata_len = sldns_wirerr_get_rdatalen(rr, len, dname_len)+2; 294b7579f77SDag-Erling Smørgrav return 1; 295b7579f77SDag-Erling Smørgrav } 296b7579f77SDag-Erling Smørgrav 297b7579f77SDag-Erling Smørgrav /** return name and class of rr; parses string */ 298b7579f77SDag-Erling Smørgrav static int 299971980c3SDag-Erling Smørgrav get_rr_nameclass(const char* str, uint8_t** nm, uint16_t* dclass, 300971980c3SDag-Erling Smørgrav uint16_t* dtype) 301b7579f77SDag-Erling Smørgrav { 30217d15b25SDag-Erling Smørgrav uint8_t rr[LDNS_RR_BUF_SIZE]; 30317d15b25SDag-Erling Smørgrav size_t len = sizeof(rr), dname_len = 0; 30417d15b25SDag-Erling Smørgrav int s = sldns_str2wire_rr_buf(str, rr, &len, &dname_len, 3600, 30517d15b25SDag-Erling Smørgrav NULL, 0, NULL, 0); 30617d15b25SDag-Erling Smørgrav if(s != 0) { 30717d15b25SDag-Erling Smørgrav log_err("error parsing local-data at %d '%s': %s", 30817d15b25SDag-Erling Smørgrav LDNS_WIREPARSE_OFFSET(s), str, 30917d15b25SDag-Erling Smørgrav sldns_get_errorstr_parse(s)); 310b7579f77SDag-Erling Smørgrav return 0; 311b7579f77SDag-Erling Smørgrav } 31217d15b25SDag-Erling Smørgrav *nm = memdup(rr, dname_len); 31317d15b25SDag-Erling Smørgrav *dclass = sldns_wirerr_get_class(rr, len, dname_len); 314971980c3SDag-Erling Smørgrav *dtype = sldns_wirerr_get_type(rr, len, dname_len); 315b7579f77SDag-Erling Smørgrav if(!*nm) { 316b7579f77SDag-Erling Smørgrav log_err("out of memory"); 317b7579f77SDag-Erling Smørgrav return 0; 318b7579f77SDag-Erling Smørgrav } 319b7579f77SDag-Erling Smørgrav return 1; 320b7579f77SDag-Erling Smørgrav } 321b7579f77SDag-Erling Smørgrav 322b7579f77SDag-Erling Smørgrav /** 323b7579f77SDag-Erling Smørgrav * Find an rrset in local data structure. 324b7579f77SDag-Erling Smørgrav * @param data: local data domain name structure. 325b7579f77SDag-Erling Smørgrav * @param type: type to look for (host order). 326bc892140SDag-Erling Smørgrav * @param alias_ok: 1 if matching a non-exact, alias type such as CNAME is 327bc892140SDag-Erling Smørgrav * allowed. otherwise 0. 328b7579f77SDag-Erling Smørgrav * @return rrset pointer or NULL if not found. 329b7579f77SDag-Erling Smørgrav */ 330b7579f77SDag-Erling Smørgrav static struct local_rrset* 331bc892140SDag-Erling Smørgrav local_data_find_type(struct local_data* data, uint16_t type, int alias_ok) 332b7579f77SDag-Erling Smørgrav { 333335c7cdaSCy Schubert struct local_rrset* p, *cname = NULL; 334b7579f77SDag-Erling Smørgrav type = htons(type); 335b7579f77SDag-Erling Smørgrav for(p = data->rrsets; p; p = p->next) { 336b7579f77SDag-Erling Smørgrav if(p->rrset->rk.type == type) 337b7579f77SDag-Erling Smørgrav return p; 338bc892140SDag-Erling Smørgrav if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) 339335c7cdaSCy Schubert cname = p; 340b7579f77SDag-Erling Smørgrav } 341335c7cdaSCy Schubert if(alias_ok) 342335c7cdaSCy Schubert return cname; 343b7579f77SDag-Erling Smørgrav return NULL; 344b7579f77SDag-Erling Smørgrav } 345b7579f77SDag-Erling Smørgrav 346b7579f77SDag-Erling Smørgrav /** check for RR duplicates */ 347b7579f77SDag-Erling Smørgrav static int 34817d15b25SDag-Erling Smørgrav rr_is_duplicate(struct packed_rrset_data* pd, uint8_t* rdata, size_t rdata_len) 349b7579f77SDag-Erling Smørgrav { 350b7579f77SDag-Erling Smørgrav size_t i; 351b7579f77SDag-Erling Smørgrav for(i=0; i<pd->count; i++) { 35217d15b25SDag-Erling Smørgrav if(pd->rr_len[i] == rdata_len && 35317d15b25SDag-Erling Smørgrav memcmp(pd->rr_data[i], rdata, rdata_len) == 0) 354b7579f77SDag-Erling Smørgrav return 1; 355b7579f77SDag-Erling Smørgrav } 356b7579f77SDag-Erling Smørgrav return 0; 357b7579f77SDag-Erling Smørgrav } 358b7579f77SDag-Erling Smørgrav 359b7579f77SDag-Erling Smørgrav /** new local_rrset */ 360b7579f77SDag-Erling Smørgrav static struct local_rrset* 361b7579f77SDag-Erling Smørgrav new_local_rrset(struct regional* region, struct local_data* node, 362b7579f77SDag-Erling Smørgrav uint16_t rrtype, uint16_t rrclass) 363b7579f77SDag-Erling Smørgrav { 364b7579f77SDag-Erling Smørgrav struct packed_rrset_data* pd; 365b7579f77SDag-Erling Smørgrav struct local_rrset* rrset = (struct local_rrset*) 366b7579f77SDag-Erling Smørgrav regional_alloc_zero(region, sizeof(*rrset)); 367b7579f77SDag-Erling Smørgrav if(!rrset) { 368b7579f77SDag-Erling Smørgrav log_err("out of memory"); 369b7579f77SDag-Erling Smørgrav return NULL; 370b7579f77SDag-Erling Smørgrav } 371b7579f77SDag-Erling Smørgrav rrset->next = node->rrsets; 372b7579f77SDag-Erling Smørgrav node->rrsets = rrset; 373b7579f77SDag-Erling Smørgrav rrset->rrset = (struct ub_packed_rrset_key*) 374b7579f77SDag-Erling Smørgrav regional_alloc_zero(region, sizeof(*rrset->rrset)); 375b7579f77SDag-Erling Smørgrav if(!rrset->rrset) { 376b7579f77SDag-Erling Smørgrav log_err("out of memory"); 377b7579f77SDag-Erling Smørgrav return NULL; 378b7579f77SDag-Erling Smørgrav } 379b7579f77SDag-Erling Smørgrav rrset->rrset->entry.key = rrset->rrset; 380b7579f77SDag-Erling Smørgrav pd = (struct packed_rrset_data*)regional_alloc_zero(region, 381b7579f77SDag-Erling Smørgrav sizeof(*pd)); 382b7579f77SDag-Erling Smørgrav if(!pd) { 383b7579f77SDag-Erling Smørgrav log_err("out of memory"); 384b7579f77SDag-Erling Smørgrav return NULL; 385b7579f77SDag-Erling Smørgrav } 386b7579f77SDag-Erling Smørgrav pd->trust = rrset_trust_prim_noglue; 387b7579f77SDag-Erling Smørgrav pd->security = sec_status_insecure; 388b7579f77SDag-Erling Smørgrav rrset->rrset->entry.data = pd; 389b7579f77SDag-Erling Smørgrav rrset->rrset->rk.dname = node->name; 390b7579f77SDag-Erling Smørgrav rrset->rrset->rk.dname_len = node->namelen; 391b7579f77SDag-Erling Smørgrav rrset->rrset->rk.type = htons(rrtype); 392b7579f77SDag-Erling Smørgrav rrset->rrset->rk.rrset_class = htons(rrclass); 393b7579f77SDag-Erling Smørgrav return rrset; 394b7579f77SDag-Erling Smørgrav } 395b7579f77SDag-Erling Smørgrav 396b7579f77SDag-Erling Smørgrav /** insert RR into RRset data structure; Wastes a couple of bytes */ 39765b390aaSDag-Erling Smørgrav int 39865b390aaSDag-Erling Smørgrav rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd, 399bc892140SDag-Erling Smørgrav uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr) 400b7579f77SDag-Erling Smørgrav { 401b7579f77SDag-Erling Smørgrav size_t* oldlen = pd->rr_len; 40217d15b25SDag-Erling Smørgrav time_t* oldttl = pd->rr_ttl; 403b7579f77SDag-Erling Smørgrav uint8_t** olddata = pd->rr_data; 404b7579f77SDag-Erling Smørgrav 405b7579f77SDag-Erling Smørgrav /* add RR to rrset */ 406bc892140SDag-Erling Smørgrav if(pd->count > LOCALZONE_RRSET_COUNT_MAX) { 407bc892140SDag-Erling Smørgrav log_warn("RRset '%s' has more than %d records, record ignored", 408bc892140SDag-Erling Smørgrav rrstr, LOCALZONE_RRSET_COUNT_MAX); 409bc892140SDag-Erling Smørgrav return 1; 410bc892140SDag-Erling Smørgrav } 411b7579f77SDag-Erling Smørgrav pd->count++; 412b7579f77SDag-Erling Smørgrav pd->rr_len = regional_alloc(region, sizeof(*pd->rr_len)*pd->count); 413b7579f77SDag-Erling Smørgrav pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count); 414b7579f77SDag-Erling Smørgrav pd->rr_data = regional_alloc(region, sizeof(*pd->rr_data)*pd->count); 415b7579f77SDag-Erling Smørgrav if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) { 416b7579f77SDag-Erling Smørgrav log_err("out of memory"); 417b7579f77SDag-Erling Smørgrav return 0; 418b7579f77SDag-Erling Smørgrav } 419b7579f77SDag-Erling Smørgrav if(pd->count > 1) { 420b7579f77SDag-Erling Smørgrav memcpy(pd->rr_len+1, oldlen, 421b7579f77SDag-Erling Smørgrav sizeof(*pd->rr_len)*(pd->count-1)); 422b7579f77SDag-Erling Smørgrav memcpy(pd->rr_ttl+1, oldttl, 423b7579f77SDag-Erling Smørgrav sizeof(*pd->rr_ttl)*(pd->count-1)); 424b7579f77SDag-Erling Smørgrav memcpy(pd->rr_data+1, olddata, 425b7579f77SDag-Erling Smørgrav sizeof(*pd->rr_data)*(pd->count-1)); 426b7579f77SDag-Erling Smørgrav } 42717d15b25SDag-Erling Smørgrav pd->rr_len[0] = rdata_len; 428b7579f77SDag-Erling Smørgrav pd->rr_ttl[0] = ttl; 42917d15b25SDag-Erling Smørgrav pd->rr_data[0] = regional_alloc_init(region, rdata, rdata_len); 430b7579f77SDag-Erling Smørgrav if(!pd->rr_data[0]) { 431b7579f77SDag-Erling Smørgrav log_err("out of memory"); 432b7579f77SDag-Erling Smørgrav return 0; 433b7579f77SDag-Erling Smørgrav } 434b7579f77SDag-Erling Smørgrav return 1; 435b7579f77SDag-Erling Smørgrav } 436b7579f77SDag-Erling Smørgrav 437091e9e46SCy Schubert /** Delete RR from local-zone RRset, wastes memory as the deleted RRs cannot be 438091e9e46SCy Schubert * free'd (regionally alloc'd) */ 439091e9e46SCy Schubert int 440091e9e46SCy Schubert local_rrset_remove_rr(struct packed_rrset_data* pd, size_t index) 441091e9e46SCy Schubert { 442091e9e46SCy Schubert log_assert(pd->count > 0); 443091e9e46SCy Schubert if(index >= pd->count) { 444091e9e46SCy Schubert log_warn("Trying to remove RR with out of bound index"); 445091e9e46SCy Schubert return 0; 446091e9e46SCy Schubert } 447091e9e46SCy Schubert if(index + 1 < pd->count) { 448091e9e46SCy Schubert /* not removing last element */ 449091e9e46SCy Schubert size_t nexti = index + 1; 450091e9e46SCy Schubert size_t num = pd->count - nexti; 451091e9e46SCy Schubert memmove(pd->rr_len+index, pd->rr_len+nexti, sizeof(*pd->rr_len)*num); 452091e9e46SCy Schubert memmove(pd->rr_ttl+index, pd->rr_ttl+nexti, sizeof(*pd->rr_ttl)*num); 453091e9e46SCy Schubert memmove(pd->rr_data+index, pd->rr_data+nexti, sizeof(*pd->rr_data)*num); 454091e9e46SCy Schubert } 455091e9e46SCy Schubert pd->count--; 456091e9e46SCy Schubert return 1; 457091e9e46SCy Schubert } 458091e9e46SCy Schubert 459091e9e46SCy Schubert struct local_data* 460091e9e46SCy Schubert local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs) 461b7579f77SDag-Erling Smørgrav { 462b7579f77SDag-Erling Smørgrav struct local_data key; 463b7579f77SDag-Erling Smørgrav key.node.key = &key; 464b7579f77SDag-Erling Smørgrav key.name = nm; 465b7579f77SDag-Erling Smørgrav key.namelen = nmlen; 466b7579f77SDag-Erling Smørgrav key.namelabs = nmlabs; 467b7579f77SDag-Erling Smørgrav return (struct local_data*)rbtree_search(&z->data, &key.node); 468b7579f77SDag-Erling Smørgrav } 469b7579f77SDag-Erling Smørgrav 470b7579f77SDag-Erling Smørgrav /** find a node, create it if not and all its empty nonterminal parents */ 471b7579f77SDag-Erling Smørgrav static int 472b7579f77SDag-Erling Smørgrav lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen, 473b7579f77SDag-Erling Smørgrav int nmlabs, struct local_data** res) 474b7579f77SDag-Erling Smørgrav { 475091e9e46SCy Schubert struct local_data* ld = local_zone_find_data(z, nm, nmlen, nmlabs); 476b7579f77SDag-Erling Smørgrav if(!ld) { 477b7579f77SDag-Erling Smørgrav /* create a domain name to store rr. */ 478b7579f77SDag-Erling Smørgrav ld = (struct local_data*)regional_alloc_zero(z->region, 479b7579f77SDag-Erling Smørgrav sizeof(*ld)); 480b7579f77SDag-Erling Smørgrav if(!ld) { 481b7579f77SDag-Erling Smørgrav log_err("out of memory adding local data"); 482b7579f77SDag-Erling Smørgrav return 0; 483b7579f77SDag-Erling Smørgrav } 484b7579f77SDag-Erling Smørgrav ld->node.key = ld; 485b7579f77SDag-Erling Smørgrav ld->name = regional_alloc_init(z->region, nm, nmlen); 486b7579f77SDag-Erling Smørgrav if(!ld->name) { 487b7579f77SDag-Erling Smørgrav log_err("out of memory"); 488b7579f77SDag-Erling Smørgrav return 0; 489b7579f77SDag-Erling Smørgrav } 490b7579f77SDag-Erling Smørgrav ld->namelen = nmlen; 491b7579f77SDag-Erling Smørgrav ld->namelabs = nmlabs; 492b7579f77SDag-Erling Smørgrav if(!rbtree_insert(&z->data, &ld->node)) { 493b7579f77SDag-Erling Smørgrav log_assert(0); /* duplicate name */ 494b7579f77SDag-Erling Smørgrav } 495b7579f77SDag-Erling Smørgrav /* see if empty nonterminals need to be created */ 496b7579f77SDag-Erling Smørgrav if(nmlabs > z->namelabs) { 497b7579f77SDag-Erling Smørgrav dname_remove_label(&nm, &nmlen); 498b7579f77SDag-Erling Smørgrav if(!lz_find_create_node(z, nm, nmlen, nmlabs-1, res)) 499b7579f77SDag-Erling Smørgrav return 0; 500b7579f77SDag-Erling Smørgrav } 501b7579f77SDag-Erling Smørgrav } 502b7579f77SDag-Erling Smørgrav *res = ld; 503b7579f77SDag-Erling Smørgrav return 1; 504b7579f77SDag-Erling Smørgrav } 505b7579f77SDag-Erling Smørgrav 506f44e67d1SCy Schubert /* Mark the SOA record for the zone. This only marks the SOA rrset; the data 507f44e67d1SCy Schubert * for the RR is entered later on local_zone_enter_rr() as with the other 50824e36522SCy Schubert * records. An artificial soa_negative record with a modified TTL (minimum of 509f44e67d1SCy Schubert * the TTL and the SOA.MINIMUM) is also created and marked for usage with 510f44e67d1SCy Schubert * negative answers and to avoid allocations during those answers. */ 511f44e67d1SCy Schubert static int 512f44e67d1SCy Schubert lz_mark_soa_for_zone(struct local_zone* z, struct ub_packed_rrset_key* soa_rrset, 513f44e67d1SCy Schubert uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr) 514f44e67d1SCy Schubert { 515f44e67d1SCy Schubert struct packed_rrset_data* pd = (struct packed_rrset_data*) 516f44e67d1SCy Schubert regional_alloc_zero(z->region, sizeof(*pd)); 517f44e67d1SCy Schubert struct ub_packed_rrset_key* rrset_negative = (struct ub_packed_rrset_key*) 518f44e67d1SCy Schubert regional_alloc_zero(z->region, sizeof(*rrset_negative)); 519f44e67d1SCy Schubert time_t minimum; 520f44e67d1SCy Schubert if(!rrset_negative||!pd) { 521f44e67d1SCy Schubert log_err("out of memory"); 522f44e67d1SCy Schubert return 0; 523f44e67d1SCy Schubert } 524f44e67d1SCy Schubert /* Mark the original SOA record and then continue with the negative one. */ 525f44e67d1SCy Schubert z->soa = soa_rrset; 526f44e67d1SCy Schubert rrset_negative->entry.key = rrset_negative; 527f44e67d1SCy Schubert pd->trust = rrset_trust_prim_noglue; 528f44e67d1SCy Schubert pd->security = sec_status_insecure; 529f44e67d1SCy Schubert rrset_negative->entry.data = pd; 530f44e67d1SCy Schubert rrset_negative->rk.dname = soa_rrset->rk.dname; 531f44e67d1SCy Schubert rrset_negative->rk.dname_len = soa_rrset->rk.dname_len; 532f44e67d1SCy Schubert rrset_negative->rk.type = soa_rrset->rk.type; 533f44e67d1SCy Schubert rrset_negative->rk.rrset_class = soa_rrset->rk.rrset_class; 534f44e67d1SCy Schubert if(!rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr)) 535f44e67d1SCy Schubert return 0; 536f44e67d1SCy Schubert /* last 4 bytes are minimum ttl in network format */ 537f44e67d1SCy Schubert if(pd->count == 0 || pd->rr_len[0] < 2+4) 538f44e67d1SCy Schubert return 0; 539f44e67d1SCy Schubert minimum = (time_t)sldns_read_uint32(pd->rr_data[0]+(pd->rr_len[0]-4)); 540f44e67d1SCy Schubert minimum = ttl<minimum?ttl:minimum; 541f44e67d1SCy Schubert pd->ttl = minimum; 542f44e67d1SCy Schubert pd->rr_ttl[0] = minimum; 543f44e67d1SCy Schubert 544f44e67d1SCy Schubert z->soa_negative = rrset_negative; 545f44e67d1SCy Schubert return 1; 546f44e67d1SCy Schubert } 547f44e67d1SCy Schubert 548091e9e46SCy Schubert int 549091e9e46SCy Schubert local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen, 550091e9e46SCy Schubert int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl, 551091e9e46SCy Schubert uint8_t* rdata, size_t rdata_len, const char* rrstr) 552b7579f77SDag-Erling Smørgrav { 553b7579f77SDag-Erling Smørgrav struct local_data* node; 554b7579f77SDag-Erling Smørgrav struct local_rrset* rrset; 555b7579f77SDag-Erling Smørgrav struct packed_rrset_data* pd; 556091e9e46SCy Schubert 557b7579f77SDag-Erling Smørgrav if(!lz_find_create_node(z, nm, nmlen, nmlabs, &node)) { 558b7579f77SDag-Erling Smørgrav return 0; 559b7579f77SDag-Erling Smørgrav } 560b7579f77SDag-Erling Smørgrav log_assert(node); 561b7579f77SDag-Erling Smørgrav 562bc892140SDag-Erling Smørgrav /* Reject it if we would end up having CNAME and other data (including 563bc892140SDag-Erling Smørgrav * another CNAME) for a redirect zone. */ 564e86b9096SDag-Erling Smørgrav if((z->type == local_zone_redirect || 565e86b9096SDag-Erling Smørgrav z->type == local_zone_inform_redirect) && node->rrsets) { 566bc892140SDag-Erling Smørgrav const char* othertype = NULL; 567bc892140SDag-Erling Smørgrav if (rrtype == LDNS_RR_TYPE_CNAME) 568bc892140SDag-Erling Smørgrav othertype = "other"; 569bc892140SDag-Erling Smørgrav else if (node->rrsets->rrset->rk.type == 570bc892140SDag-Erling Smørgrav htons(LDNS_RR_TYPE_CNAME)) { 571bc892140SDag-Erling Smørgrav othertype = "CNAME"; 572bc892140SDag-Erling Smørgrav } 573bc892140SDag-Erling Smørgrav if(othertype) { 574bc892140SDag-Erling Smørgrav log_err("local-data '%s' in redirect zone must not " 575bc892140SDag-Erling Smørgrav "coexist with %s local-data", rrstr, othertype); 576bc892140SDag-Erling Smørgrav return 0; 577bc892140SDag-Erling Smørgrav } 578bc892140SDag-Erling Smørgrav } 579bc892140SDag-Erling Smørgrav rrset = local_data_find_type(node, rrtype, 0); 580b7579f77SDag-Erling Smørgrav if(!rrset) { 581b7579f77SDag-Erling Smørgrav rrset = new_local_rrset(z->region, node, rrtype, rrclass); 582b7579f77SDag-Erling Smørgrav if(!rrset) 583b7579f77SDag-Erling Smørgrav return 0; 584b7579f77SDag-Erling Smørgrav if(query_dname_compare(node->name, z->name) == 0) { 585b7579f77SDag-Erling Smørgrav if(rrtype == LDNS_RR_TYPE_NSEC) 586b7579f77SDag-Erling Smørgrav rrset->rrset->rk.flags = PACKED_RRSET_NSEC_AT_APEX; 587f44e67d1SCy Schubert if(rrtype == LDNS_RR_TYPE_SOA && 588f44e67d1SCy Schubert !lz_mark_soa_for_zone(z, rrset->rrset, rdata, rdata_len, ttl, 589f44e67d1SCy Schubert rrstr)) 590f44e67d1SCy Schubert return 0; 591b7579f77SDag-Erling Smørgrav } 592b7579f77SDag-Erling Smørgrav } 593b7579f77SDag-Erling Smørgrav pd = (struct packed_rrset_data*)rrset->rrset->entry.data; 594b7579f77SDag-Erling Smørgrav log_assert(rrset && pd); 595b7579f77SDag-Erling Smørgrav 596b7579f77SDag-Erling Smørgrav /* check for duplicate RR */ 59717d15b25SDag-Erling Smørgrav if(rr_is_duplicate(pd, rdata, rdata_len)) { 598b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "ignoring duplicate RR: %s", rrstr); 599b7579f77SDag-Erling Smørgrav return 1; 600b7579f77SDag-Erling Smørgrav } 60165b390aaSDag-Erling Smørgrav return rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr); 602b7579f77SDag-Erling Smørgrav } 603b7579f77SDag-Erling Smørgrav 604091e9e46SCy Schubert /** enter data RR into auth zone */ 60525039b37SCy Schubert static int 606091e9e46SCy Schubert lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr) 607091e9e46SCy Schubert { 608091e9e46SCy Schubert uint8_t* nm; 609091e9e46SCy Schubert size_t nmlen; 610091e9e46SCy Schubert int nmlabs, ret; 611091e9e46SCy Schubert uint16_t rrtype = 0, rrclass = 0; 612091e9e46SCy Schubert time_t ttl = 0; 613091e9e46SCy Schubert uint8_t rr[LDNS_RR_BUF_SIZE]; 614091e9e46SCy Schubert uint8_t* rdata; 615091e9e46SCy Schubert size_t rdata_len; 616091e9e46SCy Schubert if(!rrstr_get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, rr, 617091e9e46SCy Schubert sizeof(rr), &rdata, &rdata_len)) { 618091e9e46SCy Schubert log_err("bad local-data: %s", rrstr); 619091e9e46SCy Schubert return 0; 620091e9e46SCy Schubert } 621091e9e46SCy Schubert log_assert(z->dclass == rrclass); 622091e9e46SCy Schubert if((z->type == local_zone_redirect || 623091e9e46SCy Schubert z->type == local_zone_inform_redirect) && 624091e9e46SCy Schubert query_dname_compare(z->name, nm) != 0) { 625091e9e46SCy Schubert log_err("local-data in redirect zone must reside at top of zone" 626091e9e46SCy Schubert ", not at %s", rrstr); 627091e9e46SCy Schubert free(nm); 628091e9e46SCy Schubert return 0; 629091e9e46SCy Schubert } 630091e9e46SCy Schubert nmlabs = dname_count_size_labels(nm, &nmlen); 631091e9e46SCy Schubert ret = local_zone_enter_rr(z, nm, nmlen, nmlabs, rrtype, rrclass, ttl, 632091e9e46SCy Schubert rdata, rdata_len, rrstr); 633091e9e46SCy Schubert free(nm); 634091e9e46SCy Schubert return ret; 635091e9e46SCy Schubert } 636091e9e46SCy Schubert 637b7579f77SDag-Erling Smørgrav /** enter a data RR into auth data; a zone for it must exist */ 638b7579f77SDag-Erling Smørgrav static int 63917d15b25SDag-Erling Smørgrav lz_enter_rr_str(struct local_zones* zones, const char* rr) 640b7579f77SDag-Erling Smørgrav { 641b7579f77SDag-Erling Smørgrav uint8_t* rr_name; 642971980c3SDag-Erling Smørgrav uint16_t rr_class, rr_type; 643b7579f77SDag-Erling Smørgrav size_t len; 644b7579f77SDag-Erling Smørgrav int labs; 645b7579f77SDag-Erling Smørgrav struct local_zone* z; 646b7579f77SDag-Erling Smørgrav int r; 647971980c3SDag-Erling Smørgrav if(!get_rr_nameclass(rr, &rr_name, &rr_class, &rr_type)) { 648b7579f77SDag-Erling Smørgrav log_err("bad rr %s", rr); 649b7579f77SDag-Erling Smørgrav return 0; 650b7579f77SDag-Erling Smørgrav } 651b7579f77SDag-Erling Smørgrav labs = dname_count_size_labels(rr_name, &len); 65217d15b25SDag-Erling Smørgrav lock_rw_rdlock(&zones->lock); 653971980c3SDag-Erling Smørgrav z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type); 654b7579f77SDag-Erling Smørgrav if(!z) { 65517d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 656b7579f77SDag-Erling Smørgrav fatal_exit("internal error: no zone for rr %s", rr); 657b7579f77SDag-Erling Smørgrav } 658b7579f77SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 65917d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 660b7579f77SDag-Erling Smørgrav free(rr_name); 66117d15b25SDag-Erling Smørgrav r = lz_enter_rr_into_zone(z, rr); 662b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 663b7579f77SDag-Erling Smørgrav return r; 664b7579f77SDag-Erling Smørgrav } 665b7579f77SDag-Erling Smørgrav 666e2d15004SDag-Erling Smørgrav /** enter tagstring into zone */ 667e2d15004SDag-Erling Smørgrav static int 668e2d15004SDag-Erling Smørgrav lz_enter_zone_tag(struct local_zones* zones, char* zname, uint8_t* list, 669e2d15004SDag-Erling Smørgrav size_t len, uint16_t rr_class) 670e2d15004SDag-Erling Smørgrav { 671e2d15004SDag-Erling Smørgrav uint8_t dname[LDNS_MAX_DOMAINLEN+1]; 672e2d15004SDag-Erling Smørgrav size_t dname_len = sizeof(dname); 673e2d15004SDag-Erling Smørgrav int dname_labs, r = 0; 674e2d15004SDag-Erling Smørgrav struct local_zone* z; 675e2d15004SDag-Erling Smørgrav 676e2d15004SDag-Erling Smørgrav if(sldns_str2wire_dname_buf(zname, dname, &dname_len) != 0) { 677e2d15004SDag-Erling Smørgrav log_err("cannot parse zone name in local-zone-tag: %s", zname); 678e2d15004SDag-Erling Smørgrav return 0; 679e2d15004SDag-Erling Smørgrav } 680e2d15004SDag-Erling Smørgrav dname_labs = dname_count_labels(dname); 681e2d15004SDag-Erling Smørgrav 682e2d15004SDag-Erling Smørgrav lock_rw_rdlock(&zones->lock); 683b5663de9SDag-Erling Smørgrav z = local_zones_find(zones, dname, dname_len, dname_labs, rr_class); 684e2d15004SDag-Erling Smørgrav if(!z) { 685e2d15004SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 686e2d15004SDag-Erling Smørgrav log_err("no local-zone for tag %s", zname); 687e2d15004SDag-Erling Smørgrav return 0; 688e2d15004SDag-Erling Smørgrav } 689e2d15004SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 690e2d15004SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 691e2d15004SDag-Erling Smørgrav free(z->taglist); 692e2d15004SDag-Erling Smørgrav z->taglist = memdup(list, len); 693e2d15004SDag-Erling Smørgrav z->taglen = len; 694e2d15004SDag-Erling Smørgrav if(z->taglist) 695e2d15004SDag-Erling Smørgrav r = 1; 696e2d15004SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 697e2d15004SDag-Erling Smørgrav return r; 698e2d15004SDag-Erling Smørgrav } 699e2d15004SDag-Erling Smørgrav 700b5663de9SDag-Erling Smørgrav /** enter override into zone */ 701b5663de9SDag-Erling Smørgrav static int 702b5663de9SDag-Erling Smørgrav lz_enter_override(struct local_zones* zones, char* zname, char* netblock, 703b5663de9SDag-Erling Smørgrav char* type, uint16_t rr_class) 704b5663de9SDag-Erling Smørgrav { 705b5663de9SDag-Erling Smørgrav uint8_t dname[LDNS_MAX_DOMAINLEN+1]; 706b5663de9SDag-Erling Smørgrav size_t dname_len = sizeof(dname); 707b5663de9SDag-Erling Smørgrav int dname_labs; 708b5663de9SDag-Erling Smørgrav struct sockaddr_storage addr; 709b5663de9SDag-Erling Smørgrav int net; 710b5663de9SDag-Erling Smørgrav socklen_t addrlen; 711b5663de9SDag-Erling Smørgrav struct local_zone* z; 712b5663de9SDag-Erling Smørgrav enum localzone_type t; 713b5663de9SDag-Erling Smørgrav 714b5663de9SDag-Erling Smørgrav /* parse zone name */ 715b5663de9SDag-Erling Smørgrav if(sldns_str2wire_dname_buf(zname, dname, &dname_len) != 0) { 716b5663de9SDag-Erling Smørgrav log_err("cannot parse zone name in local-zone-override: %s %s", 717b5663de9SDag-Erling Smørgrav zname, netblock); 718b5663de9SDag-Erling Smørgrav return 0; 719b5663de9SDag-Erling Smørgrav } 720b5663de9SDag-Erling Smørgrav dname_labs = dname_count_labels(dname); 721b5663de9SDag-Erling Smørgrav 722b5663de9SDag-Erling Smørgrav /* parse netblock */ 723b5663de9SDag-Erling Smørgrav if(!netblockstrtoaddr(netblock, UNBOUND_DNS_PORT, &addr, &addrlen, 724b5663de9SDag-Erling Smørgrav &net)) { 725b5663de9SDag-Erling Smørgrav log_err("cannot parse netblock in local-zone-override: %s %s", 726b5663de9SDag-Erling Smørgrav zname, netblock); 727b5663de9SDag-Erling Smørgrav return 0; 728b5663de9SDag-Erling Smørgrav } 729b5663de9SDag-Erling Smørgrav 730b5663de9SDag-Erling Smørgrav /* parse zone type */ 731b5663de9SDag-Erling Smørgrav if(!local_zone_str2type(type, &t)) { 732b5663de9SDag-Erling Smørgrav log_err("cannot parse type in local-zone-override: %s %s %s", 733b5663de9SDag-Erling Smørgrav zname, netblock, type); 734b5663de9SDag-Erling Smørgrav return 0; 735b5663de9SDag-Erling Smørgrav } 736b5663de9SDag-Erling Smørgrav 737b5663de9SDag-Erling Smørgrav /* find localzone entry */ 738b5663de9SDag-Erling Smørgrav lock_rw_rdlock(&zones->lock); 739b5663de9SDag-Erling Smørgrav z = local_zones_find(zones, dname, dname_len, dname_labs, rr_class); 740b5663de9SDag-Erling Smørgrav if(!z) { 741b5663de9SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 742b5663de9SDag-Erling Smørgrav log_err("no local-zone for local-zone-override %s", zname); 743b5663de9SDag-Erling Smørgrav return 0; 744b5663de9SDag-Erling Smørgrav } 745b5663de9SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 746b5663de9SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 747b5663de9SDag-Erling Smørgrav 748b5663de9SDag-Erling Smørgrav /* create netblock addr_tree if not present yet */ 749b5663de9SDag-Erling Smørgrav if(!z->override_tree) { 7503005e0a3SDag-Erling Smørgrav z->override_tree = (struct rbtree_type*)regional_alloc_zero( 751b5663de9SDag-Erling Smørgrav z->region, sizeof(*z->override_tree)); 752b5663de9SDag-Erling Smørgrav if(!z->override_tree) { 753b5663de9SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 754b5663de9SDag-Erling Smørgrav log_err("out of memory"); 755b5663de9SDag-Erling Smørgrav return 0; 756b5663de9SDag-Erling Smørgrav } 757b5663de9SDag-Erling Smørgrav addr_tree_init(z->override_tree); 758b5663de9SDag-Erling Smørgrav } 759b5663de9SDag-Erling Smørgrav /* add new elem to tree */ 760b5663de9SDag-Erling Smørgrav if(z->override_tree) { 761b5663de9SDag-Erling Smørgrav struct local_zone_override* n; 762b5663de9SDag-Erling Smørgrav n = (struct local_zone_override*)regional_alloc_zero( 763b5663de9SDag-Erling Smørgrav z->region, sizeof(*n)); 764b5663de9SDag-Erling Smørgrav if(!n) { 765b5663de9SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 766b5663de9SDag-Erling Smørgrav log_err("out of memory"); 767b5663de9SDag-Erling Smørgrav return 0; 768b5663de9SDag-Erling Smørgrav } 769b5663de9SDag-Erling Smørgrav n->type = t; 770b5663de9SDag-Erling Smørgrav if(!addr_tree_insert(z->override_tree, 771b5663de9SDag-Erling Smørgrav (struct addr_tree_node*)n, &addr, addrlen, net)) { 772b5663de9SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 773b5663de9SDag-Erling Smørgrav log_err("duplicate local-zone-override %s %s", 774b5663de9SDag-Erling Smørgrav zname, netblock); 775b5663de9SDag-Erling Smørgrav return 1; 776b5663de9SDag-Erling Smørgrav } 777b5663de9SDag-Erling Smørgrav } 778b5663de9SDag-Erling Smørgrav 779b5663de9SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 780b5663de9SDag-Erling Smørgrav return 1; 781b5663de9SDag-Erling Smørgrav } 782b5663de9SDag-Erling Smørgrav 783b7579f77SDag-Erling Smørgrav /** parse local-zone: statements */ 784b7579f77SDag-Erling Smørgrav static int 785b7579f77SDag-Erling Smørgrav lz_enter_zones(struct local_zones* zones, struct config_file* cfg) 786b7579f77SDag-Erling Smørgrav { 787b7579f77SDag-Erling Smørgrav struct config_str2list* p; 7885469a995SCy Schubert #ifndef THREADS_DISABLED 789b7579f77SDag-Erling Smørgrav struct local_zone* z; 7905469a995SCy Schubert #endif 791b7579f77SDag-Erling Smørgrav for(p = cfg->local_zones; p; p = p->next) { 7925469a995SCy Schubert if(!( 7935469a995SCy Schubert #ifndef THREADS_DISABLED 7945469a995SCy Schubert z= 7955469a995SCy Schubert #endif 7965469a995SCy Schubert lz_enter_zone(zones, p->str, p->str2, 797b7579f77SDag-Erling Smørgrav LDNS_RR_CLASS_IN))) 798b7579f77SDag-Erling Smørgrav return 0; 799b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 800b7579f77SDag-Erling Smørgrav } 801b7579f77SDag-Erling Smørgrav return 1; 802b7579f77SDag-Erling Smørgrav } 803b7579f77SDag-Erling Smørgrav 804b7579f77SDag-Erling Smørgrav /** lookup a zone in rbtree; exact match only; SLOW due to parse */ 805b7579f77SDag-Erling Smørgrav static int 806b7579f77SDag-Erling Smørgrav lz_exists(struct local_zones* zones, const char* name) 807b7579f77SDag-Erling Smørgrav { 808b7579f77SDag-Erling Smørgrav struct local_zone z; 809b7579f77SDag-Erling Smørgrav z.node.key = &z; 810b7579f77SDag-Erling Smørgrav z.dclass = LDNS_RR_CLASS_IN; 811b7579f77SDag-Erling Smørgrav if(!parse_dname(name, &z.name, &z.namelen, &z.namelabs)) { 812b7579f77SDag-Erling Smørgrav log_err("bad name %s", name); 813b7579f77SDag-Erling Smørgrav return 0; 814b7579f77SDag-Erling Smørgrav } 81517d15b25SDag-Erling Smørgrav lock_rw_rdlock(&zones->lock); 816b7579f77SDag-Erling Smørgrav if(rbtree_search(&zones->ztree, &z.node)) { 81717d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 818b7579f77SDag-Erling Smørgrav free(z.name); 819b7579f77SDag-Erling Smørgrav return 1; 820b7579f77SDag-Erling Smørgrav } 82117d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 822b7579f77SDag-Erling Smørgrav free(z.name); 823b7579f77SDag-Erling Smørgrav return 0; 824b7579f77SDag-Erling Smørgrav } 825b7579f77SDag-Erling Smørgrav 826b7579f77SDag-Erling Smørgrav /** lookup a zone in cfg->nodefault list */ 827b7579f77SDag-Erling Smørgrav static int 828b7579f77SDag-Erling Smørgrav lz_nodefault(struct config_file* cfg, const char* name) 829b7579f77SDag-Erling Smørgrav { 830b7579f77SDag-Erling Smørgrav struct config_strlist* p; 831b7579f77SDag-Erling Smørgrav size_t len = strlen(name); 832b7579f77SDag-Erling Smørgrav if(len == 0) return 0; 833b7579f77SDag-Erling Smørgrav if(name[len-1] == '.') len--; 834b7579f77SDag-Erling Smørgrav 835b7579f77SDag-Erling Smørgrav for(p = cfg->local_zones_nodefault; p; p = p->next) { 836b7579f77SDag-Erling Smørgrav /* compare zone name, lowercase, compare without ending . */ 837b7579f77SDag-Erling Smørgrav if(strncasecmp(p->str, name, len) == 0 && 838b7579f77SDag-Erling Smørgrav (strlen(p->str) == len || (strlen(p->str)==len+1 && 839b7579f77SDag-Erling Smørgrav p->str[len] == '.'))) 840b7579f77SDag-Erling Smørgrav return 1; 841b7579f77SDag-Erling Smørgrav } 842b7579f77SDag-Erling Smørgrav return 0; 843b7579f77SDag-Erling Smørgrav } 844b7579f77SDag-Erling Smørgrav 845971980c3SDag-Erling Smørgrav /** enter (AS112) empty default zone */ 846b7579f77SDag-Erling Smørgrav static int 847971980c3SDag-Erling Smørgrav add_empty_default(struct local_zones* zones, struct config_file* cfg, 84817d15b25SDag-Erling Smørgrav const char* name) 849b7579f77SDag-Erling Smørgrav { 850b7579f77SDag-Erling Smørgrav struct local_zone* z; 851b7579f77SDag-Erling Smørgrav char str[1024]; /* known long enough */ 852b7579f77SDag-Erling Smørgrav if(lz_exists(zones, name) || lz_nodefault(cfg, name)) 853b7579f77SDag-Erling Smørgrav return 1; /* do not enter default content */ 854b7579f77SDag-Erling Smørgrav if(!(z=lz_enter_zone(zones, name, "static", LDNS_RR_CLASS_IN))) 855b7579f77SDag-Erling Smørgrav return 0; 856b7579f77SDag-Erling Smørgrav snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. " 857b7579f77SDag-Erling Smørgrav "nobody.invalid. 1 3600 1200 604800 10800", name); 85817d15b25SDag-Erling Smørgrav if(!lz_enter_rr_into_zone(z, str)) { 859b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 860b7579f77SDag-Erling Smørgrav return 0; 861b7579f77SDag-Erling Smørgrav } 862b7579f77SDag-Erling Smørgrav snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name); 86317d15b25SDag-Erling Smørgrav if(!lz_enter_rr_into_zone(z, str)) { 864b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 865b7579f77SDag-Erling Smørgrav return 0; 866b7579f77SDag-Erling Smørgrav } 867b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 868b7579f77SDag-Erling Smørgrav return 1; 869b7579f77SDag-Erling Smørgrav } 870b7579f77SDag-Erling Smørgrav 871b7579f77SDag-Erling Smørgrav /** enter default zones */ 872c7f4d7adSDag-Erling Smørgrav int local_zone_enter_defaults(struct local_zones* zones, struct config_file* cfg) 873b7579f77SDag-Erling Smørgrav { 874b7579f77SDag-Erling Smørgrav struct local_zone* z; 8750de4f1bfSDag-Erling Smørgrav const char** zstr; 876b7579f77SDag-Erling Smørgrav 877c7f4d7adSDag-Erling Smørgrav /* Do not add any default */ 878c7f4d7adSDag-Erling Smørgrav if(cfg->local_zones_disable_default) 879c7f4d7adSDag-Erling Smørgrav return 1; 880c7f4d7adSDag-Erling Smørgrav 881f61ef7f6SDag-Erling Smørgrav /* this list of zones is from RFC 6303 and RFC 7686 */ 882b7579f77SDag-Erling Smørgrav 883f61ef7f6SDag-Erling Smørgrav /* block localhost level zones first, then onion and later the LAN zones */ 884c536e4dcSDag-Erling Smørgrav 885b7579f77SDag-Erling Smørgrav /* localhost. zone */ 886b7579f77SDag-Erling Smørgrav if(!lz_exists(zones, "localhost.") && 887b7579f77SDag-Erling Smørgrav !lz_nodefault(cfg, "localhost.")) { 888971980c3SDag-Erling Smørgrav if(!(z=lz_enter_zone(zones, "localhost.", "redirect", 889b7579f77SDag-Erling Smørgrav LDNS_RR_CLASS_IN)) || 89017d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 891b7579f77SDag-Erling Smørgrav "localhost. 10800 IN NS localhost.") || 89217d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 893b7579f77SDag-Erling Smørgrav "localhost. 10800 IN SOA localhost. nobody.invalid. " 894b7579f77SDag-Erling Smørgrav "1 3600 1200 604800 10800") || 89517d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 896b7579f77SDag-Erling Smørgrav "localhost. 10800 IN A 127.0.0.1") || 89717d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 898b7579f77SDag-Erling Smørgrav "localhost. 10800 IN AAAA ::1")) { 899b7579f77SDag-Erling Smørgrav log_err("out of memory adding default zone"); 900b7579f77SDag-Erling Smørgrav if(z) { lock_rw_unlock(&z->lock); } 901b7579f77SDag-Erling Smørgrav return 0; 902b7579f77SDag-Erling Smørgrav } 903b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 904b7579f77SDag-Erling Smørgrav } 905b7579f77SDag-Erling Smørgrav /* reverse ip4 zone */ 906b7579f77SDag-Erling Smørgrav if(!lz_exists(zones, "127.in-addr.arpa.") && 907b7579f77SDag-Erling Smørgrav !lz_nodefault(cfg, "127.in-addr.arpa.")) { 908b7579f77SDag-Erling Smørgrav if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static", 909b7579f77SDag-Erling Smørgrav LDNS_RR_CLASS_IN)) || 91017d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 911b7579f77SDag-Erling Smørgrav "127.in-addr.arpa. 10800 IN NS localhost.") || 91217d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 913b7579f77SDag-Erling Smørgrav "127.in-addr.arpa. 10800 IN SOA localhost. " 914b7579f77SDag-Erling Smørgrav "nobody.invalid. 1 3600 1200 604800 10800") || 91517d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 916b7579f77SDag-Erling Smørgrav "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) { 917b7579f77SDag-Erling Smørgrav log_err("out of memory adding default zone"); 918b7579f77SDag-Erling Smørgrav if(z) { lock_rw_unlock(&z->lock); } 919b7579f77SDag-Erling Smørgrav return 0; 920b7579f77SDag-Erling Smørgrav } 921b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 922b7579f77SDag-Erling Smørgrav } 923b7579f77SDag-Erling Smørgrav /* reverse ip6 zone */ 924b7579f77SDag-Erling Smørgrav 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.") && 925b7579f77SDag-Erling Smørgrav !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.")) { 926b7579f77SDag-Erling Smørgrav 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", 927b7579f77SDag-Erling Smørgrav LDNS_RR_CLASS_IN)) || 92817d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 929b7579f77SDag-Erling Smørgrav "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.") || 93017d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 931b7579f77SDag-Erling Smørgrav "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. " 932b7579f77SDag-Erling Smørgrav "nobody.invalid. 1 3600 1200 604800 10800") || 93317d15b25SDag-Erling Smørgrav !lz_enter_rr_into_zone(z, 934b7579f77SDag-Erling Smørgrav "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.")) { 935b7579f77SDag-Erling Smørgrav log_err("out of memory adding default zone"); 936b7579f77SDag-Erling Smørgrav if(z) { lock_rw_unlock(&z->lock); } 937b7579f77SDag-Erling Smørgrav return 0; 938b7579f77SDag-Erling Smørgrav } 939b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 940b7579f77SDag-Erling Smørgrav } 94124e36522SCy Schubert /* home.arpa. zone (RFC 8375) */ 94224e36522SCy Schubert if(!add_empty_default(zones, cfg, "home.arpa.")) { 94324e36522SCy Schubert log_err("out of memory adding default zone"); 94424e36522SCy Schubert return 0; 94524e36522SCy Schubert } 946*be771a7bSCy Schubert /* resolver.arpa. zone (RFC 9462) */ 947*be771a7bSCy Schubert if(!add_empty_default(zones, cfg, "resolver.arpa.")) { 948*be771a7bSCy Schubert log_err("out of memory adding default zone"); 949*be771a7bSCy Schubert return 0; 950*be771a7bSCy Schubert } 951*be771a7bSCy Schubert /* service.arpa. zone (draft-ietf-dnssd-srp-25) */ 952*be771a7bSCy Schubert if(!add_empty_default(zones, cfg, "service.arpa.")) { 953*be771a7bSCy Schubert log_err("out of memory adding default zone"); 954*be771a7bSCy Schubert return 0; 955*be771a7bSCy Schubert } 956f61ef7f6SDag-Erling Smørgrav /* onion. zone (RFC 7686) */ 957971980c3SDag-Erling Smørgrav if(!add_empty_default(zones, cfg, "onion.")) { 958f61ef7f6SDag-Erling Smørgrav log_err("out of memory adding default zone"); 959f61ef7f6SDag-Erling Smørgrav return 0; 960f61ef7f6SDag-Erling Smørgrav } 961091e9e46SCy Schubert /* test. zone (RFC 6761) */ 962971980c3SDag-Erling Smørgrav if(!add_empty_default(zones, cfg, "test.")) { 963971980c3SDag-Erling Smørgrav log_err("out of memory adding default zone"); 964971980c3SDag-Erling Smørgrav return 0; 965f61ef7f6SDag-Erling Smørgrav } 966091e9e46SCy Schubert /* invalid. zone (RFC 6761) */ 967971980c3SDag-Erling Smørgrav if(!add_empty_default(zones, cfg, "invalid.")) { 968971980c3SDag-Erling Smørgrav log_err("out of memory adding default zone"); 969971980c3SDag-Erling Smørgrav return 0; 970971980c3SDag-Erling Smørgrav } 9710de4f1bfSDag-Erling Smørgrav /* block AS112 zones, unless asked not to */ 9720de4f1bfSDag-Erling Smørgrav if(!cfg->unblock_lan_zones) { 9730de4f1bfSDag-Erling Smørgrav for(zstr = as112_zones; *zstr; zstr++) { 974971980c3SDag-Erling Smørgrav if(!add_empty_default(zones, cfg, *zstr)) { 975b7579f77SDag-Erling Smørgrav log_err("out of memory adding default zone"); 976b7579f77SDag-Erling Smørgrav return 0; 977b7579f77SDag-Erling Smørgrav } 9780de4f1bfSDag-Erling Smørgrav } 9790de4f1bfSDag-Erling Smørgrav } 980b7579f77SDag-Erling Smørgrav return 1; 981b7579f77SDag-Erling Smørgrav } 982b7579f77SDag-Erling Smørgrav 983b5663de9SDag-Erling Smørgrav /** parse local-zone-override: statements */ 984b5663de9SDag-Erling Smørgrav static int 985b5663de9SDag-Erling Smørgrav lz_enter_overrides(struct local_zones* zones, struct config_file* cfg) 986b5663de9SDag-Erling Smørgrav { 987b5663de9SDag-Erling Smørgrav struct config_str3list* p; 988b5663de9SDag-Erling Smørgrav for(p = cfg->local_zone_overrides; p; p = p->next) { 989b5663de9SDag-Erling Smørgrav if(!lz_enter_override(zones, p->str, p->str2, p->str3, 990b5663de9SDag-Erling Smørgrav LDNS_RR_CLASS_IN)) 991b5663de9SDag-Erling Smørgrav return 0; 992b5663de9SDag-Erling Smørgrav } 993b5663de9SDag-Erling Smørgrav return 1; 994b5663de9SDag-Erling Smørgrav } 995b5663de9SDag-Erling Smørgrav 99656850988SCy Schubert /* return closest parent in the tree, NULL if none */ 99756850988SCy Schubert static struct local_zone* find_closest_parent(struct local_zone* curr, 99856850988SCy Schubert struct local_zone* prev) 999b7579f77SDag-Erling Smørgrav { 100056850988SCy Schubert struct local_zone* p; 1001b7579f77SDag-Erling Smørgrav int m; 100256850988SCy Schubert if(!prev || prev->dclass != curr->dclass) return NULL; 100356850988SCy Schubert (void)dname_lab_cmp(prev->name, prev->namelabs, curr->name, 100456850988SCy Schubert curr->namelabs, &m); /* we know prev is smaller */ 1005b7579f77SDag-Erling Smørgrav /* sort order like: . com. bla.com. zwb.com. net. */ 1006b7579f77SDag-Erling Smørgrav /* find the previous, or parent-parent-parent */ 100756850988SCy Schubert for(p = prev; p; p = p->parent) { 1008b7579f77SDag-Erling Smørgrav /* looking for name with few labels, a parent */ 1009b7579f77SDag-Erling Smørgrav if(p->namelabs <= m) { 1010b7579f77SDag-Erling Smørgrav /* ==: since prev matched m, this is closest*/ 1011b7579f77SDag-Erling Smørgrav /* <: prev matches more, but is not a parent, 1012b7579f77SDag-Erling Smørgrav * this one is a (grand)parent */ 101356850988SCy Schubert return p; 1014b7579f77SDag-Erling Smørgrav } 101556850988SCy Schubert } 101656850988SCy Schubert return NULL; 101756850988SCy Schubert } 1018b5663de9SDag-Erling Smørgrav 101956850988SCy Schubert /** setup parent pointers, so that a lookup can be done for closest match */ 102056850988SCy Schubert void 102156850988SCy Schubert lz_init_parents(struct local_zones* zones) 102256850988SCy Schubert { 102356850988SCy Schubert struct local_zone* node, *prev = NULL; 102456850988SCy Schubert lock_rw_wrlock(&zones->lock); 102556850988SCy Schubert RBTREE_FOR(node, struct local_zone*, &zones->ztree) { 102656850988SCy Schubert lock_rw_wrlock(&node->lock); 102756850988SCy Schubert node->parent = find_closest_parent(node, prev); 102856850988SCy Schubert prev = node; 1029b5663de9SDag-Erling Smørgrav if(node->override_tree) 1030b5663de9SDag-Erling Smørgrav addr_tree_init_parents(node->override_tree); 1031b7579f77SDag-Erling Smørgrav lock_rw_unlock(&node->lock); 1032b7579f77SDag-Erling Smørgrav } 103317d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 1034b7579f77SDag-Erling Smørgrav } 1035b7579f77SDag-Erling Smørgrav 1036b7579f77SDag-Erling Smørgrav /** enter implicit transparent zone for local-data: without local-zone: */ 1037b7579f77SDag-Erling Smørgrav static int 1038b7579f77SDag-Erling Smørgrav lz_setup_implicit(struct local_zones* zones, struct config_file* cfg) 1039b7579f77SDag-Erling Smørgrav { 1040b7579f77SDag-Erling Smørgrav /* walk over all items that have no parent zone and find 1041b7579f77SDag-Erling Smørgrav * the name that covers them all (could be the root) and 1042b7579f77SDag-Erling Smørgrav * add that as a transparent zone */ 1043b7579f77SDag-Erling Smørgrav struct config_strlist* p; 1044b7579f77SDag-Erling Smørgrav int have_name = 0; 1045b7579f77SDag-Erling Smørgrav int have_other_classes = 0; 1046b7579f77SDag-Erling Smørgrav uint16_t dclass = 0; 1047b7579f77SDag-Erling Smørgrav uint8_t* nm = 0; 1048b7579f77SDag-Erling Smørgrav size_t nmlen = 0; 1049b7579f77SDag-Erling Smørgrav int nmlabs = 0; 1050b7579f77SDag-Erling Smørgrav int match = 0; /* number of labels match count */ 1051b7579f77SDag-Erling Smørgrav 105256850988SCy Schubert lz_init_parents(zones); /* to enable local_zones_lookup() */ 1053b7579f77SDag-Erling Smørgrav for(p = cfg->local_data; p; p = p->next) { 1054b7579f77SDag-Erling Smørgrav uint8_t* rr_name; 1055971980c3SDag-Erling Smørgrav uint16_t rr_class, rr_type; 1056b7579f77SDag-Erling Smørgrav size_t len; 1057b7579f77SDag-Erling Smørgrav int labs; 1058971980c3SDag-Erling Smørgrav if(!get_rr_nameclass(p->str, &rr_name, &rr_class, &rr_type)) { 1059b7579f77SDag-Erling Smørgrav log_err("Bad local-data RR %s", p->str); 1060b7579f77SDag-Erling Smørgrav return 0; 1061b7579f77SDag-Erling Smørgrav } 1062b7579f77SDag-Erling Smørgrav labs = dname_count_size_labels(rr_name, &len); 106317d15b25SDag-Erling Smørgrav lock_rw_rdlock(&zones->lock); 1064971980c3SDag-Erling Smørgrav if(!local_zones_lookup(zones, rr_name, len, labs, rr_class, 1065971980c3SDag-Erling Smørgrav rr_type)) { 10669cf5bc93SCy Schubert /* Check if there is a zone that this could go 10679cf5bc93SCy Schubert * under but for different class; created zones are 10689cf5bc93SCy Schubert * always for LDNS_RR_CLASS_IN. Create the zone with 10699cf5bc93SCy Schubert * a different class but the same configured 10709cf5bc93SCy Schubert * local_zone_type. */ 10719cf5bc93SCy Schubert struct local_zone* z = local_zones_lookup(zones, 10729cf5bc93SCy Schubert rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type); 10739cf5bc93SCy Schubert if(z) { 10749cf5bc93SCy Schubert uint8_t* name = memdup(z->name, z->namelen); 10759cf5bc93SCy Schubert size_t znamelen = z->namelen; 10769cf5bc93SCy Schubert int znamelabs = z->namelabs; 10779cf5bc93SCy Schubert enum localzone_type ztype = z->type; 10789cf5bc93SCy Schubert lock_rw_unlock(&zones->lock); 10799cf5bc93SCy Schubert if(!name) { 10809cf5bc93SCy Schubert log_err("out of memory"); 10819cf5bc93SCy Schubert free(rr_name); 10829cf5bc93SCy Schubert return 0; 10839cf5bc93SCy Schubert } 10849cf5bc93SCy Schubert if(!( 10859cf5bc93SCy Schubert #ifndef THREADS_DISABLED 10869cf5bc93SCy Schubert z = 10879cf5bc93SCy Schubert #endif 10889cf5bc93SCy Schubert lz_enter_zone_dname(zones, name, 10899cf5bc93SCy Schubert znamelen, znamelabs, 10909cf5bc93SCy Schubert ztype, rr_class))) { 10919cf5bc93SCy Schubert free(rr_name); 10929cf5bc93SCy Schubert return 0; 10939cf5bc93SCy Schubert } 10949cf5bc93SCy Schubert lock_rw_unlock(&z->lock); 10959cf5bc93SCy Schubert free(rr_name); 10969cf5bc93SCy Schubert continue; 10979cf5bc93SCy Schubert } 1098b7579f77SDag-Erling Smørgrav if(!have_name) { 1099b7579f77SDag-Erling Smørgrav dclass = rr_class; 1100b7579f77SDag-Erling Smørgrav nm = rr_name; 1101b7579f77SDag-Erling Smørgrav nmlen = len; 1102b7579f77SDag-Erling Smørgrav nmlabs = labs; 1103b7579f77SDag-Erling Smørgrav match = labs; 1104b7579f77SDag-Erling Smørgrav have_name = 1; 1105b7579f77SDag-Erling Smørgrav } else { 1106b7579f77SDag-Erling Smørgrav int m; 1107b7579f77SDag-Erling Smørgrav if(rr_class != dclass) { 1108b7579f77SDag-Erling Smørgrav /* process other classes later */ 1109b7579f77SDag-Erling Smørgrav free(rr_name); 1110b7579f77SDag-Erling Smørgrav have_other_classes = 1; 111117d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 1112b7579f77SDag-Erling Smørgrav continue; 1113b7579f77SDag-Erling Smørgrav } 1114b7579f77SDag-Erling Smørgrav /* find smallest shared topdomain */ 1115b7579f77SDag-Erling Smørgrav (void)dname_lab_cmp(nm, nmlabs, 1116b7579f77SDag-Erling Smørgrav rr_name, labs, &m); 1117b7579f77SDag-Erling Smørgrav free(rr_name); 1118b7579f77SDag-Erling Smørgrav if(m < match) 1119b7579f77SDag-Erling Smørgrav match = m; 1120b7579f77SDag-Erling Smørgrav } 1121b7579f77SDag-Erling Smørgrav } else free(rr_name); 112217d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 1123b7579f77SDag-Erling Smørgrav } 1124b7579f77SDag-Erling Smørgrav if(have_name) { 1125b7579f77SDag-Erling Smørgrav uint8_t* n2; 11265469a995SCy Schubert #ifndef THREADS_DISABLED 1127b7579f77SDag-Erling Smørgrav struct local_zone* z; 11285469a995SCy Schubert #endif 1129b7579f77SDag-Erling Smørgrav /* allocate zone of smallest shared topdomain to contain em */ 1130b7579f77SDag-Erling Smørgrav n2 = nm; 1131b7579f77SDag-Erling Smørgrav dname_remove_labels(&n2, &nmlen, nmlabs - match); 1132b7579f77SDag-Erling Smørgrav n2 = memdup(n2, nmlen); 1133b7579f77SDag-Erling Smørgrav free(nm); 1134b7579f77SDag-Erling Smørgrav if(!n2) { 1135b7579f77SDag-Erling Smørgrav log_err("out of memory"); 1136b7579f77SDag-Erling Smørgrav return 0; 1137b7579f77SDag-Erling Smørgrav } 1138b7579f77SDag-Erling Smørgrav log_nametypeclass(VERB_ALGO, "implicit transparent local-zone", 1139b7579f77SDag-Erling Smørgrav n2, 0, dclass); 11405469a995SCy Schubert if(!( 11415469a995SCy Schubert #ifndef THREADS_DISABLED 11425469a995SCy Schubert z= 11435469a995SCy Schubert #endif 11445469a995SCy Schubert lz_enter_zone_dname(zones, n2, nmlen, match, 1145b7579f77SDag-Erling Smørgrav local_zone_transparent, dclass))) { 1146b7579f77SDag-Erling Smørgrav return 0; 1147b7579f77SDag-Erling Smørgrav } 1148b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 1149b7579f77SDag-Erling Smørgrav } 1150b7579f77SDag-Erling Smørgrav if(have_other_classes) { 1151b7579f77SDag-Erling Smørgrav /* restart to setup other class */ 1152b7579f77SDag-Erling Smørgrav return lz_setup_implicit(zones, cfg); 1153b7579f77SDag-Erling Smørgrav } 1154b7579f77SDag-Erling Smørgrav return 1; 1155b7579f77SDag-Erling Smørgrav } 1156b7579f77SDag-Erling Smørgrav 1157e2d15004SDag-Erling Smørgrav /** enter local-zone-tag info */ 1158e2d15004SDag-Erling Smørgrav static int 1159e2d15004SDag-Erling Smørgrav lz_enter_zone_tags(struct local_zones* zones, struct config_file* cfg) 1160e2d15004SDag-Erling Smørgrav { 1161e2d15004SDag-Erling Smørgrav struct config_strbytelist* p; 1162e2d15004SDag-Erling Smørgrav int c = 0; 1163e2d15004SDag-Erling Smørgrav for(p = cfg->local_zone_tags; p; p = p->next) { 1164e2d15004SDag-Erling Smørgrav if(!lz_enter_zone_tag(zones, p->str, p->str2, p->str2len, 1165e2d15004SDag-Erling Smørgrav LDNS_RR_CLASS_IN)) 1166e2d15004SDag-Erling Smørgrav return 0; 1167e2d15004SDag-Erling Smørgrav c++; 1168e2d15004SDag-Erling Smørgrav } 1169e2d15004SDag-Erling Smørgrav if(c) verbose(VERB_ALGO, "applied tags to %d local zones", c); 1170e2d15004SDag-Erling Smørgrav return 1; 1171e2d15004SDag-Erling Smørgrav } 1172e2d15004SDag-Erling Smørgrav 1173b7579f77SDag-Erling Smørgrav /** enter auth data */ 1174b7579f77SDag-Erling Smørgrav static int 117517d15b25SDag-Erling Smørgrav lz_enter_data(struct local_zones* zones, struct config_file* cfg) 1176b7579f77SDag-Erling Smørgrav { 1177b7579f77SDag-Erling Smørgrav struct config_strlist* p; 1178b7579f77SDag-Erling Smørgrav for(p = cfg->local_data; p; p = p->next) { 117917d15b25SDag-Erling Smørgrav if(!lz_enter_rr_str(zones, p->str)) 1180b7579f77SDag-Erling Smørgrav return 0; 1181b7579f77SDag-Erling Smørgrav } 1182b7579f77SDag-Erling Smørgrav return 1; 1183b7579f77SDag-Erling Smørgrav } 1184b7579f77SDag-Erling Smørgrav 1185b7579f77SDag-Erling Smørgrav /** free memory from config */ 1186b7579f77SDag-Erling Smørgrav static void 1187b7579f77SDag-Erling Smørgrav lz_freeup_cfg(struct config_file* cfg) 1188b7579f77SDag-Erling Smørgrav { 1189b7579f77SDag-Erling Smørgrav config_deldblstrlist(cfg->local_zones); 1190b7579f77SDag-Erling Smørgrav cfg->local_zones = NULL; 1191b7579f77SDag-Erling Smørgrav config_delstrlist(cfg->local_zones_nodefault); 1192b7579f77SDag-Erling Smørgrav cfg->local_zones_nodefault = NULL; 1193b7579f77SDag-Erling Smørgrav config_delstrlist(cfg->local_data); 1194b7579f77SDag-Erling Smørgrav cfg->local_data = NULL; 1195b7579f77SDag-Erling Smørgrav } 1196b7579f77SDag-Erling Smørgrav 1197b7579f77SDag-Erling Smørgrav int 1198b7579f77SDag-Erling Smørgrav local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg) 1199b7579f77SDag-Erling Smørgrav { 1200b7579f77SDag-Erling Smørgrav /* create zones from zone statements. */ 1201b7579f77SDag-Erling Smørgrav if(!lz_enter_zones(zones, cfg)) { 1202b7579f77SDag-Erling Smørgrav return 0; 1203b7579f77SDag-Erling Smørgrav } 1204b7579f77SDag-Erling Smørgrav /* apply default zones+content (unless disabled, or overridden) */ 1205c7f4d7adSDag-Erling Smørgrav if(!local_zone_enter_defaults(zones, cfg)) { 1206b7579f77SDag-Erling Smørgrav return 0; 1207b7579f77SDag-Erling Smørgrav } 1208b5663de9SDag-Erling Smørgrav /* enter local zone overrides */ 1209b5663de9SDag-Erling Smørgrav if(!lz_enter_overrides(zones, cfg)) { 1210b5663de9SDag-Erling Smørgrav return 0; 1211b5663de9SDag-Erling Smørgrav } 1212b7579f77SDag-Erling Smørgrav /* create implicit transparent zone from data. */ 1213b7579f77SDag-Erling Smørgrav if(!lz_setup_implicit(zones, cfg)) { 1214b7579f77SDag-Erling Smørgrav return 0; 1215b7579f77SDag-Erling Smørgrav } 1216b7579f77SDag-Erling Smørgrav 1217b7579f77SDag-Erling Smørgrav /* setup parent ptrs for lookup during data entry */ 121856850988SCy Schubert lz_init_parents(zones); 1219e2d15004SDag-Erling Smørgrav /* insert local zone tags */ 1220e2d15004SDag-Erling Smørgrav if(!lz_enter_zone_tags(zones, cfg)) { 1221e2d15004SDag-Erling Smørgrav return 0; 1222e2d15004SDag-Erling Smørgrav } 1223b7579f77SDag-Erling Smørgrav /* insert local data */ 122417d15b25SDag-Erling Smørgrav if(!lz_enter_data(zones, cfg)) { 1225b7579f77SDag-Erling Smørgrav return 0; 1226b7579f77SDag-Erling Smørgrav } 1227b7579f77SDag-Erling Smørgrav /* freeup memory from cfg struct. */ 1228b7579f77SDag-Erling Smørgrav lz_freeup_cfg(cfg); 1229b7579f77SDag-Erling Smørgrav return 1; 1230b7579f77SDag-Erling Smørgrav } 1231b7579f77SDag-Erling Smørgrav 1232b7579f77SDag-Erling Smørgrav struct local_zone* 1233b7579f77SDag-Erling Smørgrav local_zones_lookup(struct local_zones* zones, 1234971980c3SDag-Erling Smørgrav uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype) 1235b7579f77SDag-Erling Smørgrav { 1236b5663de9SDag-Erling Smørgrav return local_zones_tags_lookup(zones, name, len, labs, 1237971980c3SDag-Erling Smørgrav dclass, dtype, NULL, 0, 1); 1238b5663de9SDag-Erling Smørgrav } 1239b5663de9SDag-Erling Smørgrav 1240b5663de9SDag-Erling Smørgrav struct local_zone* 1241b5663de9SDag-Erling Smørgrav local_zones_tags_lookup(struct local_zones* zones, 1242971980c3SDag-Erling Smørgrav uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype, 1243b5663de9SDag-Erling Smørgrav uint8_t* taglist, size_t taglen, int ignoretags) 1244b5663de9SDag-Erling Smørgrav { 12453005e0a3SDag-Erling Smørgrav rbnode_type* res = NULL; 1246b7579f77SDag-Erling Smørgrav struct local_zone *result; 1247b7579f77SDag-Erling Smørgrav struct local_zone key; 1248b5663de9SDag-Erling Smørgrav int m; 1249971980c3SDag-Erling Smørgrav /* for type DS use a zone higher when on a zonecut */ 1250971980c3SDag-Erling Smørgrav if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) { 1251971980c3SDag-Erling Smørgrav dname_remove_label(&name, &len); 1252971980c3SDag-Erling Smørgrav labs--; 1253971980c3SDag-Erling Smørgrav } 1254b7579f77SDag-Erling Smørgrav key.node.key = &key; 1255b7579f77SDag-Erling Smørgrav key.dclass = dclass; 1256b7579f77SDag-Erling Smørgrav key.name = name; 1257b7579f77SDag-Erling Smørgrav key.namelen = len; 1258b7579f77SDag-Erling Smørgrav key.namelabs = labs; 1259b5663de9SDag-Erling Smørgrav rbtree_find_less_equal(&zones->ztree, &key, &res); 1260b7579f77SDag-Erling Smørgrav result = (struct local_zone*)res; 1261b5663de9SDag-Erling Smørgrav /* exact or smaller element (or no element) */ 1262b7579f77SDag-Erling Smørgrav if(!result || result->dclass != dclass) 1263b7579f77SDag-Erling Smørgrav return NULL; 1264b7579f77SDag-Erling Smørgrav /* count number of labels matched */ 1265b7579f77SDag-Erling Smørgrav (void)dname_lab_cmp(result->name, result->namelabs, key.name, 1266b7579f77SDag-Erling Smørgrav key.namelabs, &m); 1267b5663de9SDag-Erling Smørgrav while(result) { /* go up until qname is zone or subdomain of zone */ 1268b7579f77SDag-Erling Smørgrav if(result->namelabs <= m) 1269b5663de9SDag-Erling Smørgrav if(ignoretags || !result->taglist || 1270b5663de9SDag-Erling Smørgrav taglist_intersect(result->taglist, 1271b5663de9SDag-Erling Smørgrav result->taglen, taglist, taglen)) 1272b7579f77SDag-Erling Smørgrav break; 1273b7579f77SDag-Erling Smørgrav result = result->parent; 1274b7579f77SDag-Erling Smørgrav } 1275b7579f77SDag-Erling Smørgrav return result; 1276b7579f77SDag-Erling Smørgrav } 1277b7579f77SDag-Erling Smørgrav 1278b7579f77SDag-Erling Smørgrav struct local_zone* 1279b7579f77SDag-Erling Smørgrav local_zones_find(struct local_zones* zones, 1280b7579f77SDag-Erling Smørgrav uint8_t* name, size_t len, int labs, uint16_t dclass) 1281b7579f77SDag-Erling Smørgrav { 1282b7579f77SDag-Erling Smørgrav struct local_zone key; 1283b7579f77SDag-Erling Smørgrav key.node.key = &key; 1284b7579f77SDag-Erling Smørgrav key.dclass = dclass; 1285b7579f77SDag-Erling Smørgrav key.name = name; 1286b7579f77SDag-Erling Smørgrav key.namelen = len; 1287b7579f77SDag-Erling Smørgrav key.namelabs = labs; 1288b7579f77SDag-Erling Smørgrav /* exact */ 1289b7579f77SDag-Erling Smørgrav return (struct local_zone*)rbtree_search(&zones->ztree, &key); 1290b7579f77SDag-Erling Smørgrav } 1291b7579f77SDag-Erling Smørgrav 1292091e9e46SCy Schubert struct local_zone* 1293091e9e46SCy Schubert local_zones_find_le(struct local_zones* zones, 1294091e9e46SCy Schubert uint8_t* name, size_t len, int labs, uint16_t dclass, 1295091e9e46SCy Schubert int* exact) 1296091e9e46SCy Schubert { 1297091e9e46SCy Schubert struct local_zone key; 1298091e9e46SCy Schubert rbnode_type *node; 1299091e9e46SCy Schubert key.node.key = &key; 1300091e9e46SCy Schubert key.dclass = dclass; 1301091e9e46SCy Schubert key.name = name; 1302091e9e46SCy Schubert key.namelen = len; 1303091e9e46SCy Schubert key.namelabs = labs; 1304091e9e46SCy Schubert *exact = rbtree_find_less_equal(&zones->ztree, &key, &node); 1305091e9e46SCy Schubert return (struct local_zone*)node; 1306091e9e46SCy Schubert } 1307091e9e46SCy Schubert 1308b7579f77SDag-Erling Smørgrav /** encode answer consisting of 1 rrset */ 1309b7579f77SDag-Erling Smørgrav static int 1310bc892140SDag-Erling Smørgrav local_encode(struct query_info* qinfo, struct module_env* env, 13114c75e3aaSDag-Erling Smørgrav struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, 13124c75e3aaSDag-Erling Smørgrav struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec, 13134c75e3aaSDag-Erling Smørgrav int rcode) 1314b7579f77SDag-Erling Smørgrav { 1315b7579f77SDag-Erling Smørgrav struct reply_info rep; 1316b7579f77SDag-Erling Smørgrav uint16_t udpsize; 1317b7579f77SDag-Erling Smørgrav /* make answer with time=0 for fixed TTL values */ 1318b7579f77SDag-Erling Smørgrav memset(&rep, 0, sizeof(rep)); 1319b7579f77SDag-Erling Smørgrav rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode); 1320b7579f77SDag-Erling Smørgrav rep.qdcount = 1; 1321b7579f77SDag-Erling Smørgrav if(ansec) 1322b7579f77SDag-Erling Smørgrav rep.an_numrrsets = 1; 1323b7579f77SDag-Erling Smørgrav else rep.ns_numrrsets = 1; 1324b7579f77SDag-Erling Smørgrav rep.rrset_count = 1; 1325b7579f77SDag-Erling Smørgrav rep.rrsets = &rrset; 13268f76bb7dSCy Schubert rep.reason_bogus = LDNS_EDE_NONE; 1327b7579f77SDag-Erling Smørgrav udpsize = edns->udp_size; 1328b7579f77SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 1329b7579f77SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 1330b7579f77SDag-Erling Smørgrav edns->ext_rcode = 0; 1331b7579f77SDag-Erling Smørgrav edns->bits &= EDNS_DO; 13324c75e3aaSDag-Erling Smørgrav if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns, 1333f44e67d1SCy Schubert repinfo, temp, env->now_tv) || !reply_info_answer_encode(qinfo, &rep, 13344c75e3aaSDag-Erling Smørgrav *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), 13354c75e3aaSDag-Erling Smørgrav buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) { 1336b7579f77SDag-Erling Smørgrav error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo, 133717d15b25SDag-Erling Smørgrav *(uint16_t*)sldns_buffer_begin(buf), 133817d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(buf, 2), edns); 13394c75e3aaSDag-Erling Smørgrav } 1340b7579f77SDag-Erling Smørgrav return 1; 1341b7579f77SDag-Erling Smørgrav } 1342b7579f77SDag-Erling Smørgrav 13433005e0a3SDag-Erling Smørgrav /** encode local error answer */ 13443005e0a3SDag-Erling Smørgrav static void 13453005e0a3SDag-Erling Smørgrav local_error_encode(struct query_info* qinfo, struct module_env* env, 13464c75e3aaSDag-Erling Smørgrav struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, 1347a39a5a69SCy Schubert struct regional* temp, int rcode, int r, int ede_code, 1348a39a5a69SCy Schubert const char* ede_txt) 13493005e0a3SDag-Erling Smørgrav { 13503005e0a3SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 13513005e0a3SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 13523005e0a3SDag-Erling Smørgrav edns->ext_rcode = 0; 13533005e0a3SDag-Erling Smørgrav edns->bits &= EDNS_DO; 13543005e0a3SDag-Erling Smørgrav 13553005e0a3SDag-Erling Smørgrav if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, 1356f44e67d1SCy Schubert rcode, edns, repinfo, temp, env->now_tv)) 135724e36522SCy Schubert edns->opt_list_inplace_cb_out = NULL; 1358a39a5a69SCy Schubert 1359a39a5a69SCy Schubert if(ede_code != LDNS_EDE_NONE && env->cfg->ede) { 1360a39a5a69SCy Schubert edns_opt_list_append_ede(&edns->opt_list_out, temp, 1361a39a5a69SCy Schubert ede_code, ede_txt); 1362a39a5a69SCy Schubert } 1363a39a5a69SCy Schubert 13643005e0a3SDag-Erling Smørgrav error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf), 13653005e0a3SDag-Erling Smørgrav sldns_buffer_read_u16_at(buf, 2), edns); 13663005e0a3SDag-Erling Smørgrav } 13673005e0a3SDag-Erling Smørgrav 1368b5663de9SDag-Erling Smørgrav /** find local data tag string match for the given type in the list */ 136965b390aaSDag-Erling Smørgrav int 137065b390aaSDag-Erling Smørgrav local_data_find_tag_datas(const struct query_info* qinfo, 137165b390aaSDag-Erling Smørgrav struct config_strlist* list, struct ub_packed_rrset_key* r, 137265b390aaSDag-Erling Smørgrav struct regional* temp) 1373b5663de9SDag-Erling Smørgrav { 1374b5663de9SDag-Erling Smørgrav struct config_strlist* p; 1375b5663de9SDag-Erling Smørgrav char buf[65536]; 1376b5663de9SDag-Erling Smørgrav uint8_t rr[LDNS_RR_BUF_SIZE]; 1377b5663de9SDag-Erling Smørgrav size_t len; 1378b5663de9SDag-Erling Smørgrav int res; 1379b5663de9SDag-Erling Smørgrav struct packed_rrset_data* d; 1380b5663de9SDag-Erling Smørgrav for(p=list; p; p=p->next) { 1381bc892140SDag-Erling Smørgrav uint16_t rdr_type; 1382bc892140SDag-Erling Smørgrav 1383b5663de9SDag-Erling Smørgrav len = sizeof(rr); 1384b5663de9SDag-Erling Smørgrav /* does this element match the type? */ 1385b5663de9SDag-Erling Smørgrav snprintf(buf, sizeof(buf), ". %s", p->str); 1386b5663de9SDag-Erling Smørgrav res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, 1387bc892140SDag-Erling Smørgrav NULL, 0, NULL, 0); 1388b5663de9SDag-Erling Smørgrav if(res != 0) 1389b5663de9SDag-Erling Smørgrav /* parse errors are already checked before, in 1390b5663de9SDag-Erling Smørgrav * acllist check_data, skip this for robustness */ 1391b5663de9SDag-Erling Smørgrav continue; 1392b5663de9SDag-Erling Smørgrav if(len < 1 /* . */ + 8 /* typeclassttl*/ + 2 /*rdatalen*/) 1393b5663de9SDag-Erling Smørgrav continue; 1394bc892140SDag-Erling Smørgrav rdr_type = sldns_wirerr_get_type(rr, len, 1); 1395bc892140SDag-Erling Smørgrav if(rdr_type != qinfo->qtype && rdr_type != LDNS_RR_TYPE_CNAME) 1396b5663de9SDag-Erling Smørgrav continue; 1397b5663de9SDag-Erling Smørgrav 1398b5663de9SDag-Erling Smørgrav /* do we have entries already? if not setup key */ 1399b5663de9SDag-Erling Smørgrav if(r->rk.dname == NULL) { 1400b5663de9SDag-Erling Smørgrav r->entry.key = r; 1401b5663de9SDag-Erling Smørgrav r->rk.dname = qinfo->qname; 1402b5663de9SDag-Erling Smørgrav r->rk.dname_len = qinfo->qname_len; 1403bc892140SDag-Erling Smørgrav r->rk.type = htons(rdr_type); 1404b5663de9SDag-Erling Smørgrav r->rk.rrset_class = htons(qinfo->qclass); 1405b5663de9SDag-Erling Smørgrav r->rk.flags = 0; 1406b5663de9SDag-Erling Smørgrav d = (struct packed_rrset_data*)regional_alloc_zero( 1407b5663de9SDag-Erling Smørgrav temp, sizeof(struct packed_rrset_data) 1408b5663de9SDag-Erling Smørgrav + sizeof(size_t) + sizeof(uint8_t*) + 1409b5663de9SDag-Erling Smørgrav sizeof(time_t)); 1410b5663de9SDag-Erling Smørgrav if(!d) return 0; /* out of memory */ 1411b5663de9SDag-Erling Smørgrav r->entry.data = d; 1412b5663de9SDag-Erling Smørgrav d->ttl = sldns_wirerr_get_ttl(rr, len, 1); 1413b5663de9SDag-Erling Smørgrav d->rr_len = (size_t*)((uint8_t*)d + 1414b5663de9SDag-Erling Smørgrav sizeof(struct packed_rrset_data)); 1415b5663de9SDag-Erling Smørgrav d->rr_data = (uint8_t**)&(d->rr_len[1]); 1416b5663de9SDag-Erling Smørgrav d->rr_ttl = (time_t*)&(d->rr_data[1]); 1417b5663de9SDag-Erling Smørgrav } 1418b5663de9SDag-Erling Smørgrav d = (struct packed_rrset_data*)r->entry.data; 1419b5663de9SDag-Erling Smørgrav /* add entry to the data */ 1420b5663de9SDag-Erling Smørgrav if(d->count != 0) { 1421b5663de9SDag-Erling Smørgrav size_t* oldlen = d->rr_len; 1422b5663de9SDag-Erling Smørgrav uint8_t** olddata = d->rr_data; 1423b5663de9SDag-Erling Smørgrav time_t* oldttl = d->rr_ttl; 1424b5663de9SDag-Erling Smørgrav /* increase arrays for lookup */ 1425b5663de9SDag-Erling Smørgrav /* this is of course slow for very many records, 1426b5663de9SDag-Erling Smørgrav * but most redirects are expected with few records */ 1427b5663de9SDag-Erling Smørgrav d->rr_len = (size_t*)regional_alloc_zero(temp, 1428b5663de9SDag-Erling Smørgrav (d->count+1)*sizeof(size_t)); 1429b5663de9SDag-Erling Smørgrav d->rr_data = (uint8_t**)regional_alloc_zero(temp, 1430b5663de9SDag-Erling Smørgrav (d->count+1)*sizeof(uint8_t*)); 1431b5663de9SDag-Erling Smørgrav d->rr_ttl = (time_t*)regional_alloc_zero(temp, 1432b5663de9SDag-Erling Smørgrav (d->count+1)*sizeof(time_t)); 1433b5663de9SDag-Erling Smørgrav if(!d->rr_len || !d->rr_data || !d->rr_ttl) 1434b5663de9SDag-Erling Smørgrav return 0; /* out of memory */ 1435b5663de9SDag-Erling Smørgrav /* first one was allocated after struct d, but new 1436b5663de9SDag-Erling Smørgrav * ones get their own array increment alloc, so 1437b5663de9SDag-Erling Smørgrav * copy old content */ 1438b5663de9SDag-Erling Smørgrav memmove(d->rr_len, oldlen, d->count*sizeof(size_t)); 1439b5663de9SDag-Erling Smørgrav memmove(d->rr_data, olddata, d->count*sizeof(uint8_t*)); 1440b5663de9SDag-Erling Smørgrav memmove(d->rr_ttl, oldttl, d->count*sizeof(time_t)); 1441b5663de9SDag-Erling Smørgrav } 1442b5663de9SDag-Erling Smørgrav 1443b5663de9SDag-Erling Smørgrav d->rr_len[d->count] = sldns_wirerr_get_rdatalen(rr, len, 1)+2; 1444b5663de9SDag-Erling Smørgrav d->rr_ttl[d->count] = sldns_wirerr_get_ttl(rr, len, 1); 1445b5663de9SDag-Erling Smørgrav d->rr_data[d->count] = regional_alloc_init(temp, 1446b5663de9SDag-Erling Smørgrav sldns_wirerr_get_rdatawl(rr, len, 1), 1447b5663de9SDag-Erling Smørgrav d->rr_len[d->count]); 1448b5663de9SDag-Erling Smørgrav if(!d->rr_data[d->count]) 144965b390aaSDag-Erling Smørgrav return 0; /* out of memory */ 1450b5663de9SDag-Erling Smørgrav d->count++; 1451b5663de9SDag-Erling Smørgrav } 145265b390aaSDag-Erling Smørgrav if(r->rk.dname) 145365b390aaSDag-Erling Smørgrav return 1; 145465b390aaSDag-Erling Smørgrav return 0; 145565b390aaSDag-Erling Smørgrav } 145665b390aaSDag-Erling Smørgrav 145765b390aaSDag-Erling Smørgrav static int 145865b390aaSDag-Erling Smørgrav find_tag_datas(struct query_info* qinfo, struct config_strlist* list, 145965b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* r, struct regional* temp) 146065b390aaSDag-Erling Smørgrav { 146165b390aaSDag-Erling Smørgrav int result = local_data_find_tag_datas(qinfo, list, r, temp); 146265b390aaSDag-Erling Smørgrav 1463bc892140SDag-Erling Smørgrav /* If we've found a non-exact alias type of local data, make a shallow 1464bc892140SDag-Erling Smørgrav * copy of the RRset and remember it in qinfo to complete the alias 1465bc892140SDag-Erling Smørgrav * chain later. */ 146665b390aaSDag-Erling Smørgrav if(result && qinfo->qtype != LDNS_RR_TYPE_CNAME && 1467bc892140SDag-Erling Smørgrav r->rk.type == htons(LDNS_RR_TYPE_CNAME)) { 1468bc892140SDag-Erling Smørgrav qinfo->local_alias = 1469bc892140SDag-Erling Smørgrav regional_alloc_zero(temp, sizeof(struct local_rrset)); 1470bc892140SDag-Erling Smørgrav if(!qinfo->local_alias) 1471bc892140SDag-Erling Smørgrav return 0; /* out of memory */ 1472bc892140SDag-Erling Smørgrav qinfo->local_alias->rrset = 1473bc892140SDag-Erling Smørgrav regional_alloc_init(temp, r, sizeof(*r)); 1474bc892140SDag-Erling Smørgrav if(!qinfo->local_alias->rrset) 1475bc892140SDag-Erling Smørgrav return 0; /* out of memory */ 1476bc892140SDag-Erling Smørgrav } 147765b390aaSDag-Erling Smørgrav return result; 1478b5663de9SDag-Erling Smørgrav } 1479b5663de9SDag-Erling Smørgrav 1480091e9e46SCy Schubert int 1481bc892140SDag-Erling Smørgrav local_data_answer(struct local_zone* z, struct module_env* env, 14824c75e3aaSDag-Erling Smørgrav struct query_info* qinfo, struct edns_data* edns, 14834c75e3aaSDag-Erling Smørgrav struct comm_reply* repinfo, sldns_buffer* buf, 1484bc892140SDag-Erling Smørgrav struct regional* temp, int labs, struct local_data** ldp, 1485bc892140SDag-Erling Smørgrav enum localzone_type lz_type, int tag, struct config_strlist** tag_datas, 1486bc892140SDag-Erling Smørgrav size_t tag_datas_size, char** tagname, int num_tags) 1487b7579f77SDag-Erling Smørgrav { 1488b7579f77SDag-Erling Smørgrav struct local_data key; 1489b7579f77SDag-Erling Smørgrav struct local_data* ld; 1490b7579f77SDag-Erling Smørgrav struct local_rrset* lr; 1491b7579f77SDag-Erling Smørgrav key.node.key = &key; 1492b7579f77SDag-Erling Smørgrav key.name = qinfo->qname; 1493b7579f77SDag-Erling Smørgrav key.namelen = qinfo->qname_len; 1494b7579f77SDag-Erling Smørgrav key.namelabs = labs; 1495e86b9096SDag-Erling Smørgrav if(lz_type == local_zone_redirect || 1496e86b9096SDag-Erling Smørgrav lz_type == local_zone_inform_redirect) { 1497b7579f77SDag-Erling Smørgrav key.name = z->name; 1498b7579f77SDag-Erling Smørgrav key.namelen = z->namelen; 1499b7579f77SDag-Erling Smørgrav key.namelabs = z->namelabs; 1500b5663de9SDag-Erling Smørgrav if(tag != -1 && (size_t)tag<tag_datas_size && tag_datas[tag]) { 1501b5663de9SDag-Erling Smørgrav struct ub_packed_rrset_key r; 1502b5663de9SDag-Erling Smørgrav memset(&r, 0, sizeof(r)); 1503bc892140SDag-Erling Smørgrav if(find_tag_datas(qinfo, tag_datas[tag], &r, temp)) { 1504b5663de9SDag-Erling Smørgrav verbose(VERB_ALGO, "redirect with tag data [%d] %s", 1505b5663de9SDag-Erling Smørgrav tag, (tag<num_tags?tagname[tag]:"null")); 1506bc892140SDag-Erling Smørgrav 1507bc892140SDag-Erling Smørgrav /* If we found a matching alias, we should 1508bc892140SDag-Erling Smørgrav * use it as part of the answer, but we can't 1509bc892140SDag-Erling Smørgrav * encode it until we complete the alias 1510bc892140SDag-Erling Smørgrav * chain. */ 1511bc892140SDag-Erling Smørgrav if(qinfo->local_alias) 1512bc892140SDag-Erling Smørgrav return 1; 15134c75e3aaSDag-Erling Smørgrav return local_encode(qinfo, env, edns, repinfo, buf, temp, 1514b5663de9SDag-Erling Smørgrav &r, 1, LDNS_RCODE_NOERROR); 1515b5663de9SDag-Erling Smørgrav } 1516b5663de9SDag-Erling Smørgrav } 1517b7579f77SDag-Erling Smørgrav } 1518b7579f77SDag-Erling Smørgrav ld = (struct local_data*)rbtree_search(&z->data, &key.node); 1519b7579f77SDag-Erling Smørgrav *ldp = ld; 1520b7579f77SDag-Erling Smørgrav if(!ld) { 1521b7579f77SDag-Erling Smørgrav return 0; 1522b7579f77SDag-Erling Smørgrav } 1523bc892140SDag-Erling Smørgrav lr = local_data_find_type(ld, qinfo->qtype, 1); 1524b7579f77SDag-Erling Smørgrav if(!lr) 1525b7579f77SDag-Erling Smørgrav return 0; 1526bc892140SDag-Erling Smørgrav 1527bc892140SDag-Erling Smørgrav /* Special case for alias matching. See local_data_answer(). */ 1528e86b9096SDag-Erling Smørgrav if((lz_type == local_zone_redirect || 1529e86b9096SDag-Erling Smørgrav lz_type == local_zone_inform_redirect) && 1530bc892140SDag-Erling Smørgrav qinfo->qtype != LDNS_RR_TYPE_CNAME && 1531bc892140SDag-Erling Smørgrav lr->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) { 1532091e9e46SCy Schubert uint8_t* ctarget; 1533091e9e46SCy Schubert size_t ctargetlen = 0; 1534091e9e46SCy Schubert 1535bc892140SDag-Erling Smørgrav qinfo->local_alias = 1536bc892140SDag-Erling Smørgrav regional_alloc_zero(temp, sizeof(struct local_rrset)); 1537bc892140SDag-Erling Smørgrav if(!qinfo->local_alias) 1538bc892140SDag-Erling Smørgrav return 0; /* out of memory */ 1539091e9e46SCy Schubert qinfo->local_alias->rrset = regional_alloc_init( 1540091e9e46SCy Schubert temp, lr->rrset, sizeof(*lr->rrset)); 1541bc892140SDag-Erling Smørgrav if(!qinfo->local_alias->rrset) 1542bc892140SDag-Erling Smørgrav return 0; /* out of memory */ 1543bc892140SDag-Erling Smørgrav qinfo->local_alias->rrset->rk.dname = qinfo->qname; 1544bc892140SDag-Erling Smørgrav qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len; 1545091e9e46SCy Schubert get_cname_target(lr->rrset, &ctarget, &ctargetlen); 1546091e9e46SCy Schubert if(!ctargetlen) 1547091e9e46SCy Schubert return 0; /* invalid cname */ 1548091e9e46SCy Schubert if(dname_is_wild(ctarget)) { 1549091e9e46SCy Schubert /* synthesize cname target */ 1550b7c0c8c1SCy Schubert struct packed_rrset_data* d, *lr_d; 1551091e9e46SCy Schubert /* -3 for wildcard label and root label from qname */ 1552091e9e46SCy Schubert size_t newtargetlen = qinfo->qname_len + ctargetlen - 3; 1553091e9e46SCy Schubert 1554091e9e46SCy Schubert log_assert(ctargetlen >= 3); 1555091e9e46SCy Schubert log_assert(qinfo->qname_len >= 1); 1556091e9e46SCy Schubert 1557091e9e46SCy Schubert if(newtargetlen > LDNS_MAX_DOMAINLEN) { 1558091e9e46SCy Schubert qinfo->local_alias = NULL; 1559091e9e46SCy Schubert local_error_encode(qinfo, env, edns, repinfo, 1560091e9e46SCy Schubert buf, temp, LDNS_RCODE_YXDOMAIN, 1561a39a5a69SCy Schubert (LDNS_RCODE_YXDOMAIN|BIT_AA), 1562a39a5a69SCy Schubert LDNS_EDE_OTHER, 1563a39a5a69SCy Schubert "DNAME expansion became too large"); 1564091e9e46SCy Schubert return 1; 1565091e9e46SCy Schubert } 1566091e9e46SCy Schubert memset(&qinfo->local_alias->rrset->entry, 0, 1567091e9e46SCy Schubert sizeof(qinfo->local_alias->rrset->entry)); 1568091e9e46SCy Schubert qinfo->local_alias->rrset->entry.key = 1569091e9e46SCy Schubert qinfo->local_alias->rrset; 1570091e9e46SCy Schubert qinfo->local_alias->rrset->entry.hash = 1571091e9e46SCy Schubert rrset_key_hash(&qinfo->local_alias->rrset->rk); 1572091e9e46SCy Schubert d = (struct packed_rrset_data*)regional_alloc_zero(temp, 1573091e9e46SCy Schubert sizeof(struct packed_rrset_data) + sizeof(size_t) + 1574091e9e46SCy Schubert sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t) 1575091e9e46SCy Schubert + newtargetlen); 1576091e9e46SCy Schubert if(!d) 1577091e9e46SCy Schubert return 0; /* out of memory */ 1578b7c0c8c1SCy Schubert lr_d = (struct packed_rrset_data*)lr->rrset->entry.data; 1579091e9e46SCy Schubert qinfo->local_alias->rrset->entry.data = d; 1580b7c0c8c1SCy Schubert d->ttl = lr_d->rr_ttl[0]; /* RFC6672-like behavior: 1581b7c0c8c1SCy Schubert synth CNAME TTL uses original TTL*/ 1582091e9e46SCy Schubert d->count = 1; 1583091e9e46SCy Schubert d->rrsig_count = 0; 1584091e9e46SCy Schubert d->trust = rrset_trust_ans_noAA; 1585091e9e46SCy Schubert d->rr_len = (size_t*)((uint8_t*)d + 1586091e9e46SCy Schubert sizeof(struct packed_rrset_data)); 1587091e9e46SCy Schubert d->rr_len[0] = newtargetlen + sizeof(uint16_t); 1588091e9e46SCy Schubert packed_rrset_ptr_fixup(d); 1589091e9e46SCy Schubert d->rr_ttl[0] = d->ttl; 1590091e9e46SCy Schubert sldns_write_uint16(d->rr_data[0], newtargetlen); 1591091e9e46SCy Schubert /* write qname */ 1592091e9e46SCy Schubert memmove(d->rr_data[0] + sizeof(uint16_t), qinfo->qname, 1593091e9e46SCy Schubert qinfo->qname_len - 1); 159424e36522SCy Schubert /* write cname target wildcard label */ 1595091e9e46SCy Schubert memmove(d->rr_data[0] + sizeof(uint16_t) + 1596091e9e46SCy Schubert qinfo->qname_len - 1, ctarget + 2, 1597091e9e46SCy Schubert ctargetlen - 2); 1598091e9e46SCy Schubert } 1599bc892140SDag-Erling Smørgrav return 1; 1600bc892140SDag-Erling Smørgrav } 1601e86b9096SDag-Erling Smørgrav if(lz_type == local_zone_redirect || 1602e86b9096SDag-Erling Smørgrav lz_type == local_zone_inform_redirect) { 1603b7579f77SDag-Erling Smørgrav /* convert rrset name to query name; like a wildcard */ 1604b7579f77SDag-Erling Smørgrav struct ub_packed_rrset_key r = *lr->rrset; 1605b7579f77SDag-Erling Smørgrav r.rk.dname = qinfo->qname; 1606b7579f77SDag-Erling Smørgrav r.rk.dname_len = qinfo->qname_len; 16074c75e3aaSDag-Erling Smørgrav return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1, 1608b7579f77SDag-Erling Smørgrav LDNS_RCODE_NOERROR); 1609b7579f77SDag-Erling Smørgrav } 16104c75e3aaSDag-Erling Smørgrav return local_encode(qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1, 1611b7579f77SDag-Erling Smørgrav LDNS_RCODE_NOERROR); 1612b7579f77SDag-Erling Smørgrav } 1613b7579f77SDag-Erling Smørgrav 1614b7579f77SDag-Erling Smørgrav /** 16154c75e3aaSDag-Erling Smørgrav * See if the local zone does not cover the name, eg. the name is not 16164c75e3aaSDag-Erling Smørgrav * in the zone and the zone is transparent */ 16174c75e3aaSDag-Erling Smørgrav static int 16184c75e3aaSDag-Erling Smørgrav local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo, 16194c75e3aaSDag-Erling Smørgrav int labs) 16204c75e3aaSDag-Erling Smørgrav { 16214c75e3aaSDag-Erling Smørgrav struct local_data key; 16224c75e3aaSDag-Erling Smørgrav struct local_data* ld = NULL; 16234c75e3aaSDag-Erling Smørgrav struct local_rrset* lr = NULL; 16248f76bb7dSCy Schubert if(z->type == local_zone_always_transparent || z->type == local_zone_block_a) 16254c75e3aaSDag-Erling Smørgrav return 1; 16264c75e3aaSDag-Erling Smørgrav if(z->type != local_zone_transparent 16274c75e3aaSDag-Erling Smørgrav && z->type != local_zone_typetransparent 16284c75e3aaSDag-Erling Smørgrav && z->type != local_zone_inform) 16294c75e3aaSDag-Erling Smørgrav return 0; 16304c75e3aaSDag-Erling Smørgrav key.node.key = &key; 16314c75e3aaSDag-Erling Smørgrav key.name = qinfo->qname; 16324c75e3aaSDag-Erling Smørgrav key.namelen = qinfo->qname_len; 16334c75e3aaSDag-Erling Smørgrav key.namelabs = labs; 16344c75e3aaSDag-Erling Smørgrav ld = (struct local_data*)rbtree_search(&z->data, &key.node); 16354c75e3aaSDag-Erling Smørgrav if(z->type == local_zone_transparent || z->type == local_zone_inform) 16364c75e3aaSDag-Erling Smørgrav return (ld == NULL); 16374c75e3aaSDag-Erling Smørgrav if(ld) 16384c75e3aaSDag-Erling Smørgrav lr = local_data_find_type(ld, qinfo->qtype, 1); 16394c75e3aaSDag-Erling Smørgrav /* local_zone_typetransparent */ 16404c75e3aaSDag-Erling Smørgrav return (lr == NULL); 16414c75e3aaSDag-Erling Smørgrav } 16424c75e3aaSDag-Erling Smørgrav 164324e36522SCy Schubert static inline int 164424e36522SCy Schubert local_zone_is_udp_query(struct comm_reply* repinfo) { 164524e36522SCy Schubert return repinfo != NULL 164624e36522SCy Schubert ? (repinfo->c != NULL 164724e36522SCy Schubert ? repinfo->c->type == comm_udp 164824e36522SCy Schubert : 0) 164924e36522SCy Schubert : 0; 165024e36522SCy Schubert } 165124e36522SCy Schubert 1652091e9e46SCy Schubert int 1653091e9e46SCy Schubert local_zones_zone_answer(struct local_zone* z, struct module_env* env, 16544c75e3aaSDag-Erling Smørgrav struct query_info* qinfo, struct edns_data* edns, 16554c75e3aaSDag-Erling Smørgrav struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp, 16564c75e3aaSDag-Erling Smørgrav struct local_data* ld, enum localzone_type lz_type) 1657b7579f77SDag-Erling Smørgrav { 1658091e9e46SCy Schubert if(lz_type == local_zone_deny || 1659091e9e46SCy Schubert lz_type == local_zone_always_deny || 1660091e9e46SCy Schubert lz_type == local_zone_inform_deny) { 1661b7579f77SDag-Erling Smørgrav /** no reply at all, signal caller by clearing buffer. */ 166217d15b25SDag-Erling Smørgrav sldns_buffer_clear(buf); 166317d15b25SDag-Erling Smørgrav sldns_buffer_flip(buf); 1664b7579f77SDag-Erling Smørgrav return 1; 1665b5663de9SDag-Erling Smørgrav } else if(lz_type == local_zone_refuse 1666b5663de9SDag-Erling Smørgrav || lz_type == local_zone_always_refuse) { 16674c75e3aaSDag-Erling Smørgrav local_error_encode(qinfo, env, edns, repinfo, buf, temp, 1668a39a5a69SCy Schubert LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA), 1669a39a5a69SCy Schubert LDNS_EDE_NONE, NULL); 1670b7579f77SDag-Erling Smørgrav return 1; 1671b5663de9SDag-Erling Smørgrav } else if(lz_type == local_zone_static || 1672b5663de9SDag-Erling Smørgrav lz_type == local_zone_redirect || 1673e86b9096SDag-Erling Smørgrav lz_type == local_zone_inform_redirect || 1674091e9e46SCy Schubert lz_type == local_zone_always_nxdomain || 167524e36522SCy Schubert lz_type == local_zone_always_nodata || 167624e36522SCy Schubert (lz_type == local_zone_truncate 167724e36522SCy Schubert && local_zone_is_udp_query(repinfo))) { 1678b7579f77SDag-Erling Smørgrav /* for static, reply nodata or nxdomain 1679b7579f77SDag-Erling Smørgrav * for redirect, reply nodata */ 1680b7579f77SDag-Erling Smørgrav /* no additional section processing, 1681b7579f77SDag-Erling Smørgrav * cname, dname or wildcard processing, 1682b7579f77SDag-Erling Smørgrav * or using closest match for NSEC. 1683b7579f77SDag-Erling Smørgrav * or using closest match for returning delegation downwards 1684b7579f77SDag-Erling Smørgrav */ 1685e86b9096SDag-Erling Smørgrav int rcode = (ld || lz_type == local_zone_redirect || 1686091e9e46SCy Schubert lz_type == local_zone_inform_redirect || 168724e36522SCy Schubert lz_type == local_zone_always_nodata || 168824e36522SCy Schubert lz_type == local_zone_truncate)? 1689b5663de9SDag-Erling Smørgrav LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN; 169024e36522SCy Schubert rcode = (lz_type == local_zone_truncate ? (rcode|BIT_TC) : rcode); 169124e36522SCy Schubert if(z != NULL && z->soa && z->soa_negative) 16924c75e3aaSDag-Erling Smørgrav return local_encode(qinfo, env, edns, repinfo, buf, temp, 1693f44e67d1SCy Schubert z->soa_negative, 0, rcode); 1694a39a5a69SCy Schubert local_error_encode(qinfo, env, edns, repinfo, buf, temp, 1695a39a5a69SCy Schubert rcode, (rcode|BIT_AA), LDNS_EDE_NONE, NULL); 1696b7579f77SDag-Erling Smørgrav return 1; 1697b5663de9SDag-Erling Smørgrav } else if(lz_type == local_zone_typetransparent 1698b5663de9SDag-Erling Smørgrav || lz_type == local_zone_always_transparent) { 1699b7579f77SDag-Erling Smørgrav /* no NODATA or NXDOMAINS for this zone type */ 1700b7579f77SDag-Erling Smørgrav return 0; 17018f76bb7dSCy Schubert } else if(lz_type == local_zone_block_a) { 17028f76bb7dSCy Schubert /* Return NODATA for all A queries */ 17038f76bb7dSCy Schubert if(qinfo->qtype == LDNS_RR_TYPE_A) { 17048f76bb7dSCy Schubert local_error_encode(qinfo, env, edns, repinfo, buf, temp, 17058f76bb7dSCy Schubert LDNS_RCODE_NOERROR, (LDNS_RCODE_NOERROR|BIT_AA), 17068f76bb7dSCy Schubert LDNS_EDE_NONE, NULL); 17078f76bb7dSCy Schubert return 1; 17088f76bb7dSCy Schubert } 17098f76bb7dSCy Schubert 17108f76bb7dSCy Schubert return 0; 1711f44e67d1SCy Schubert } else if(lz_type == local_zone_always_null) { 1712f44e67d1SCy Schubert /* 0.0.0.0 or ::0 or noerror/nodata for this zone type, 1713f44e67d1SCy Schubert * used for blocklists. */ 1714f44e67d1SCy Schubert if(qinfo->qtype == LDNS_RR_TYPE_A || 1715f44e67d1SCy Schubert qinfo->qtype == LDNS_RR_TYPE_AAAA) { 1716f44e67d1SCy Schubert struct ub_packed_rrset_key lrr; 1717f44e67d1SCy Schubert struct packed_rrset_data d; 1718f44e67d1SCy Schubert time_t rr_ttl = 3600; 1719f44e67d1SCy Schubert size_t rr_len = 0; 1720f44e67d1SCy Schubert uint8_t rr_data[2+16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 1721f44e67d1SCy Schubert uint8_t* rr_datas = rr_data; 1722f44e67d1SCy Schubert memset(&lrr, 0, sizeof(lrr)); 1723f44e67d1SCy Schubert memset(&d, 0, sizeof(d)); 1724f44e67d1SCy Schubert lrr.entry.data = &d; 1725f44e67d1SCy Schubert lrr.rk.dname = qinfo->qname; 1726f44e67d1SCy Schubert lrr.rk.dname_len = qinfo->qname_len; 1727f44e67d1SCy Schubert lrr.rk.type = htons(qinfo->qtype); 1728f44e67d1SCy Schubert lrr.rk.rrset_class = htons(qinfo->qclass); 1729f44e67d1SCy Schubert if(qinfo->qtype == LDNS_RR_TYPE_A) { 1730f44e67d1SCy Schubert rr_len = 4; 1731f44e67d1SCy Schubert sldns_write_uint16(rr_data, rr_len); 1732f44e67d1SCy Schubert rr_len += 2; 1733f44e67d1SCy Schubert } else { 1734f44e67d1SCy Schubert rr_len = 16; 1735f44e67d1SCy Schubert sldns_write_uint16(rr_data, rr_len); 1736f44e67d1SCy Schubert rr_len += 2; 1737f44e67d1SCy Schubert } 1738f44e67d1SCy Schubert d.ttl = rr_ttl; 1739f44e67d1SCy Schubert d.count = 1; 1740f44e67d1SCy Schubert d.rr_len = &rr_len; 1741f44e67d1SCy Schubert d.rr_data = &rr_datas; 1742f44e67d1SCy Schubert d.rr_ttl = &rr_ttl; 1743f44e67d1SCy Schubert return local_encode(qinfo, env, edns, repinfo, buf, temp, 1744f44e67d1SCy Schubert &lrr, 1, LDNS_RCODE_NOERROR); 1745f44e67d1SCy Schubert } else { 1746a39a5a69SCy Schubert /* NODATA: No EDE needed */ 1747f44e67d1SCy Schubert local_error_encode(qinfo, env, edns, repinfo, buf, 1748f44e67d1SCy Schubert temp, LDNS_RCODE_NOERROR, 1749a39a5a69SCy Schubert (LDNS_RCODE_NOERROR|BIT_AA), -1, NULL); 1750f44e67d1SCy Schubert } 1751f44e67d1SCy Schubert return 1; 1752b7579f77SDag-Erling Smørgrav } 1753b5663de9SDag-Erling Smørgrav /* else lz_type == local_zone_transparent */ 1754b7579f77SDag-Erling Smørgrav 1755b7579f77SDag-Erling Smørgrav /* if the zone is transparent and the name exists, but the type 1756b7579f77SDag-Erling Smørgrav * does not, then we should make this noerror/nodata */ 1757b7579f77SDag-Erling Smørgrav if(ld && ld->rrsets) { 1758b7579f77SDag-Erling Smørgrav int rcode = LDNS_RCODE_NOERROR; 175924e36522SCy Schubert if(z != NULL && z->soa && z->soa_negative) 17604c75e3aaSDag-Erling Smørgrav return local_encode(qinfo, env, edns, repinfo, buf, temp, 1761f44e67d1SCy Schubert z->soa_negative, 0, rcode); 1762a39a5a69SCy Schubert /* NODATA: No EDE needed */ 17634c75e3aaSDag-Erling Smørgrav local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode, 1764a39a5a69SCy Schubert (rcode|BIT_AA), LDNS_EDE_NONE, NULL); 1765b7579f77SDag-Erling Smørgrav return 1; 1766b7579f77SDag-Erling Smørgrav } 1767b7579f77SDag-Erling Smørgrav 1768b7579f77SDag-Erling Smørgrav /* stop here, and resolve further on */ 1769b7579f77SDag-Erling Smørgrav return 0; 1770b7579f77SDag-Erling Smørgrav } 1771b7579f77SDag-Erling Smørgrav 17726480faa8SDag-Erling Smørgrav /** print log information for an inform zone query */ 17736480faa8SDag-Erling Smørgrav static void 17746480faa8SDag-Erling Smørgrav lz_inform_print(struct local_zone* z, struct query_info* qinfo, 1775865f46b2SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen) 17766480faa8SDag-Erling Smørgrav { 17776480faa8SDag-Erling Smørgrav char ip[128], txt[512]; 1778*be771a7bSCy Schubert char zname[LDNS_MAX_DOMAINLEN]; 1779865f46b2SCy Schubert uint16_t port = ntohs(((struct sockaddr_in*)addr)->sin_port); 17806480faa8SDag-Erling Smørgrav dname_str(z->name, zname); 1781865f46b2SCy Schubert addr_to_str(addr, addrlen, ip, sizeof(ip)); 17824c75e3aaSDag-Erling Smørgrav snprintf(txt, sizeof(txt), "%s %s %s@%u", zname, local_zone_type2str(z->type), ip, 17836480faa8SDag-Erling Smørgrav (unsigned)port); 17840eefd307SCy Schubert log_nametypeclass(NO_VERBOSE, txt, qinfo->qname, qinfo->qtype, qinfo->qclass); 17856480faa8SDag-Erling Smørgrav } 17866480faa8SDag-Erling Smørgrav 1787b5663de9SDag-Erling Smørgrav static enum localzone_type 1788b5663de9SDag-Erling Smørgrav lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2, 1789b5663de9SDag-Erling Smørgrav uint8_t *tagactions, size_t tagactionssize, enum localzone_type lzt, 17903005e0a3SDag-Erling Smørgrav struct comm_reply* repinfo, struct rbtree_type* override_tree, 17913005e0a3SDag-Erling Smørgrav int* tag, char** tagname, int num_tags) 1792b5663de9SDag-Erling Smørgrav { 1793b5663de9SDag-Erling Smørgrav struct local_zone_override* lzo; 1794b5663de9SDag-Erling Smørgrav if(repinfo && override_tree) { 1795b5663de9SDag-Erling Smørgrav lzo = (struct local_zone_override*)addr_tree_lookup( 1796865f46b2SCy Schubert override_tree, &repinfo->client_addr, 1797865f46b2SCy Schubert repinfo->client_addrlen); 1798b5663de9SDag-Erling Smørgrav if(lzo && lzo->type) { 1799b5663de9SDag-Erling Smørgrav verbose(VERB_ALGO, "local zone override to type %s", 1800b5663de9SDag-Erling Smørgrav local_zone_type2str(lzo->type)); 1801b5663de9SDag-Erling Smørgrav return lzo->type; 1802b5663de9SDag-Erling Smørgrav } 1803b5663de9SDag-Erling Smørgrav } 1804b5663de9SDag-Erling Smørgrav if(!taglist || !taglist2) 1805b5663de9SDag-Erling Smørgrav return lzt; 180665b390aaSDag-Erling Smørgrav return local_data_find_tag_action(taglist, taglen, taglist2, taglen2, 180765b390aaSDag-Erling Smørgrav tagactions, tagactionssize, lzt, tag, tagname, num_tags); 180865b390aaSDag-Erling Smørgrav } 180965b390aaSDag-Erling Smørgrav 181065b390aaSDag-Erling Smørgrav enum localzone_type 181165b390aaSDag-Erling Smørgrav local_data_find_tag_action(const uint8_t* taglist, size_t taglen, 181265b390aaSDag-Erling Smørgrav const uint8_t* taglist2, size_t taglen2, const uint8_t* tagactions, 181365b390aaSDag-Erling Smørgrav size_t tagactionssize, enum localzone_type lzt, int* tag, 181465b390aaSDag-Erling Smørgrav char* const* tagname, int num_tags) 181565b390aaSDag-Erling Smørgrav { 181665b390aaSDag-Erling Smørgrav size_t i, j; 181765b390aaSDag-Erling Smørgrav uint8_t tagmatch; 181865b390aaSDag-Erling Smørgrav 1819b5663de9SDag-Erling Smørgrav for(i=0; i<taglen && i<taglen2; i++) { 1820b5663de9SDag-Erling Smørgrav tagmatch = (taglist[i] & taglist2[i]); 1821b5663de9SDag-Erling Smørgrav for(j=0; j<8 && tagmatch>0; j++) { 1822b5663de9SDag-Erling Smørgrav if((tagmatch & 0x1)) { 1823b5663de9SDag-Erling Smørgrav *tag = (int)(i*8+j); 1824b5663de9SDag-Erling Smørgrav verbose(VERB_ALGO, "matched tag [%d] %s", 1825b5663de9SDag-Erling Smørgrav *tag, (*tag<num_tags?tagname[*tag]:"null")); 1826b5663de9SDag-Erling Smørgrav /* does this tag have a tag action? */ 1827b5663de9SDag-Erling Smørgrav if(i*8+j < tagactionssize && tagactions 1828b5663de9SDag-Erling Smørgrav && tagactions[i*8+j] != 0) { 1829b5663de9SDag-Erling Smørgrav verbose(VERB_ALGO, "tag action [%d] %s to type %s", 1830b5663de9SDag-Erling Smørgrav *tag, (*tag<num_tags?tagname[*tag]:"null"), 1831b5663de9SDag-Erling Smørgrav local_zone_type2str( 1832b5663de9SDag-Erling Smørgrav (enum localzone_type) 1833b5663de9SDag-Erling Smørgrav tagactions[i*8+j])); 1834b5663de9SDag-Erling Smørgrav return (enum localzone_type)tagactions[i*8+j]; 1835b5663de9SDag-Erling Smørgrav } 1836b5663de9SDag-Erling Smørgrav return lzt; 1837b5663de9SDag-Erling Smørgrav } 1838b5663de9SDag-Erling Smørgrav tagmatch >>= 1; 1839b5663de9SDag-Erling Smørgrav } 1840b5663de9SDag-Erling Smørgrav } 1841b5663de9SDag-Erling Smørgrav return lzt; 1842b5663de9SDag-Erling Smørgrav } 1843b5663de9SDag-Erling Smørgrav 1844b7579f77SDag-Erling Smørgrav int 1845bc892140SDag-Erling Smørgrav local_zones_answer(struct local_zones* zones, struct module_env* env, 1846bc892140SDag-Erling Smørgrav struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, 1847bc892140SDag-Erling Smørgrav struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist, 1848bc892140SDag-Erling Smørgrav size_t taglen, uint8_t* tagactions, size_t tagactionssize, 1849b5663de9SDag-Erling Smørgrav struct config_strlist** tag_datas, size_t tag_datas_size, 1850bc892140SDag-Erling Smørgrav char** tagname, int num_tags, struct view* view) 1851b7579f77SDag-Erling Smørgrav { 1852b7579f77SDag-Erling Smørgrav /* see if query is covered by a zone, 1853b7579f77SDag-Erling Smørgrav * if so: - try to match (exact) local data 1854b7579f77SDag-Erling Smørgrav * - look at zone type for negative response. */ 1855b7579f77SDag-Erling Smørgrav int labs = dname_count_labels(qinfo->qname); 1856b5663de9SDag-Erling Smørgrav struct local_data* ld = NULL; 1857bc892140SDag-Erling Smørgrav struct local_zone* z = NULL; 1858bc892140SDag-Erling Smørgrav enum localzone_type lzt = local_zone_transparent; 1859b5663de9SDag-Erling Smørgrav int r, tag = -1; 1860bc892140SDag-Erling Smørgrav 1861bc892140SDag-Erling Smørgrav if(view) { 1862bc892140SDag-Erling Smørgrav lock_rw_rdlock(&view->lock); 1863bc892140SDag-Erling Smørgrav if(view->local_zones && 1864bc892140SDag-Erling Smørgrav (z = local_zones_lookup(view->local_zones, 1865bc892140SDag-Erling Smørgrav qinfo->qname, qinfo->qname_len, labs, 1866971980c3SDag-Erling Smørgrav qinfo->qclass, qinfo->qtype))) { 1867bc892140SDag-Erling Smørgrav lock_rw_rdlock(&z->lock); 1868bc892140SDag-Erling Smørgrav lzt = z->type; 1869bc892140SDag-Erling Smørgrav } 187057bddd21SDag-Erling Smørgrav if(lzt == local_zone_noview) { 187157bddd21SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 187257bddd21SDag-Erling Smørgrav z = NULL; 187357bddd21SDag-Erling Smørgrav } 18744c75e3aaSDag-Erling Smørgrav if(z && (lzt == local_zone_transparent || 18754c75e3aaSDag-Erling Smørgrav lzt == local_zone_typetransparent || 18764c75e3aaSDag-Erling Smørgrav lzt == local_zone_inform || 18778f76bb7dSCy Schubert lzt == local_zone_always_transparent || 18788f76bb7dSCy Schubert lzt == local_zone_block_a) && 18794c75e3aaSDag-Erling Smørgrav local_zone_does_not_cover(z, qinfo, labs)) { 18804c75e3aaSDag-Erling Smørgrav lock_rw_unlock(&z->lock); 18814c75e3aaSDag-Erling Smørgrav z = NULL; 18824c75e3aaSDag-Erling Smørgrav } 1883c7f4d7adSDag-Erling Smørgrav if(view->local_zones && !z && !view->isfirst){ 1884bc892140SDag-Erling Smørgrav lock_rw_unlock(&view->lock); 1885bc892140SDag-Erling Smørgrav return 0; 1886bc892140SDag-Erling Smørgrav } 18874c75e3aaSDag-Erling Smørgrav if(z && verbosity >= VERB_ALGO) { 1888*be771a7bSCy Schubert char zname[LDNS_MAX_DOMAINLEN]; 18894c75e3aaSDag-Erling Smørgrav dname_str(z->name, zname); 18904c75e3aaSDag-Erling Smørgrav verbose(VERB_ALGO, "using localzone %s %s from view %s", 18914c75e3aaSDag-Erling Smørgrav zname, local_zone_type2str(lzt), view->name); 18924c75e3aaSDag-Erling Smørgrav } 1893bc892140SDag-Erling Smørgrav lock_rw_unlock(&view->lock); 1894bc892140SDag-Erling Smørgrav } 1895b7579f77SDag-Erling Smørgrav if(!z) { 1896bc892140SDag-Erling Smørgrav /* try global local_zones tree */ 1897bc892140SDag-Erling Smørgrav lock_rw_rdlock(&zones->lock); 1898bc892140SDag-Erling Smørgrav if(!(z = local_zones_tags_lookup(zones, qinfo->qname, 1899971980c3SDag-Erling Smørgrav qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype, 1900971980c3SDag-Erling Smørgrav taglist, taglen, 0))) { 190117d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 1902b7579f77SDag-Erling Smørgrav return 0; 1903b7579f77SDag-Erling Smørgrav } 1904b7579f77SDag-Erling Smørgrav lock_rw_rdlock(&z->lock); 1905bc892140SDag-Erling Smørgrav lzt = lz_type(taglist, taglen, z->taglist, z->taglen, 1906bc892140SDag-Erling Smørgrav tagactions, tagactionssize, z->type, repinfo, 1907bc892140SDag-Erling Smørgrav z->override_tree, &tag, tagname, num_tags); 190817d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 19094c75e3aaSDag-Erling Smørgrav if(z && verbosity >= VERB_ALGO) { 1910*be771a7bSCy Schubert char zname[LDNS_MAX_DOMAINLEN]; 19114c75e3aaSDag-Erling Smørgrav dname_str(z->name, zname); 19124c75e3aaSDag-Erling Smørgrav verbose(VERB_ALGO, "using localzone %s %s", zname, 19134c75e3aaSDag-Erling Smørgrav local_zone_type2str(lzt)); 1914bc892140SDag-Erling Smørgrav } 19154c75e3aaSDag-Erling Smørgrav } 19164c75e3aaSDag-Erling Smørgrav if((env->cfg->log_local_actions || 1917e86b9096SDag-Erling Smørgrav lzt == local_zone_inform || 1918e86b9096SDag-Erling Smørgrav lzt == local_zone_inform_deny || 1919e86b9096SDag-Erling Smørgrav lzt == local_zone_inform_redirect) 192009a3aaf3SDag-Erling Smørgrav && repinfo) 1921865f46b2SCy Schubert lz_inform_print(z, qinfo, &repinfo->client_addr, 1922865f46b2SCy Schubert repinfo->client_addrlen); 19236480faa8SDag-Erling Smørgrav 1924bc892140SDag-Erling Smørgrav if(lzt != local_zone_always_refuse 1925bc892140SDag-Erling Smørgrav && lzt != local_zone_always_transparent 19268f76bb7dSCy Schubert && lzt != local_zone_block_a 1927b5663de9SDag-Erling Smørgrav && lzt != local_zone_always_nxdomain 1928091e9e46SCy Schubert && lzt != local_zone_always_nodata 1929091e9e46SCy Schubert && lzt != local_zone_always_deny 19304c75e3aaSDag-Erling Smørgrav && local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs, 19314c75e3aaSDag-Erling Smørgrav &ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) { 1932b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 1933bc892140SDag-Erling Smørgrav /* We should tell the caller that encode is deferred if we found 1934bc892140SDag-Erling Smørgrav * a local alias. */ 1935bc892140SDag-Erling Smørgrav return !qinfo->local_alias; 1936b7579f77SDag-Erling Smørgrav } 1937091e9e46SCy Schubert r = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt); 1938b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 1939bc892140SDag-Erling Smørgrav return r && !qinfo->local_alias; /* see above */ 1940b7579f77SDag-Erling Smørgrav } 1941b7579f77SDag-Erling Smørgrav 1942b7579f77SDag-Erling Smørgrav const char* local_zone_type2str(enum localzone_type t) 1943b7579f77SDag-Erling Smørgrav { 1944b7579f77SDag-Erling Smørgrav switch(t) { 1945bc892140SDag-Erling Smørgrav case local_zone_unset: return "unset"; 1946b7579f77SDag-Erling Smørgrav case local_zone_deny: return "deny"; 1947b7579f77SDag-Erling Smørgrav case local_zone_refuse: return "refuse"; 1948b7579f77SDag-Erling Smørgrav case local_zone_redirect: return "redirect"; 1949b7579f77SDag-Erling Smørgrav case local_zone_transparent: return "transparent"; 1950b7579f77SDag-Erling Smørgrav case local_zone_typetransparent: return "typetransparent"; 1951b7579f77SDag-Erling Smørgrav case local_zone_static: return "static"; 1952b7579f77SDag-Erling Smørgrav case local_zone_nodefault: return "nodefault"; 19536480faa8SDag-Erling Smørgrav case local_zone_inform: return "inform"; 195409a3aaf3SDag-Erling Smørgrav case local_zone_inform_deny: return "inform_deny"; 1955e86b9096SDag-Erling Smørgrav case local_zone_inform_redirect: return "inform_redirect"; 1956b5663de9SDag-Erling Smørgrav case local_zone_always_transparent: return "always_transparent"; 19578f76bb7dSCy Schubert case local_zone_block_a: return "block_a"; 1958b5663de9SDag-Erling Smørgrav case local_zone_always_refuse: return "always_refuse"; 1959b5663de9SDag-Erling Smørgrav case local_zone_always_nxdomain: return "always_nxdomain"; 1960091e9e46SCy Schubert case local_zone_always_nodata: return "always_nodata"; 1961091e9e46SCy Schubert case local_zone_always_deny: return "always_deny"; 1962f44e67d1SCy Schubert case local_zone_always_null: return "always_null"; 196357bddd21SDag-Erling Smørgrav case local_zone_noview: return "noview"; 196424e36522SCy Schubert case local_zone_truncate: return "truncate"; 1965091e9e46SCy Schubert case local_zone_invalid: return "invalid"; 1966b7579f77SDag-Erling Smørgrav } 1967b7579f77SDag-Erling Smørgrav return "badtyped"; 1968b7579f77SDag-Erling Smørgrav } 1969b7579f77SDag-Erling Smørgrav 1970b7579f77SDag-Erling Smørgrav int local_zone_str2type(const char* type, enum localzone_type* t) 1971b7579f77SDag-Erling Smørgrav { 1972b7579f77SDag-Erling Smørgrav if(strcmp(type, "deny") == 0) 1973b7579f77SDag-Erling Smørgrav *t = local_zone_deny; 1974b7579f77SDag-Erling Smørgrav else if(strcmp(type, "refuse") == 0) 1975b7579f77SDag-Erling Smørgrav *t = local_zone_refuse; 1976b7579f77SDag-Erling Smørgrav else if(strcmp(type, "static") == 0) 1977b7579f77SDag-Erling Smørgrav *t = local_zone_static; 1978b7579f77SDag-Erling Smørgrav else if(strcmp(type, "transparent") == 0) 1979b7579f77SDag-Erling Smørgrav *t = local_zone_transparent; 1980b7579f77SDag-Erling Smørgrav else if(strcmp(type, "typetransparent") == 0) 1981b7579f77SDag-Erling Smørgrav *t = local_zone_typetransparent; 1982b7579f77SDag-Erling Smørgrav else if(strcmp(type, "redirect") == 0) 1983b7579f77SDag-Erling Smørgrav *t = local_zone_redirect; 19846480faa8SDag-Erling Smørgrav else if(strcmp(type, "inform") == 0) 19856480faa8SDag-Erling Smørgrav *t = local_zone_inform; 198609a3aaf3SDag-Erling Smørgrav else if(strcmp(type, "inform_deny") == 0) 198709a3aaf3SDag-Erling Smørgrav *t = local_zone_inform_deny; 1988e86b9096SDag-Erling Smørgrav else if(strcmp(type, "inform_redirect") == 0) 1989e86b9096SDag-Erling Smørgrav *t = local_zone_inform_redirect; 1990b5663de9SDag-Erling Smørgrav else if(strcmp(type, "always_transparent") == 0) 1991b5663de9SDag-Erling Smørgrav *t = local_zone_always_transparent; 19928f76bb7dSCy Schubert else if(strcmp(type, "block_a") == 0) 19938f76bb7dSCy Schubert *t = local_zone_block_a; 1994b5663de9SDag-Erling Smørgrav else if(strcmp(type, "always_refuse") == 0) 1995b5663de9SDag-Erling Smørgrav *t = local_zone_always_refuse; 1996b5663de9SDag-Erling Smørgrav else if(strcmp(type, "always_nxdomain") == 0) 1997b5663de9SDag-Erling Smørgrav *t = local_zone_always_nxdomain; 1998091e9e46SCy Schubert else if(strcmp(type, "always_nodata") == 0) 1999091e9e46SCy Schubert *t = local_zone_always_nodata; 2000091e9e46SCy Schubert else if(strcmp(type, "always_deny") == 0) 2001091e9e46SCy Schubert *t = local_zone_always_deny; 2002f44e67d1SCy Schubert else if(strcmp(type, "always_null") == 0) 2003f44e67d1SCy Schubert *t = local_zone_always_null; 200457bddd21SDag-Erling Smørgrav else if(strcmp(type, "noview") == 0) 200557bddd21SDag-Erling Smørgrav *t = local_zone_noview; 200624e36522SCy Schubert else if(strcmp(type, "truncate") == 0) 200724e36522SCy Schubert *t = local_zone_truncate; 2008c7f4d7adSDag-Erling Smørgrav else if(strcmp(type, "nodefault") == 0) 2009c7f4d7adSDag-Erling Smørgrav *t = local_zone_nodefault; 2010b7579f77SDag-Erling Smørgrav else return 0; 2011b7579f77SDag-Erling Smørgrav return 1; 2012b7579f77SDag-Erling Smørgrav } 2013b7579f77SDag-Erling Smørgrav 2014b7579f77SDag-Erling Smørgrav /** iterate over the kiddies of the given name and set their parent ptr */ 2015b7579f77SDag-Erling Smørgrav static void 2016b7579f77SDag-Erling Smørgrav set_kiddo_parents(struct local_zone* z, struct local_zone* match, 2017b7579f77SDag-Erling Smørgrav struct local_zone* newp) 2018b7579f77SDag-Erling Smørgrav { 2019b7579f77SDag-Erling Smørgrav /* both zones and z are locked already */ 2020b7579f77SDag-Erling Smørgrav /* in the sorted rbtree, the kiddies of z are located after z */ 2021b7579f77SDag-Erling Smørgrav /* z must be present in the tree */ 2022b7579f77SDag-Erling Smørgrav struct local_zone* p = z; 2023b7579f77SDag-Erling Smørgrav p = (struct local_zone*)rbtree_next(&p->node); 2024b7579f77SDag-Erling Smørgrav while(p!=(struct local_zone*)RBTREE_NULL && 2025b7579f77SDag-Erling Smørgrav p->dclass == z->dclass && dname_strict_subdomain(p->name, 2026b7579f77SDag-Erling Smørgrav p->namelabs, z->name, z->namelabs)) { 2027b7579f77SDag-Erling Smørgrav /* update parent ptr */ 2028b7579f77SDag-Erling Smørgrav /* only when matches with existing parent pointer, so that 2029b7579f77SDag-Erling Smørgrav * deeper child structures are not touched, i.e. 2030b7579f77SDag-Erling Smørgrav * update of x, and a.x, b.x, f.b.x, g.b.x, c.x, y 2031b7579f77SDag-Erling Smørgrav * gets to update a.x, b.x and c.x */ 2032b7579f77SDag-Erling Smørgrav lock_rw_wrlock(&p->lock); 2033b7579f77SDag-Erling Smørgrav if(p->parent == match) 2034b7579f77SDag-Erling Smørgrav p->parent = newp; 2035b7579f77SDag-Erling Smørgrav lock_rw_unlock(&p->lock); 2036b7579f77SDag-Erling Smørgrav p = (struct local_zone*)rbtree_next(&p->node); 2037b7579f77SDag-Erling Smørgrav } 2038b7579f77SDag-Erling Smørgrav } 2039b7579f77SDag-Erling Smørgrav 2040b7579f77SDag-Erling Smørgrav struct local_zone* local_zones_add_zone(struct local_zones* zones, 2041b7579f77SDag-Erling Smørgrav uint8_t* name, size_t len, int labs, uint16_t dclass, 2042b7579f77SDag-Erling Smørgrav enum localzone_type tp) 2043b7579f77SDag-Erling Smørgrav { 204456850988SCy Schubert int exact; 2045b7579f77SDag-Erling Smørgrav /* create */ 204656850988SCy Schubert struct local_zone *prev; 2047b7579f77SDag-Erling Smørgrav struct local_zone* z = local_zone_create(name, len, labs, tp, dclass); 2048e2d15004SDag-Erling Smørgrav if(!z) { 2049e2d15004SDag-Erling Smørgrav free(name); 2050e2d15004SDag-Erling Smørgrav return NULL; 2051e2d15004SDag-Erling Smørgrav } 2052b7579f77SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 2053b7579f77SDag-Erling Smørgrav 2054b7579f77SDag-Erling Smørgrav /* find the closest parent */ 205556850988SCy Schubert prev = local_zones_find_le(zones, name, len, labs, dclass, &exact); 205656850988SCy Schubert if(!exact) 205756850988SCy Schubert z->parent = find_closest_parent(z, prev); 2058b7579f77SDag-Erling Smørgrav 2059b7579f77SDag-Erling Smørgrav /* insert into the tree */ 206056850988SCy Schubert if(exact||!rbtree_insert(&zones->ztree, &z->node)) { 2061b7579f77SDag-Erling Smørgrav /* duplicate entry! */ 2062b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 2063b7579f77SDag-Erling Smørgrav local_zone_delete(z); 2064b7579f77SDag-Erling Smørgrav log_err("internal: duplicate entry in local_zones_add_zone"); 2065b7579f77SDag-Erling Smørgrav return NULL; 2066b7579f77SDag-Erling Smørgrav } 2067b7579f77SDag-Erling Smørgrav 2068b7579f77SDag-Erling Smørgrav /* set parent pointers right */ 2069b7579f77SDag-Erling Smørgrav set_kiddo_parents(z, z->parent, z); 2070b7579f77SDag-Erling Smørgrav 2071b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 2072b7579f77SDag-Erling Smørgrav return z; 2073b7579f77SDag-Erling Smørgrav } 2074b7579f77SDag-Erling Smørgrav 2075b7579f77SDag-Erling Smørgrav void local_zones_del_zone(struct local_zones* zones, struct local_zone* z) 2076b7579f77SDag-Erling Smørgrav { 2077b7579f77SDag-Erling Smørgrav /* fix up parents in tree */ 2078b7579f77SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 2079b7579f77SDag-Erling Smørgrav set_kiddo_parents(z, z, z->parent); 2080b7579f77SDag-Erling Smørgrav 2081b7579f77SDag-Erling Smørgrav /* remove from tree */ 2082b7579f77SDag-Erling Smørgrav (void)rbtree_delete(&zones->ztree, z); 2083b7579f77SDag-Erling Smørgrav 2084b7579f77SDag-Erling Smørgrav /* delete the zone */ 2085b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 2086b7579f77SDag-Erling Smørgrav local_zone_delete(z); 2087b7579f77SDag-Erling Smørgrav } 2088b7579f77SDag-Erling Smørgrav 2089b7579f77SDag-Erling Smørgrav int 209017d15b25SDag-Erling Smørgrav local_zones_add_RR(struct local_zones* zones, const char* rr) 2091b7579f77SDag-Erling Smørgrav { 2092b7579f77SDag-Erling Smørgrav uint8_t* rr_name; 2093971980c3SDag-Erling Smørgrav uint16_t rr_class, rr_type; 2094b7579f77SDag-Erling Smørgrav size_t len; 2095b7579f77SDag-Erling Smørgrav int labs; 2096b7579f77SDag-Erling Smørgrav struct local_zone* z; 2097b7579f77SDag-Erling Smørgrav int r; 2098971980c3SDag-Erling Smørgrav if(!get_rr_nameclass(rr, &rr_name, &rr_class, &rr_type)) { 2099b7579f77SDag-Erling Smørgrav return 0; 2100b7579f77SDag-Erling Smørgrav } 2101b7579f77SDag-Erling Smørgrav labs = dname_count_size_labels(rr_name, &len); 210217d15b25SDag-Erling Smørgrav /* could first try readlock then get writelock if zone does not exist, 210317d15b25SDag-Erling Smørgrav * but we do not add enough RRs (from multiple threads) to optimize */ 210417d15b25SDag-Erling Smørgrav lock_rw_wrlock(&zones->lock); 2105971980c3SDag-Erling Smørgrav z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type); 2106b7579f77SDag-Erling Smørgrav if(!z) { 2107b7579f77SDag-Erling Smørgrav z = local_zones_add_zone(zones, rr_name, len, labs, rr_class, 2108b7579f77SDag-Erling Smørgrav local_zone_transparent); 2109b7579f77SDag-Erling Smørgrav if(!z) { 211017d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 2111b7579f77SDag-Erling Smørgrav return 0; 2112b7579f77SDag-Erling Smørgrav } 2113b7579f77SDag-Erling Smørgrav } else { 2114b7579f77SDag-Erling Smørgrav free(rr_name); 2115b7579f77SDag-Erling Smørgrav } 2116b7579f77SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 211717d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 211817d15b25SDag-Erling Smørgrav r = lz_enter_rr_into_zone(z, rr); 2119b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 2120b7579f77SDag-Erling Smørgrav return r; 2121b7579f77SDag-Erling Smørgrav } 2122b7579f77SDag-Erling Smørgrav 2123b7579f77SDag-Erling Smørgrav /** returns true if the node is terminal so no deeper domain names exist */ 2124b7579f77SDag-Erling Smørgrav static int 2125b7579f77SDag-Erling Smørgrav is_terminal(struct local_data* d) 2126b7579f77SDag-Erling Smørgrav { 2127b7579f77SDag-Erling Smørgrav /* for empty nonterminals, the deeper domain names are sorted 2128b7579f77SDag-Erling Smørgrav * right after them, so simply check the next name in the tree 2129b7579f77SDag-Erling Smørgrav */ 2130b7579f77SDag-Erling Smørgrav struct local_data* n = (struct local_data*)rbtree_next(&d->node); 2131b7579f77SDag-Erling Smørgrav if(n == (struct local_data*)RBTREE_NULL) 2132b7579f77SDag-Erling Smørgrav return 1; /* last in tree, no deeper node */ 2133b7579f77SDag-Erling Smørgrav if(dname_strict_subdomain(n->name, n->namelabs, d->name, d->namelabs)) 2134b7579f77SDag-Erling Smørgrav return 0; /* there is a deeper node */ 2135b7579f77SDag-Erling Smørgrav return 1; 2136b7579f77SDag-Erling Smørgrav } 2137b7579f77SDag-Erling Smørgrav 2138b7579f77SDag-Erling Smørgrav /** delete empty terminals from tree when final data is deleted */ 2139b7579f77SDag-Erling Smørgrav static void 2140b7579f77SDag-Erling Smørgrav del_empty_term(struct local_zone* z, struct local_data* d, 2141b7579f77SDag-Erling Smørgrav uint8_t* name, size_t len, int labs) 2142b7579f77SDag-Erling Smørgrav { 2143b7579f77SDag-Erling Smørgrav while(d && d->rrsets == NULL && is_terminal(d)) { 2144b7579f77SDag-Erling Smørgrav /* is this empty nonterminal? delete */ 2145b7579f77SDag-Erling Smørgrav /* note, no memory recycling in zone region */ 2146b7579f77SDag-Erling Smørgrav (void)rbtree_delete(&z->data, d); 2147b7579f77SDag-Erling Smørgrav 2148b7579f77SDag-Erling Smørgrav /* go up and to the next label */ 2149b7579f77SDag-Erling Smørgrav if(dname_is_root(name)) 2150b7579f77SDag-Erling Smørgrav return; 2151b7579f77SDag-Erling Smørgrav dname_remove_label(&name, &len); 2152b7579f77SDag-Erling Smørgrav labs--; 2153091e9e46SCy Schubert d = local_zone_find_data(z, name, len, labs); 2154b7579f77SDag-Erling Smørgrav } 2155b7579f77SDag-Erling Smørgrav } 2156b7579f77SDag-Erling Smørgrav 2157971980c3SDag-Erling Smørgrav /** find and remove type from list in domain struct */ 2158971980c3SDag-Erling Smørgrav static void 2159971980c3SDag-Erling Smørgrav del_local_rrset(struct local_data* d, uint16_t dtype) 2160971980c3SDag-Erling Smørgrav { 2161971980c3SDag-Erling Smørgrav struct local_rrset* prev=NULL, *p=d->rrsets; 2162971980c3SDag-Erling Smørgrav while(p && ntohs(p->rrset->rk.type) != dtype) { 2163971980c3SDag-Erling Smørgrav prev = p; 2164971980c3SDag-Erling Smørgrav p = p->next; 2165971980c3SDag-Erling Smørgrav } 2166971980c3SDag-Erling Smørgrav if(!p) 2167971980c3SDag-Erling Smørgrav return; /* rrset type not found */ 2168971980c3SDag-Erling Smørgrav /* unlink it */ 2169971980c3SDag-Erling Smørgrav if(prev) prev->next = p->next; 2170971980c3SDag-Erling Smørgrav else d->rrsets = p->next; 2171971980c3SDag-Erling Smørgrav /* no memory recycling for zone deletions ... */ 2172971980c3SDag-Erling Smørgrav } 2173971980c3SDag-Erling Smørgrav 2174b7579f77SDag-Erling Smørgrav void local_zones_del_data(struct local_zones* zones, 2175b7579f77SDag-Erling Smørgrav uint8_t* name, size_t len, int labs, uint16_t dclass) 2176b7579f77SDag-Erling Smørgrav { 2177b7579f77SDag-Erling Smørgrav /* find zone */ 2178b7579f77SDag-Erling Smørgrav struct local_zone* z; 2179b7579f77SDag-Erling Smørgrav struct local_data* d; 2180971980c3SDag-Erling Smørgrav 2181971980c3SDag-Erling Smørgrav /* remove DS */ 218217d15b25SDag-Erling Smørgrav lock_rw_rdlock(&zones->lock); 2183971980c3SDag-Erling Smørgrav z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS); 2184971980c3SDag-Erling Smørgrav if(z) { 2185971980c3SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 2186091e9e46SCy Schubert d = local_zone_find_data(z, name, len, labs); 2187971980c3SDag-Erling Smørgrav if(d) { 2188971980c3SDag-Erling Smørgrav del_local_rrset(d, LDNS_RR_TYPE_DS); 2189971980c3SDag-Erling Smørgrav del_empty_term(z, d, name, len, labs); 2190971980c3SDag-Erling Smørgrav } 2191971980c3SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 2192971980c3SDag-Erling Smørgrav } 2193971980c3SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 2194971980c3SDag-Erling Smørgrav 2195971980c3SDag-Erling Smørgrav /* remove other types */ 2196971980c3SDag-Erling Smørgrav lock_rw_rdlock(&zones->lock); 2197971980c3SDag-Erling Smørgrav z = local_zones_lookup(zones, name, len, labs, dclass, 0); 2198b7579f77SDag-Erling Smørgrav if(!z) { 2199b7579f77SDag-Erling Smørgrav /* no such zone, we're done */ 220017d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 2201b7579f77SDag-Erling Smørgrav return; 2202b7579f77SDag-Erling Smørgrav } 2203b7579f77SDag-Erling Smørgrav lock_rw_wrlock(&z->lock); 220417d15b25SDag-Erling Smørgrav lock_rw_unlock(&zones->lock); 2205b7579f77SDag-Erling Smørgrav 2206b7579f77SDag-Erling Smørgrav /* find the domain */ 2207091e9e46SCy Schubert d = local_zone_find_data(z, name, len, labs); 2208b7579f77SDag-Erling Smørgrav if(d) { 2209b7579f77SDag-Erling Smørgrav /* no memory recycling for zone deletions ... */ 2210b7579f77SDag-Erling Smørgrav d->rrsets = NULL; 2211b7579f77SDag-Erling Smørgrav /* did we delete the soa record ? */ 2212f44e67d1SCy Schubert if(query_dname_compare(d->name, z->name) == 0) { 2213b7579f77SDag-Erling Smørgrav z->soa = NULL; 2214f44e67d1SCy Schubert z->soa_negative = NULL; 2215f44e67d1SCy Schubert } 2216b7579f77SDag-Erling Smørgrav 2217b7579f77SDag-Erling Smørgrav /* cleanup the empty nonterminals for this name */ 2218b7579f77SDag-Erling Smørgrav del_empty_term(z, d, name, len, labs); 2219b7579f77SDag-Erling Smørgrav } 2220b7579f77SDag-Erling Smørgrav 2221b7579f77SDag-Erling Smørgrav lock_rw_unlock(&z->lock); 2222b7579f77SDag-Erling Smørgrav } 2223*be771a7bSCy Schubert 2224*be771a7bSCy Schubert /** Get memory usage for local_zone */ 2225*be771a7bSCy Schubert static size_t 2226*be771a7bSCy Schubert local_zone_get_mem(struct local_zone* z) 2227*be771a7bSCy Schubert { 2228*be771a7bSCy Schubert size_t m = sizeof(*z); 2229*be771a7bSCy Schubert lock_rw_rdlock(&z->lock); 2230*be771a7bSCy Schubert m += z->namelen + z->taglen + regional_get_mem(z->region); 2231*be771a7bSCy Schubert lock_rw_unlock(&z->lock); 2232*be771a7bSCy Schubert return m; 2233*be771a7bSCy Schubert } 2234*be771a7bSCy Schubert 2235*be771a7bSCy Schubert size_t local_zones_get_mem(struct local_zones* zones) 2236*be771a7bSCy Schubert { 2237*be771a7bSCy Schubert struct local_zone* z; 2238*be771a7bSCy Schubert size_t m; 2239*be771a7bSCy Schubert if(!zones) return 0; 2240*be771a7bSCy Schubert m = sizeof(*zones); 2241*be771a7bSCy Schubert lock_rw_rdlock(&zones->lock); 2242*be771a7bSCy Schubert RBTREE_FOR(z, struct local_zone*, &zones->ztree) { 2243*be771a7bSCy Schubert m += local_zone_get_mem(z); 2244*be771a7bSCy Schubert } 2245*be771a7bSCy Schubert lock_rw_unlock(&zones->lock); 2246*be771a7bSCy Schubert return m; 2247*be771a7bSCy Schubert } 2248*be771a7bSCy Schubert 2249*be771a7bSCy Schubert void local_zones_swap_tree(struct local_zones* zones, struct local_zones* data) 2250*be771a7bSCy Schubert { 2251*be771a7bSCy Schubert rbtree_type oldtree = zones->ztree; 2252*be771a7bSCy Schubert zones->ztree = data->ztree; 2253*be771a7bSCy Schubert data->ztree = oldtree; 2254*be771a7bSCy Schubert } 2255