1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * iterator/iter_hints.c - iterative resolver module stub and root hints. 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 assist the iterator module. 40b7579f77SDag-Erling Smørgrav * Keep track of stub and root hints, and read those from config. 41b7579f77SDag-Erling Smørgrav */ 42b7579f77SDag-Erling Smørgrav #include "config.h" 43b7579f77SDag-Erling Smørgrav #include "iterator/iter_hints.h" 44b7579f77SDag-Erling Smørgrav #include "iterator/iter_delegpt.h" 45b7579f77SDag-Erling Smørgrav #include "util/log.h" 46b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 47b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 48b7579f77SDag-Erling Smørgrav #include "util/data/dname.h" 4909a3aaf3SDag-Erling Smørgrav #include "sldns/rrdef.h" 5009a3aaf3SDag-Erling Smørgrav #include "sldns/str2wire.h" 5109a3aaf3SDag-Erling Smørgrav #include "sldns/wire2str.h" 52b7579f77SDag-Erling Smørgrav 53b7579f77SDag-Erling Smørgrav struct iter_hints* 54b7579f77SDag-Erling Smørgrav hints_create(void) 55b7579f77SDag-Erling Smørgrav { 56b7579f77SDag-Erling Smørgrav struct iter_hints* hints = (struct iter_hints*)calloc(1, 57b7579f77SDag-Erling Smørgrav sizeof(struct iter_hints)); 58b7579f77SDag-Erling Smørgrav if(!hints) 59b7579f77SDag-Erling Smørgrav return NULL; 60335c7cdaSCy Schubert lock_rw_init(&hints->lock); 61335c7cdaSCy Schubert lock_protect(&hints->lock, &hints->tree, sizeof(hints->tree)); 62b7579f77SDag-Erling Smørgrav return hints; 63b7579f77SDag-Erling Smørgrav } 64b7579f77SDag-Erling Smørgrav 65b7579f77SDag-Erling Smørgrav static void hints_stub_free(struct iter_hints_stub* s) 66b7579f77SDag-Erling Smørgrav { 67b7579f77SDag-Erling Smørgrav if(!s) return; 68b7579f77SDag-Erling Smørgrav delegpt_free_mlc(s->dp); 69b7579f77SDag-Erling Smørgrav free(s); 70b7579f77SDag-Erling Smørgrav } 71b7579f77SDag-Erling Smørgrav 723005e0a3SDag-Erling Smørgrav static void delhintnode(rbnode_type* n, void* ATTR_UNUSED(arg)) 73b7579f77SDag-Erling Smørgrav { 74b7579f77SDag-Erling Smørgrav struct iter_hints_stub* node = (struct iter_hints_stub*)n; 75b7579f77SDag-Erling Smørgrav hints_stub_free(node); 76b7579f77SDag-Erling Smørgrav } 77b7579f77SDag-Erling Smørgrav 78b7579f77SDag-Erling Smørgrav static void hints_del_tree(struct iter_hints* hints) 79b7579f77SDag-Erling Smørgrav { 80b7579f77SDag-Erling Smørgrav traverse_postorder(&hints->tree, &delhintnode, NULL); 81b7579f77SDag-Erling Smørgrav } 82b7579f77SDag-Erling Smørgrav 83b7579f77SDag-Erling Smørgrav void 84b7579f77SDag-Erling Smørgrav hints_delete(struct iter_hints* hints) 85b7579f77SDag-Erling Smørgrav { 86b7579f77SDag-Erling Smørgrav if(!hints) 87b7579f77SDag-Erling Smørgrav return; 88335c7cdaSCy Schubert lock_rw_destroy(&hints->lock); 89b7579f77SDag-Erling Smørgrav hints_del_tree(hints); 90b7579f77SDag-Erling Smørgrav free(hints); 91b7579f77SDag-Erling Smørgrav } 92b7579f77SDag-Erling Smørgrav 93b7579f77SDag-Erling Smørgrav /** add hint to delegation hints */ 94b7579f77SDag-Erling Smørgrav static int 95b7579f77SDag-Erling Smørgrav ah(struct delegpt* dp, const char* sv, const char* ip) 96b7579f77SDag-Erling Smørgrav { 97b7579f77SDag-Erling Smørgrav struct sockaddr_storage addr; 98b7579f77SDag-Erling Smørgrav socklen_t addrlen; 9917d15b25SDag-Erling Smørgrav size_t dname_len; 10017d15b25SDag-Erling Smørgrav uint8_t* dname = sldns_str2wire_dname(sv, &dname_len); 10117d15b25SDag-Erling Smørgrav if(!dname) { 102b7579f77SDag-Erling Smørgrav log_err("could not parse %s", sv); 103b7579f77SDag-Erling Smørgrav return 0; 104b7579f77SDag-Erling Smørgrav } 1059cf5bc93SCy Schubert if(!delegpt_add_ns_mlc(dp, dname, 0, NULL, UNBOUND_DNS_PORT) || 106865f46b2SCy Schubert !extstrtoaddr(ip, &addr, &addrlen, UNBOUND_DNS_PORT) || 10717d15b25SDag-Erling Smørgrav !delegpt_add_target_mlc(dp, dname, dname_len, 108b7579f77SDag-Erling Smørgrav &addr, addrlen, 0, 0)) { 10917d15b25SDag-Erling Smørgrav free(dname); 110b7579f77SDag-Erling Smørgrav return 0; 111b7579f77SDag-Erling Smørgrav } 11217d15b25SDag-Erling Smørgrav free(dname); 113b7579f77SDag-Erling Smørgrav return 1; 114b7579f77SDag-Erling Smørgrav } 115b7579f77SDag-Erling Smørgrav 116b7579f77SDag-Erling Smørgrav /** obtain compiletime provided root hints */ 117b7579f77SDag-Erling Smørgrav static struct delegpt* 118b7579f77SDag-Erling Smørgrav compile_time_root_prime(int do_ip4, int do_ip6) 119b7579f77SDag-Erling Smørgrav { 120b7579f77SDag-Erling Smørgrav /* from: 121b7579f77SDag-Erling Smørgrav ; This file is made available by InterNIC 122b7579f77SDag-Erling Smørgrav ; under anonymous FTP as 123b7579f77SDag-Erling Smørgrav ; file /domain/named.cache 124b7579f77SDag-Erling Smørgrav ; on server FTP.INTERNIC.NET 125b7579f77SDag-Erling Smørgrav ; -OR- RS.INTERNIC.NET 126b7579f77SDag-Erling Smørgrav ; 1278ed2b524SDag-Erling Smørgrav ; related version of root zone: changes-on-20120103 128b7579f77SDag-Erling Smørgrav */ 129b7579f77SDag-Erling Smørgrav struct delegpt* dp = delegpt_create_mlc((uint8_t*)"\000"); 130b7579f77SDag-Erling Smørgrav if(!dp) 131b7579f77SDag-Erling Smørgrav return NULL; 132b7579f77SDag-Erling Smørgrav dp->has_parent_side_NS = 1; 133b7579f77SDag-Erling Smørgrav if(do_ip4) { 1348ed2b524SDag-Erling Smørgrav if(!ah(dp, "A.ROOT-SERVERS.NET.", "198.41.0.4")) goto failed; 135b7c0c8c1SCy Schubert if(!ah(dp, "B.ROOT-SERVERS.NET.", "170.247.170.2")) goto failed; 1368ed2b524SDag-Erling Smørgrav if(!ah(dp, "C.ROOT-SERVERS.NET.", "192.33.4.12")) goto failed; 1378ed2b524SDag-Erling Smørgrav if(!ah(dp, "D.ROOT-SERVERS.NET.", "199.7.91.13")) goto failed; 1388ed2b524SDag-Erling Smørgrav if(!ah(dp, "E.ROOT-SERVERS.NET.", "192.203.230.10")) goto failed; 1398ed2b524SDag-Erling Smørgrav if(!ah(dp, "F.ROOT-SERVERS.NET.", "192.5.5.241")) goto failed; 1408ed2b524SDag-Erling Smørgrav if(!ah(dp, "G.ROOT-SERVERS.NET.", "192.112.36.4")) goto failed; 141b75612f8SDag-Erling Smørgrav if(!ah(dp, "H.ROOT-SERVERS.NET.", "198.97.190.53")) goto failed; 1428ed2b524SDag-Erling Smørgrav if(!ah(dp, "I.ROOT-SERVERS.NET.", "192.36.148.17")) goto failed; 1438ed2b524SDag-Erling Smørgrav if(!ah(dp, "J.ROOT-SERVERS.NET.", "192.58.128.30")) goto failed; 1448ed2b524SDag-Erling Smørgrav if(!ah(dp, "K.ROOT-SERVERS.NET.", "193.0.14.129")) goto failed; 1458ed2b524SDag-Erling Smørgrav if(!ah(dp, "L.ROOT-SERVERS.NET.", "199.7.83.42")) goto failed; 1468ed2b524SDag-Erling Smørgrav if(!ah(dp, "M.ROOT-SERVERS.NET.", "202.12.27.33")) goto failed; 147b7579f77SDag-Erling Smørgrav } 148b7579f77SDag-Erling Smørgrav if(do_ip6) { 1498ed2b524SDag-Erling Smørgrav if(!ah(dp, "A.ROOT-SERVERS.NET.", "2001:503:ba3e::2:30")) goto failed; 150b7c0c8c1SCy Schubert if(!ah(dp, "B.ROOT-SERVERS.NET.", "2801:1b8:10::b")) goto failed; 151ff825849SDag-Erling Smørgrav if(!ah(dp, "C.ROOT-SERVERS.NET.", "2001:500:2::c")) goto failed; 1528ed2b524SDag-Erling Smørgrav if(!ah(dp, "D.ROOT-SERVERS.NET.", "2001:500:2d::d")) goto failed; 153b5663de9SDag-Erling Smørgrav if(!ah(dp, "E.ROOT-SERVERS.NET.", "2001:500:a8::e")) goto failed; 1548ed2b524SDag-Erling Smørgrav if(!ah(dp, "F.ROOT-SERVERS.NET.", "2001:500:2f::f")) goto failed; 155bc892140SDag-Erling Smørgrav if(!ah(dp, "G.ROOT-SERVERS.NET.", "2001:500:12::d0d")) goto failed; 156b75612f8SDag-Erling Smørgrav if(!ah(dp, "H.ROOT-SERVERS.NET.", "2001:500:1::53")) goto failed; 1578ed2b524SDag-Erling Smørgrav if(!ah(dp, "I.ROOT-SERVERS.NET.", "2001:7fe::53")) goto failed; 1588ed2b524SDag-Erling Smørgrav if(!ah(dp, "J.ROOT-SERVERS.NET.", "2001:503:c27::2:30")) goto failed; 1598ed2b524SDag-Erling Smørgrav if(!ah(dp, "K.ROOT-SERVERS.NET.", "2001:7fd::1")) goto failed; 160a2d0006eSDag-Erling Smørgrav if(!ah(dp, "L.ROOT-SERVERS.NET.", "2001:500:9f::42")) goto failed; 1618ed2b524SDag-Erling Smørgrav if(!ah(dp, "M.ROOT-SERVERS.NET.", "2001:dc3::35")) goto failed; 162b7579f77SDag-Erling Smørgrav } 163b7579f77SDag-Erling Smørgrav return dp; 1648ed2b524SDag-Erling Smørgrav failed: 1658ed2b524SDag-Erling Smørgrav delegpt_free_mlc(dp); 1668ed2b524SDag-Erling Smørgrav return 0; 167b7579f77SDag-Erling Smørgrav } 168b7579f77SDag-Erling Smørgrav 169b7579f77SDag-Erling Smørgrav /** insert new hint info into hint structure */ 170b7579f77SDag-Erling Smørgrav static int 171b7579f77SDag-Erling Smørgrav hints_insert(struct iter_hints* hints, uint16_t c, struct delegpt* dp, 172b7579f77SDag-Erling Smørgrav int noprime) 173b7579f77SDag-Erling Smørgrav { 174b7579f77SDag-Erling Smørgrav struct iter_hints_stub* node = (struct iter_hints_stub*)malloc( 175b7579f77SDag-Erling Smørgrav sizeof(struct iter_hints_stub)); 176b7579f77SDag-Erling Smørgrav if(!node) { 177b7579f77SDag-Erling Smørgrav delegpt_free_mlc(dp); 178b7579f77SDag-Erling Smørgrav return 0; 179b7579f77SDag-Erling Smørgrav } 180b7579f77SDag-Erling Smørgrav node->dp = dp; 181b7579f77SDag-Erling Smørgrav node->noprime = (uint8_t)noprime; 182b7579f77SDag-Erling Smørgrav if(!name_tree_insert(&hints->tree, &node->node, dp->name, dp->namelen, 183b7579f77SDag-Erling Smørgrav dp->namelabs, c)) { 184*be771a7bSCy Schubert char buf[LDNS_MAX_DOMAINLEN]; 1858ed2b524SDag-Erling Smørgrav dname_str(dp->name, buf); 1868ed2b524SDag-Erling Smørgrav log_err("second hints for zone %s ignored.", buf); 187b7579f77SDag-Erling Smørgrav delegpt_free_mlc(dp); 188b7579f77SDag-Erling Smørgrav free(node); 189b7579f77SDag-Erling Smørgrav } 190b7579f77SDag-Erling Smørgrav return 1; 191b7579f77SDag-Erling Smørgrav } 192b7579f77SDag-Erling Smørgrav 193b7579f77SDag-Erling Smørgrav /** set stub name */ 194b7579f77SDag-Erling Smørgrav static struct delegpt* 195b7579f77SDag-Erling Smørgrav read_stubs_name(struct config_stub* s) 196b7579f77SDag-Erling Smørgrav { 197b7579f77SDag-Erling Smørgrav struct delegpt* dp; 19817d15b25SDag-Erling Smørgrav size_t dname_len; 19917d15b25SDag-Erling Smørgrav uint8_t* dname; 200b7579f77SDag-Erling Smørgrav if(!s->name) { 201b7579f77SDag-Erling Smørgrav log_err("stub zone without a name"); 202b7579f77SDag-Erling Smørgrav return NULL; 203b7579f77SDag-Erling Smørgrav } 20417d15b25SDag-Erling Smørgrav dname = sldns_str2wire_dname(s->name, &dname_len); 20517d15b25SDag-Erling Smørgrav if(!dname) { 206b7579f77SDag-Erling Smørgrav log_err("cannot parse stub zone name %s", s->name); 207b7579f77SDag-Erling Smørgrav return NULL; 208b7579f77SDag-Erling Smørgrav } 20917d15b25SDag-Erling Smørgrav if(!(dp=delegpt_create_mlc(dname))) { 21017d15b25SDag-Erling Smørgrav free(dname); 211b7579f77SDag-Erling Smørgrav log_err("out of memory"); 212b7579f77SDag-Erling Smørgrav return NULL; 213b7579f77SDag-Erling Smørgrav } 21417d15b25SDag-Erling Smørgrav free(dname); 215b7579f77SDag-Erling Smørgrav return dp; 216b7579f77SDag-Erling Smørgrav } 217b7579f77SDag-Erling Smørgrav 218b7579f77SDag-Erling Smørgrav /** set stub host names */ 219b7579f77SDag-Erling Smørgrav static int 220b7579f77SDag-Erling Smørgrav read_stubs_host(struct config_stub* s, struct delegpt* dp) 221b7579f77SDag-Erling Smørgrav { 222b7579f77SDag-Erling Smørgrav struct config_strlist* p; 22317d15b25SDag-Erling Smørgrav uint8_t* dname; 2249cf5bc93SCy Schubert char* tls_auth_name; 2259cf5bc93SCy Schubert int port; 226b7579f77SDag-Erling Smørgrav for(p = s->hosts; p; p = p->next) { 227b7579f77SDag-Erling Smørgrav log_assert(p->str); 2289cf5bc93SCy Schubert dname = authextstrtodname(p->str, &port, &tls_auth_name); 22917d15b25SDag-Erling Smørgrav if(!dname) { 230b7579f77SDag-Erling Smørgrav log_err("cannot parse stub %s nameserver name: '%s'", 231b7579f77SDag-Erling Smørgrav s->name, p->str); 232b7579f77SDag-Erling Smørgrav return 0; 233b7579f77SDag-Erling Smørgrav } 2349cf5bc93SCy Schubert #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) 2359cf5bc93SCy Schubert if(tls_auth_name) 2369cf5bc93SCy Schubert log_err("no name verification functionality in " 2379cf5bc93SCy Schubert "ssl library, ignored name for %s", p->str); 2389cf5bc93SCy Schubert #endif 2399cf5bc93SCy Schubert if(!delegpt_add_ns_mlc(dp, dname, 0, tls_auth_name, port)) { 24017d15b25SDag-Erling Smørgrav free(dname); 241b7579f77SDag-Erling Smørgrav log_err("out of memory"); 242b7579f77SDag-Erling Smørgrav return 0; 243b7579f77SDag-Erling Smørgrav } 24417d15b25SDag-Erling Smørgrav free(dname); 245b7579f77SDag-Erling Smørgrav } 246b7579f77SDag-Erling Smørgrav return 1; 247b7579f77SDag-Erling Smørgrav } 248b7579f77SDag-Erling Smørgrav 249b7579f77SDag-Erling Smørgrav /** set stub server addresses */ 250b7579f77SDag-Erling Smørgrav static int 251b7579f77SDag-Erling Smørgrav read_stubs_addr(struct config_stub* s, struct delegpt* dp) 252b7579f77SDag-Erling Smørgrav { 253b7579f77SDag-Erling Smørgrav struct config_strlist* p; 254b7579f77SDag-Erling Smørgrav struct sockaddr_storage addr; 255b7579f77SDag-Erling Smørgrav socklen_t addrlen; 2560fb34990SDag-Erling Smørgrav char* auth_name; 257b7579f77SDag-Erling Smørgrav for(p = s->addrs; p; p = p->next) { 258b7579f77SDag-Erling Smørgrav log_assert(p->str); 2590fb34990SDag-Erling Smørgrav if(!authextstrtoaddr(p->str, &addr, &addrlen, &auth_name)) { 260b7579f77SDag-Erling Smørgrav log_err("cannot parse stub %s ip address: '%s'", 261b7579f77SDag-Erling Smørgrav s->name, p->str); 262b7579f77SDag-Erling Smørgrav return 0; 263b7579f77SDag-Erling Smørgrav } 264e86b9096SDag-Erling Smørgrav #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) 2654c75e3aaSDag-Erling Smørgrav if(auth_name) 2664c75e3aaSDag-Erling Smørgrav log_err("no name verification functionality in " 2674c75e3aaSDag-Erling Smørgrav "ssl library, ignored name for %s", p->str); 2684c75e3aaSDag-Erling Smørgrav #endif 2690fb34990SDag-Erling Smørgrav if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0, 2709cf5bc93SCy Schubert auth_name, -1)) { 271b7579f77SDag-Erling Smørgrav log_err("out of memory"); 272b7579f77SDag-Erling Smørgrav return 0; 273b7579f77SDag-Erling Smørgrav } 274b7579f77SDag-Erling Smørgrav } 275b7579f77SDag-Erling Smørgrav return 1; 276b7579f77SDag-Erling Smørgrav } 277b7579f77SDag-Erling Smørgrav 278b7579f77SDag-Erling Smørgrav /** read stubs config */ 279b7579f77SDag-Erling Smørgrav static int 280b7579f77SDag-Erling Smørgrav read_stubs(struct iter_hints* hints, struct config_file* cfg) 281b7579f77SDag-Erling Smørgrav { 282b7579f77SDag-Erling Smørgrav struct config_stub* s; 283b7579f77SDag-Erling Smørgrav struct delegpt* dp; 284b7579f77SDag-Erling Smørgrav for(s = cfg->stubs; s; s = s->next) { 2858ed2b524SDag-Erling Smørgrav if(!(dp=read_stubs_name(s))) 286b7579f77SDag-Erling Smørgrav return 0; 2878ed2b524SDag-Erling Smørgrav if(!read_stubs_host(s, dp) || !read_stubs_addr(s, dp)) { 2888ed2b524SDag-Erling Smørgrav delegpt_free_mlc(dp); 2898ed2b524SDag-Erling Smørgrav return 0; 2908ed2b524SDag-Erling Smørgrav } 291b7579f77SDag-Erling Smørgrav /* the flag is turned off for 'stub-first' so that the 292b7579f77SDag-Erling Smørgrav * last resort will ask for parent-side NS record and thus 293b7579f77SDag-Erling Smørgrav * fallback to the internet name servers on a failure */ 294b7579f77SDag-Erling Smørgrav dp->has_parent_side_NS = (uint8_t)!s->isfirst; 2954c75e3aaSDag-Erling Smørgrav /* Do not cache if set. */ 2964c75e3aaSDag-Erling Smørgrav dp->no_cache = s->no_cache; 297bc892140SDag-Erling Smørgrav /* ssl_upstream */ 298bc892140SDag-Erling Smørgrav dp->ssl_upstream = (uint8_t)s->ssl_upstream; 29924e36522SCy Schubert /* tcp_upstream */ 30024e36522SCy Schubert dp->tcp_upstream = (uint8_t)s->tcp_upstream; 3018ed2b524SDag-Erling Smørgrav delegpt_log(VERB_QUERY, dp); 302b7579f77SDag-Erling Smørgrav if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime)) 303b7579f77SDag-Erling Smørgrav return 0; 304b7579f77SDag-Erling Smørgrav } 305b7579f77SDag-Erling Smørgrav return 1; 306b7579f77SDag-Erling Smørgrav } 307b7579f77SDag-Erling Smørgrav 308b7579f77SDag-Erling Smørgrav /** read root hints from file */ 309b7579f77SDag-Erling Smørgrav static int 310b7579f77SDag-Erling Smørgrav read_root_hints(struct iter_hints* hints, char* fname) 311b7579f77SDag-Erling Smørgrav { 31217d15b25SDag-Erling Smørgrav struct sldns_file_parse_state pstate; 313b7579f77SDag-Erling Smørgrav struct delegpt* dp; 31417d15b25SDag-Erling Smørgrav uint8_t rr[LDNS_RR_BUF_SIZE]; 31517d15b25SDag-Erling Smørgrav size_t rr_len, dname_len; 31617d15b25SDag-Erling Smørgrav int status; 317b7579f77SDag-Erling Smørgrav uint16_t c = LDNS_RR_CLASS_IN; 318b7579f77SDag-Erling Smørgrav FILE* f = fopen(fname, "r"); 319b7579f77SDag-Erling Smørgrav if(!f) { 320b7579f77SDag-Erling Smørgrav log_err("could not read root hints %s: %s", 321b7579f77SDag-Erling Smørgrav fname, strerror(errno)); 322b7579f77SDag-Erling Smørgrav return 0; 323b7579f77SDag-Erling Smørgrav } 324b7579f77SDag-Erling Smørgrav dp = delegpt_create_mlc(NULL); 325b7579f77SDag-Erling Smørgrav if(!dp) { 326b7579f77SDag-Erling Smørgrav log_err("out of memory reading root hints"); 327b7579f77SDag-Erling Smørgrav fclose(f); 328b7579f77SDag-Erling Smørgrav return 0; 329b7579f77SDag-Erling Smørgrav } 330b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "Reading root hints from %s", fname); 33117d15b25SDag-Erling Smørgrav memset(&pstate, 0, sizeof(pstate)); 33217d15b25SDag-Erling Smørgrav pstate.lineno = 1; 333b7579f77SDag-Erling Smørgrav dp->has_parent_side_NS = 1; 334b7579f77SDag-Erling Smørgrav while(!feof(f)) { 33517d15b25SDag-Erling Smørgrav rr_len = sizeof(rr); 33617d15b25SDag-Erling Smørgrav dname_len = 0; 33717d15b25SDag-Erling Smørgrav status = sldns_fp2wire_rr_buf(f, rr, &rr_len, &dname_len, 33817d15b25SDag-Erling Smørgrav &pstate); 33917d15b25SDag-Erling Smørgrav if(status != 0) { 34017d15b25SDag-Erling Smørgrav log_err("reading root hints %s %d:%d: %s", fname, 34117d15b25SDag-Erling Smørgrav pstate.lineno, LDNS_WIREPARSE_OFFSET(status), 34217d15b25SDag-Erling Smørgrav sldns_get_errorstr_parse(status)); 343b7579f77SDag-Erling Smørgrav goto stop_read; 344b7579f77SDag-Erling Smørgrav } 34517d15b25SDag-Erling Smørgrav if(rr_len == 0) 34617d15b25SDag-Erling Smørgrav continue; /* EMPTY line, TTL or ORIGIN */ 34717d15b25SDag-Erling Smørgrav if(sldns_wirerr_get_type(rr, rr_len, dname_len) 34817d15b25SDag-Erling Smørgrav == LDNS_RR_TYPE_NS) { 34917d15b25SDag-Erling Smørgrav if(!delegpt_add_ns_mlc(dp, sldns_wirerr_get_rdata(rr, 3509cf5bc93SCy Schubert rr_len, dname_len), 0, NULL, UNBOUND_DNS_PORT)) { 351b7579f77SDag-Erling Smørgrav log_err("out of memory reading root hints"); 352b7579f77SDag-Erling Smørgrav goto stop_read; 353b7579f77SDag-Erling Smørgrav } 35417d15b25SDag-Erling Smørgrav c = sldns_wirerr_get_class(rr, rr_len, dname_len); 355b7579f77SDag-Erling Smørgrav if(!dp->name) { 35617d15b25SDag-Erling Smørgrav if(!delegpt_set_name_mlc(dp, rr)) { 357b7579f77SDag-Erling Smørgrav log_err("out of memory."); 358b7579f77SDag-Erling Smørgrav goto stop_read; 359b7579f77SDag-Erling Smørgrav } 360b7579f77SDag-Erling Smørgrav } 36117d15b25SDag-Erling Smørgrav } else if(sldns_wirerr_get_type(rr, rr_len, dname_len) 36217d15b25SDag-Erling Smørgrav == LDNS_RR_TYPE_A && sldns_wirerr_get_rdatalen(rr, 36317d15b25SDag-Erling Smørgrav rr_len, dname_len) == INET_SIZE) { 364b7579f77SDag-Erling Smørgrav struct sockaddr_in sa; 365b7579f77SDag-Erling Smørgrav socklen_t len = (socklen_t)sizeof(sa); 366b7579f77SDag-Erling Smørgrav memset(&sa, 0, len); 367b7579f77SDag-Erling Smørgrav sa.sin_family = AF_INET; 368b7579f77SDag-Erling Smørgrav sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); 369b7579f77SDag-Erling Smørgrav memmove(&sa.sin_addr, 37017d15b25SDag-Erling Smørgrav sldns_wirerr_get_rdata(rr, rr_len, dname_len), 37117d15b25SDag-Erling Smørgrav INET_SIZE); 37217d15b25SDag-Erling Smørgrav if(!delegpt_add_target_mlc(dp, rr, dname_len, 373b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)&sa, len, 374b7579f77SDag-Erling Smørgrav 0, 0)) { 375b7579f77SDag-Erling Smørgrav log_err("out of memory reading root hints"); 376b7579f77SDag-Erling Smørgrav goto stop_read; 377b7579f77SDag-Erling Smørgrav } 37817d15b25SDag-Erling Smørgrav } else if(sldns_wirerr_get_type(rr, rr_len, dname_len) 37917d15b25SDag-Erling Smørgrav == LDNS_RR_TYPE_AAAA && sldns_wirerr_get_rdatalen(rr, 38017d15b25SDag-Erling Smørgrav rr_len, dname_len) == INET6_SIZE) { 381b7579f77SDag-Erling Smørgrav struct sockaddr_in6 sa; 382b7579f77SDag-Erling Smørgrav socklen_t len = (socklen_t)sizeof(sa); 383b7579f77SDag-Erling Smørgrav memset(&sa, 0, len); 384b7579f77SDag-Erling Smørgrav sa.sin6_family = AF_INET6; 385b7579f77SDag-Erling Smørgrav sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); 386b7579f77SDag-Erling Smørgrav memmove(&sa.sin6_addr, 38717d15b25SDag-Erling Smørgrav sldns_wirerr_get_rdata(rr, rr_len, dname_len), 38817d15b25SDag-Erling Smørgrav INET6_SIZE); 38917d15b25SDag-Erling Smørgrav if(!delegpt_add_target_mlc(dp, rr, dname_len, 390b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)&sa, len, 391b7579f77SDag-Erling Smørgrav 0, 0)) { 392b7579f77SDag-Erling Smørgrav log_err("out of memory reading root hints"); 393b7579f77SDag-Erling Smørgrav goto stop_read; 394b7579f77SDag-Erling Smørgrav } 395b7579f77SDag-Erling Smørgrav } else { 39617d15b25SDag-Erling Smørgrav char buf[17]; 39717d15b25SDag-Erling Smørgrav sldns_wire2str_type_buf(sldns_wirerr_get_type(rr, 39817d15b25SDag-Erling Smørgrav rr_len, dname_len), buf, sizeof(buf)); 39917d15b25SDag-Erling Smørgrav log_warn("root hints %s:%d skipping type %s", 40017d15b25SDag-Erling Smørgrav fname, pstate.lineno, buf); 401b7579f77SDag-Erling Smørgrav } 402b7579f77SDag-Erling Smørgrav } 403b7579f77SDag-Erling Smørgrav fclose(f); 404b7579f77SDag-Erling Smørgrav if(!dp->name) { 405b7579f77SDag-Erling Smørgrav log_warn("root hints %s: no NS content", fname); 406b7579f77SDag-Erling Smørgrav delegpt_free_mlc(dp); 407b7579f77SDag-Erling Smørgrav return 1; 408b7579f77SDag-Erling Smørgrav } 40924e36522SCy Schubert delegpt_log(VERB_QUERY, dp); 410b7579f77SDag-Erling Smørgrav if(!hints_insert(hints, c, dp, 0)) { 411b7579f77SDag-Erling Smørgrav return 0; 412b7579f77SDag-Erling Smørgrav } 413b7579f77SDag-Erling Smørgrav return 1; 414b7579f77SDag-Erling Smørgrav 415b7579f77SDag-Erling Smørgrav stop_read: 416b7579f77SDag-Erling Smørgrav delegpt_free_mlc(dp); 417b7579f77SDag-Erling Smørgrav fclose(f); 418b7579f77SDag-Erling Smørgrav return 0; 419b7579f77SDag-Erling Smørgrav } 420b7579f77SDag-Erling Smørgrav 421b7579f77SDag-Erling Smørgrav /** read root hints list */ 422b7579f77SDag-Erling Smørgrav static int 423b7579f77SDag-Erling Smørgrav read_root_hints_list(struct iter_hints* hints, struct config_file* cfg) 424b7579f77SDag-Erling Smørgrav { 425b7579f77SDag-Erling Smørgrav struct config_strlist* p; 426b7579f77SDag-Erling Smørgrav for(p = cfg->root_hints; p; p = p->next) { 427b7579f77SDag-Erling Smørgrav log_assert(p->str); 428b7579f77SDag-Erling Smørgrav if(p->str && p->str[0]) { 429b7579f77SDag-Erling Smørgrav char* f = p->str; 430b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0] && 431b7579f77SDag-Erling Smørgrav strncmp(p->str, cfg->chrootdir, 432b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir)) == 0) 433b7579f77SDag-Erling Smørgrav f += strlen(cfg->chrootdir); 434b7579f77SDag-Erling Smørgrav if(!read_root_hints(hints, f)) 435b7579f77SDag-Erling Smørgrav return 0; 436b7579f77SDag-Erling Smørgrav } 437b7579f77SDag-Erling Smørgrav } 438b7579f77SDag-Erling Smørgrav return 1; 439b7579f77SDag-Erling Smørgrav } 440b7579f77SDag-Erling Smørgrav 441b7579f77SDag-Erling Smørgrav int 442b7579f77SDag-Erling Smørgrav hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg) 443b7579f77SDag-Erling Smørgrav { 444335c7cdaSCy Schubert int nolock = 1; 445335c7cdaSCy Schubert lock_rw_wrlock(&hints->lock); 446b7579f77SDag-Erling Smørgrav hints_del_tree(hints); 447b7579f77SDag-Erling Smørgrav name_tree_init(&hints->tree); 448b7579f77SDag-Erling Smørgrav 449b7579f77SDag-Erling Smørgrav /* read root hints */ 450335c7cdaSCy Schubert if(!read_root_hints_list(hints, cfg)) { 451335c7cdaSCy Schubert lock_rw_unlock(&hints->lock); 452b7579f77SDag-Erling Smørgrav return 0; 453b7579f77SDag-Erling Smørgrav } 454b7579f77SDag-Erling Smørgrav 455335c7cdaSCy Schubert /* read stub hints */ 456335c7cdaSCy Schubert if(!read_stubs(hints, cfg)) { 457335c7cdaSCy Schubert lock_rw_unlock(&hints->lock); 458335c7cdaSCy Schubert return 0; 459335c7cdaSCy Schubert } 460335c7cdaSCy Schubert 461335c7cdaSCy Schubert /* use fallback compiletime root hints */ 462335c7cdaSCy Schubert if(!hints_find_root(hints, LDNS_RR_CLASS_IN, nolock)) { 463335c7cdaSCy Schubert struct delegpt* dp = compile_time_root_prime(cfg->do_ip4, 464335c7cdaSCy Schubert cfg->do_ip6); 465335c7cdaSCy Schubert verbose(VERB_ALGO, "no config, using builtin root hints."); 466335c7cdaSCy Schubert if(!dp) { 467335c7cdaSCy Schubert lock_rw_unlock(&hints->lock); 468335c7cdaSCy Schubert return 0; 469335c7cdaSCy Schubert } 470335c7cdaSCy Schubert if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0)) { 471335c7cdaSCy Schubert lock_rw_unlock(&hints->lock); 472335c7cdaSCy Schubert return 0; 473335c7cdaSCy Schubert } 474335c7cdaSCy Schubert } 475335c7cdaSCy Schubert 476b7579f77SDag-Erling Smørgrav name_tree_init_parents(&hints->tree); 477335c7cdaSCy Schubert lock_rw_unlock(&hints->lock); 478b7579f77SDag-Erling Smørgrav return 1; 479b7579f77SDag-Erling Smørgrav } 480b7579f77SDag-Erling Smørgrav 481b7579f77SDag-Erling Smørgrav struct delegpt* 482335c7cdaSCy Schubert hints_find(struct iter_hints* hints, uint8_t* qname, uint16_t qclass, 483335c7cdaSCy Schubert int nolock) 484335c7cdaSCy Schubert { 485335c7cdaSCy Schubert struct iter_hints_stub *stub; 486335c7cdaSCy Schubert size_t len; 487335c7cdaSCy Schubert int has_dp; 488335c7cdaSCy Schubert int labs = dname_count_size_labels(qname, &len); 489335c7cdaSCy Schubert /* lock_() calls are macros that could be nothing, surround in {} */ 490335c7cdaSCy Schubert if(!nolock) { lock_rw_rdlock(&hints->lock); } 491335c7cdaSCy Schubert stub = (struct iter_hints_stub*)name_tree_find(&hints->tree, 492335c7cdaSCy Schubert qname, len, labs, qclass); 493335c7cdaSCy Schubert has_dp = stub && stub->dp; 494335c7cdaSCy Schubert if(!has_dp && !nolock) { lock_rw_unlock(&hints->lock); } 495335c7cdaSCy Schubert return has_dp?stub->dp:NULL; 496335c7cdaSCy Schubert } 497335c7cdaSCy Schubert 498335c7cdaSCy Schubert struct delegpt* 499335c7cdaSCy Schubert hints_find_root(struct iter_hints* hints, uint16_t qclass, int nolock) 500b7579f77SDag-Erling Smørgrav { 501b7579f77SDag-Erling Smørgrav uint8_t rootlab = 0; 502335c7cdaSCy Schubert return hints_find(hints, &rootlab, qclass, nolock); 503b7579f77SDag-Erling Smørgrav } 504b7579f77SDag-Erling Smørgrav 505b7579f77SDag-Erling Smørgrav struct iter_hints_stub* 506b7579f77SDag-Erling Smørgrav hints_lookup_stub(struct iter_hints* hints, uint8_t* qname, 507335c7cdaSCy Schubert uint16_t qclass, struct delegpt* cache_dp, int nolock) 508b7579f77SDag-Erling Smørgrav { 509b7579f77SDag-Erling Smørgrav size_t len; 510b7579f77SDag-Erling Smørgrav int labs; 511b7579f77SDag-Erling Smørgrav struct iter_hints_stub *r; 512b7579f77SDag-Erling Smørgrav 513b7579f77SDag-Erling Smørgrav /* first lookup the stub */ 514b7579f77SDag-Erling Smørgrav labs = dname_count_size_labels(qname, &len); 515335c7cdaSCy Schubert /* lock_() calls are macros that could be nothing, surround in {} */ 516335c7cdaSCy Schubert if(!nolock) { lock_rw_rdlock(&hints->lock); } 517b7579f77SDag-Erling Smørgrav r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname, 518b7579f77SDag-Erling Smørgrav len, labs, qclass); 519335c7cdaSCy Schubert if(!r) { 520335c7cdaSCy Schubert if(!nolock) { lock_rw_unlock(&hints->lock); } 521335c7cdaSCy Schubert return NULL; 522335c7cdaSCy Schubert } 523b7579f77SDag-Erling Smørgrav 524b7579f77SDag-Erling Smørgrav /* If there is no cache (root prime situation) */ 525b7579f77SDag-Erling Smørgrav if(cache_dp == NULL) { 526b7579f77SDag-Erling Smørgrav if(r->dp->namelabs != 1) 527b7579f77SDag-Erling Smørgrav return r; /* no cache dp, use any non-root stub */ 528335c7cdaSCy Schubert if(!nolock) { lock_rw_unlock(&hints->lock); } 529b7579f77SDag-Erling Smørgrav return NULL; 530b7579f77SDag-Erling Smørgrav } 531b7579f77SDag-Erling Smørgrav 532b7579f77SDag-Erling Smørgrav /* 533b7579f77SDag-Erling Smørgrav * If the stub is same as the delegation we got 534b7579f77SDag-Erling Smørgrav * And has noprime set, we need to 'prime' to use this stub instead. 535b7579f77SDag-Erling Smørgrav */ 536b7579f77SDag-Erling Smørgrav if(r->noprime && query_dname_compare(cache_dp->name, r->dp->name)==0) 537b7579f77SDag-Erling Smørgrav return r; /* use this stub instead of cached dp */ 538b7579f77SDag-Erling Smørgrav 539b7579f77SDag-Erling Smørgrav /* 540b7579f77SDag-Erling Smørgrav * If our cached delegation point is above the hint, we need to prime. 541b7579f77SDag-Erling Smørgrav */ 542b7579f77SDag-Erling Smørgrav if(dname_strict_subdomain(r->dp->name, r->dp->namelabs, 543b7579f77SDag-Erling Smørgrav cache_dp->name, cache_dp->namelabs)) 544b7579f77SDag-Erling Smørgrav return r; /* need to prime this stub */ 545335c7cdaSCy Schubert if(!nolock) { lock_rw_unlock(&hints->lock); } 546b7579f77SDag-Erling Smørgrav return NULL; 547b7579f77SDag-Erling Smørgrav } 548b7579f77SDag-Erling Smørgrav 549335c7cdaSCy Schubert int hints_next_root(struct iter_hints* hints, uint16_t* qclass, int nolock) 550b7579f77SDag-Erling Smørgrav { 551335c7cdaSCy Schubert int ret; 552335c7cdaSCy Schubert /* lock_() calls are macros that could be nothing, surround in {} */ 553335c7cdaSCy Schubert if(!nolock) { lock_rw_rdlock(&hints->lock); } 554335c7cdaSCy Schubert ret = name_tree_next_root(&hints->tree, qclass); 555335c7cdaSCy Schubert if(!nolock) { lock_rw_unlock(&hints->lock); } 556335c7cdaSCy Schubert return ret; 557b7579f77SDag-Erling Smørgrav } 558b7579f77SDag-Erling Smørgrav 559b7579f77SDag-Erling Smørgrav size_t 560b7579f77SDag-Erling Smørgrav hints_get_mem(struct iter_hints* hints) 561b7579f77SDag-Erling Smørgrav { 562b7579f77SDag-Erling Smørgrav size_t s; 563b7579f77SDag-Erling Smørgrav struct iter_hints_stub* p; 564b7579f77SDag-Erling Smørgrav if(!hints) return 0; 565335c7cdaSCy Schubert lock_rw_rdlock(&hints->lock); 566b7579f77SDag-Erling Smørgrav s = sizeof(*hints); 567b7579f77SDag-Erling Smørgrav RBTREE_FOR(p, struct iter_hints_stub*, &hints->tree) { 568b7579f77SDag-Erling Smørgrav s += sizeof(*p) + delegpt_get_mem(p->dp); 569b7579f77SDag-Erling Smørgrav } 570335c7cdaSCy Schubert lock_rw_unlock(&hints->lock); 571b7579f77SDag-Erling Smørgrav return s; 572b7579f77SDag-Erling Smørgrav } 573b7579f77SDag-Erling Smørgrav 574b7579f77SDag-Erling Smørgrav int 575b7579f77SDag-Erling Smørgrav hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp, 576335c7cdaSCy Schubert int noprime, int nolock) 577b7579f77SDag-Erling Smørgrav { 578b7579f77SDag-Erling Smørgrav struct iter_hints_stub *z; 579335c7cdaSCy Schubert /* lock_() calls are macros that could be nothing, surround in {} */ 580335c7cdaSCy Schubert if(!nolock) { lock_rw_wrlock(&hints->lock); } 581b7579f77SDag-Erling Smørgrav if((z=(struct iter_hints_stub*)name_tree_find(&hints->tree, 582b7579f77SDag-Erling Smørgrav dp->name, dp->namelen, dp->namelabs, c)) != NULL) { 583b7579f77SDag-Erling Smørgrav (void)rbtree_delete(&hints->tree, &z->node); 584b7579f77SDag-Erling Smørgrav hints_stub_free(z); 585b7579f77SDag-Erling Smørgrav } 586335c7cdaSCy Schubert if(!hints_insert(hints, c, dp, noprime)) { 587335c7cdaSCy Schubert if(!nolock) { lock_rw_unlock(&hints->lock); } 588b7579f77SDag-Erling Smørgrav return 0; 589335c7cdaSCy Schubert } 590b7579f77SDag-Erling Smørgrav name_tree_init_parents(&hints->tree); 591335c7cdaSCy Schubert if(!nolock) { lock_rw_unlock(&hints->lock); } 592b7579f77SDag-Erling Smørgrav return 1; 593b7579f77SDag-Erling Smørgrav } 594b7579f77SDag-Erling Smørgrav 595b7579f77SDag-Erling Smørgrav void 596335c7cdaSCy Schubert hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm, 597335c7cdaSCy Schubert int nolock) 598b7579f77SDag-Erling Smørgrav { 599b7579f77SDag-Erling Smørgrav struct iter_hints_stub *z; 600b7579f77SDag-Erling Smørgrav size_t len; 601b7579f77SDag-Erling Smørgrav int labs = dname_count_size_labels(nm, &len); 602335c7cdaSCy Schubert /* lock_() calls are macros that could be nothing, surround in {} */ 603335c7cdaSCy Schubert if(!nolock) { lock_rw_wrlock(&hints->lock); } 604b7579f77SDag-Erling Smørgrav if(!(z=(struct iter_hints_stub*)name_tree_find(&hints->tree, 605335c7cdaSCy Schubert nm, len, labs, c))) { 606335c7cdaSCy Schubert if(!nolock) { lock_rw_unlock(&hints->lock); } 607b7579f77SDag-Erling Smørgrav return; /* nothing to do */ 608335c7cdaSCy Schubert } 609b7579f77SDag-Erling Smørgrav (void)rbtree_delete(&hints->tree, &z->node); 610b7579f77SDag-Erling Smørgrav hints_stub_free(z); 611b7579f77SDag-Erling Smørgrav name_tree_init_parents(&hints->tree); 612335c7cdaSCy Schubert if(!nolock) { lock_rw_unlock(&hints->lock); } 613b7579f77SDag-Erling Smørgrav } 614*be771a7bSCy Schubert 615*be771a7bSCy Schubert void 616*be771a7bSCy Schubert hints_swap_tree(struct iter_hints* hints, struct iter_hints* data) 617*be771a7bSCy Schubert { 618*be771a7bSCy Schubert rbnode_type* oldroot = hints->tree.root; 619*be771a7bSCy Schubert size_t oldcount = hints->tree.count; 620*be771a7bSCy Schubert hints->tree.root = data->tree.root; 621*be771a7bSCy Schubert hints->tree.count = data->tree.count; 622*be771a7bSCy Schubert data->tree.root = oldroot; 623*be771a7bSCy Schubert data->tree.count = oldcount; 624*be771a7bSCy Schubert } 625