1*b7579f77SDag-Erling Smørgrav /* 2*b7579f77SDag-Erling Smørgrav * util/storage/dnstree.c - support for rbtree types suitable for DNS code. 3*b7579f77SDag-Erling Smørgrav * 4*b7579f77SDag-Erling Smørgrav * Copyright (c) 2008, NLnet Labs. All rights reserved. 5*b7579f77SDag-Erling Smørgrav * 6*b7579f77SDag-Erling Smørgrav * This software is open source. 7*b7579f77SDag-Erling Smørgrav * 8*b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9*b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10*b7579f77SDag-Erling Smørgrav * are met: 11*b7579f77SDag-Erling Smørgrav * 12*b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14*b7579f77SDag-Erling Smørgrav * 15*b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17*b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18*b7579f77SDag-Erling Smørgrav * 19*b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20*b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21*b7579f77SDag-Erling Smørgrav * specific prior written permission. 22*b7579f77SDag-Erling Smørgrav * 23*b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24*b7579f77SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25*b7579f77SDag-Erling Smørgrav * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26*b7579f77SDag-Erling Smørgrav * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27*b7579f77SDag-Erling Smørgrav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28*b7579f77SDag-Erling Smørgrav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29*b7579f77SDag-Erling Smørgrav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30*b7579f77SDag-Erling Smørgrav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31*b7579f77SDag-Erling Smørgrav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32*b7579f77SDag-Erling Smørgrav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33*b7579f77SDag-Erling Smørgrav * POSSIBILITY OF SUCH DAMAGE. 34*b7579f77SDag-Erling Smørgrav */ 35*b7579f77SDag-Erling Smørgrav 36*b7579f77SDag-Erling Smørgrav /** 37*b7579f77SDag-Erling Smørgrav * \file 38*b7579f77SDag-Erling Smørgrav * 39*b7579f77SDag-Erling Smørgrav * This file contains structures combining types and functions to 40*b7579f77SDag-Erling Smørgrav * manipulate those structures that help building DNS lookup trees. 41*b7579f77SDag-Erling Smørgrav */ 42*b7579f77SDag-Erling Smørgrav #include "config.h" 43*b7579f77SDag-Erling Smørgrav #include "util/storage/dnstree.h" 44*b7579f77SDag-Erling Smørgrav #include "util/data/dname.h" 45*b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 46*b7579f77SDag-Erling Smørgrav 47*b7579f77SDag-Erling Smørgrav int name_tree_compare(const void* k1, const void* k2) 48*b7579f77SDag-Erling Smørgrav { 49*b7579f77SDag-Erling Smørgrav struct name_tree_node* x = (struct name_tree_node*)k1; 50*b7579f77SDag-Erling Smørgrav struct name_tree_node* y = (struct name_tree_node*)k2; 51*b7579f77SDag-Erling Smørgrav int m; 52*b7579f77SDag-Erling Smørgrav if(x->dclass != y->dclass) { 53*b7579f77SDag-Erling Smørgrav if(x->dclass < y->dclass) 54*b7579f77SDag-Erling Smørgrav return -1; 55*b7579f77SDag-Erling Smørgrav return 1; 56*b7579f77SDag-Erling Smørgrav } 57*b7579f77SDag-Erling Smørgrav return dname_lab_cmp(x->name, x->labs, y->name, y->labs, &m); 58*b7579f77SDag-Erling Smørgrav } 59*b7579f77SDag-Erling Smørgrav 60*b7579f77SDag-Erling Smørgrav int addr_tree_compare(const void* k1, const void* k2) 61*b7579f77SDag-Erling Smørgrav { 62*b7579f77SDag-Erling Smørgrav struct addr_tree_node* n1 = (struct addr_tree_node*)k1; 63*b7579f77SDag-Erling Smørgrav struct addr_tree_node* n2 = (struct addr_tree_node*)k2; 64*b7579f77SDag-Erling Smørgrav int r = sockaddr_cmp_addr(&n1->addr, n1->addrlen, &n2->addr, 65*b7579f77SDag-Erling Smørgrav n2->addrlen); 66*b7579f77SDag-Erling Smørgrav if(r != 0) return r; 67*b7579f77SDag-Erling Smørgrav if(n1->net < n2->net) 68*b7579f77SDag-Erling Smørgrav return -1; 69*b7579f77SDag-Erling Smørgrav if(n1->net > n2->net) 70*b7579f77SDag-Erling Smørgrav return 1; 71*b7579f77SDag-Erling Smørgrav return 0; 72*b7579f77SDag-Erling Smørgrav } 73*b7579f77SDag-Erling Smørgrav 74*b7579f77SDag-Erling Smørgrav void name_tree_init(rbtree_t* tree) 75*b7579f77SDag-Erling Smørgrav { 76*b7579f77SDag-Erling Smørgrav rbtree_init(tree, &name_tree_compare); 77*b7579f77SDag-Erling Smørgrav } 78*b7579f77SDag-Erling Smørgrav 79*b7579f77SDag-Erling Smørgrav void addr_tree_init(rbtree_t* tree) 80*b7579f77SDag-Erling Smørgrav { 81*b7579f77SDag-Erling Smørgrav rbtree_init(tree, &addr_tree_compare); 82*b7579f77SDag-Erling Smørgrav } 83*b7579f77SDag-Erling Smørgrav 84*b7579f77SDag-Erling Smørgrav int name_tree_insert(rbtree_t* tree, struct name_tree_node* node, 85*b7579f77SDag-Erling Smørgrav uint8_t* name, size_t len, int labs, uint16_t dclass) 86*b7579f77SDag-Erling Smørgrav { 87*b7579f77SDag-Erling Smørgrav node->node.key = node; 88*b7579f77SDag-Erling Smørgrav node->name = name; 89*b7579f77SDag-Erling Smørgrav node->len = len; 90*b7579f77SDag-Erling Smørgrav node->labs = labs; 91*b7579f77SDag-Erling Smørgrav node->dclass = dclass; 92*b7579f77SDag-Erling Smørgrav node->parent = NULL; 93*b7579f77SDag-Erling Smørgrav return rbtree_insert(tree, &node->node) != NULL; 94*b7579f77SDag-Erling Smørgrav } 95*b7579f77SDag-Erling Smørgrav 96*b7579f77SDag-Erling Smørgrav int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node, 97*b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t addrlen, int net) 98*b7579f77SDag-Erling Smørgrav { 99*b7579f77SDag-Erling Smørgrav node->node.key = node; 100*b7579f77SDag-Erling Smørgrav memcpy(&node->addr, addr, addrlen); 101*b7579f77SDag-Erling Smørgrav node->addrlen = addrlen; 102*b7579f77SDag-Erling Smørgrav node->net = net; 103*b7579f77SDag-Erling Smørgrav node->parent = NULL; 104*b7579f77SDag-Erling Smørgrav return rbtree_insert(tree, &node->node) != NULL; 105*b7579f77SDag-Erling Smørgrav } 106*b7579f77SDag-Erling Smørgrav 107*b7579f77SDag-Erling Smørgrav void addr_tree_init_parents(rbtree_t* tree) 108*b7579f77SDag-Erling Smørgrav { 109*b7579f77SDag-Erling Smørgrav struct addr_tree_node* node, *prev = NULL, *p; 110*b7579f77SDag-Erling Smørgrav int m; 111*b7579f77SDag-Erling Smørgrav RBTREE_FOR(node, struct addr_tree_node*, tree) { 112*b7579f77SDag-Erling Smørgrav node->parent = NULL; 113*b7579f77SDag-Erling Smørgrav if(!prev || prev->addrlen != node->addrlen) { 114*b7579f77SDag-Erling Smørgrav prev = node; 115*b7579f77SDag-Erling Smørgrav continue; 116*b7579f77SDag-Erling Smørgrav } 117*b7579f77SDag-Erling Smørgrav m = addr_in_common(&prev->addr, prev->net, &node->addr, 118*b7579f77SDag-Erling Smørgrav node->net, node->addrlen); 119*b7579f77SDag-Erling Smørgrav /* sort order like: ::/0, 1::/2, 1::/4, ... 2::/2 */ 120*b7579f77SDag-Erling Smørgrav /* find the previous, or parent-parent-parent */ 121*b7579f77SDag-Erling Smørgrav for(p = prev; p; p = p->parent) 122*b7579f77SDag-Erling Smørgrav if(p->net <= m) { 123*b7579f77SDag-Erling Smørgrav /* ==: since prev matched m, this is closest*/ 124*b7579f77SDag-Erling Smørgrav /* <: prev matches more, but is not a parent, 125*b7579f77SDag-Erling Smørgrav * this one is a (grand)parent */ 126*b7579f77SDag-Erling Smørgrav node->parent = p; 127*b7579f77SDag-Erling Smørgrav break; 128*b7579f77SDag-Erling Smørgrav } 129*b7579f77SDag-Erling Smørgrav prev = node; 130*b7579f77SDag-Erling Smørgrav } 131*b7579f77SDag-Erling Smørgrav } 132*b7579f77SDag-Erling Smørgrav 133*b7579f77SDag-Erling Smørgrav void name_tree_init_parents(rbtree_t* tree) 134*b7579f77SDag-Erling Smørgrav { 135*b7579f77SDag-Erling Smørgrav struct name_tree_node* node, *prev = NULL, *p; 136*b7579f77SDag-Erling Smørgrav int m; 137*b7579f77SDag-Erling Smørgrav RBTREE_FOR(node, struct name_tree_node*, tree) { 138*b7579f77SDag-Erling Smørgrav node->parent = NULL; 139*b7579f77SDag-Erling Smørgrav if(!prev || prev->dclass != node->dclass) { 140*b7579f77SDag-Erling Smørgrav prev = node; 141*b7579f77SDag-Erling Smørgrav continue; 142*b7579f77SDag-Erling Smørgrav } 143*b7579f77SDag-Erling Smørgrav (void)dname_lab_cmp(prev->name, prev->labs, node->name, 144*b7579f77SDag-Erling Smørgrav node->labs, &m); /* we know prev is smaller */ 145*b7579f77SDag-Erling Smørgrav /* sort order like: . com. bla.com. zwb.com. net. */ 146*b7579f77SDag-Erling Smørgrav /* find the previous, or parent-parent-parent */ 147*b7579f77SDag-Erling Smørgrav for(p = prev; p; p = p->parent) 148*b7579f77SDag-Erling Smørgrav if(p->labs <= m) { 149*b7579f77SDag-Erling Smørgrav /* ==: since prev matched m, this is closest*/ 150*b7579f77SDag-Erling Smørgrav /* <: prev matches more, but is not a parent, 151*b7579f77SDag-Erling Smørgrav * this one is a (grand)parent */ 152*b7579f77SDag-Erling Smørgrav node->parent = p; 153*b7579f77SDag-Erling Smørgrav break; 154*b7579f77SDag-Erling Smørgrav } 155*b7579f77SDag-Erling Smørgrav prev = node; 156*b7579f77SDag-Erling Smørgrav } 157*b7579f77SDag-Erling Smørgrav } 158*b7579f77SDag-Erling Smørgrav 159*b7579f77SDag-Erling Smørgrav struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name, 160*b7579f77SDag-Erling Smørgrav size_t len, int labs, uint16_t dclass) 161*b7579f77SDag-Erling Smørgrav { 162*b7579f77SDag-Erling Smørgrav struct name_tree_node key; 163*b7579f77SDag-Erling Smørgrav key.node.key = &key; 164*b7579f77SDag-Erling Smørgrav key.name = name; 165*b7579f77SDag-Erling Smørgrav key.len = len; 166*b7579f77SDag-Erling Smørgrav key.labs = labs; 167*b7579f77SDag-Erling Smørgrav key.dclass = dclass; 168*b7579f77SDag-Erling Smørgrav return (struct name_tree_node*)rbtree_search(tree, &key); 169*b7579f77SDag-Erling Smørgrav } 170*b7579f77SDag-Erling Smørgrav 171*b7579f77SDag-Erling Smørgrav struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name, 172*b7579f77SDag-Erling Smørgrav size_t len, int labs, uint16_t dclass) 173*b7579f77SDag-Erling Smørgrav { 174*b7579f77SDag-Erling Smørgrav rbnode_t* res = NULL; 175*b7579f77SDag-Erling Smørgrav struct name_tree_node *result; 176*b7579f77SDag-Erling Smørgrav struct name_tree_node key; 177*b7579f77SDag-Erling Smørgrav key.node.key = &key; 178*b7579f77SDag-Erling Smørgrav key.name = name; 179*b7579f77SDag-Erling Smørgrav key.len = len; 180*b7579f77SDag-Erling Smørgrav key.labs = labs; 181*b7579f77SDag-Erling Smørgrav key.dclass = dclass; 182*b7579f77SDag-Erling Smørgrav if(rbtree_find_less_equal(tree, &key, &res)) { 183*b7579f77SDag-Erling Smørgrav /* exact */ 184*b7579f77SDag-Erling Smørgrav result = (struct name_tree_node*)res; 185*b7579f77SDag-Erling Smørgrav } else { 186*b7579f77SDag-Erling Smørgrav /* smaller element (or no element) */ 187*b7579f77SDag-Erling Smørgrav int m; 188*b7579f77SDag-Erling Smørgrav result = (struct name_tree_node*)res; 189*b7579f77SDag-Erling Smørgrav if(!result || result->dclass != dclass) 190*b7579f77SDag-Erling Smørgrav return NULL; 191*b7579f77SDag-Erling Smørgrav /* count number of labels matched */ 192*b7579f77SDag-Erling Smørgrav (void)dname_lab_cmp(result->name, result->labs, key.name, 193*b7579f77SDag-Erling Smørgrav key.labs, &m); 194*b7579f77SDag-Erling Smørgrav while(result) { /* go up until qname is subdomain of stub */ 195*b7579f77SDag-Erling Smørgrav if(result->labs <= m) 196*b7579f77SDag-Erling Smørgrav break; 197*b7579f77SDag-Erling Smørgrav result = result->parent; 198*b7579f77SDag-Erling Smørgrav } 199*b7579f77SDag-Erling Smørgrav } 200*b7579f77SDag-Erling Smørgrav return result; 201*b7579f77SDag-Erling Smørgrav } 202*b7579f77SDag-Erling Smørgrav 203*b7579f77SDag-Erling Smørgrav struct addr_tree_node* addr_tree_lookup(rbtree_t* tree, 204*b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t addrlen) 205*b7579f77SDag-Erling Smørgrav { 206*b7579f77SDag-Erling Smørgrav rbnode_t* res = NULL; 207*b7579f77SDag-Erling Smørgrav struct addr_tree_node* result; 208*b7579f77SDag-Erling Smørgrav struct addr_tree_node key; 209*b7579f77SDag-Erling Smørgrav key.node.key = &key; 210*b7579f77SDag-Erling Smørgrav memcpy(&key.addr, addr, addrlen); 211*b7579f77SDag-Erling Smørgrav key.addrlen = addrlen; 212*b7579f77SDag-Erling Smørgrav key.net = (addr_is_ip6(addr, addrlen)?128:32); 213*b7579f77SDag-Erling Smørgrav if(rbtree_find_less_equal(tree, &key, &res)) { 214*b7579f77SDag-Erling Smørgrav /* exact */ 215*b7579f77SDag-Erling Smørgrav return (struct addr_tree_node*)res; 216*b7579f77SDag-Erling Smørgrav } else { 217*b7579f77SDag-Erling Smørgrav /* smaller element (or no element) */ 218*b7579f77SDag-Erling Smørgrav int m; 219*b7579f77SDag-Erling Smørgrav result = (struct addr_tree_node*)res; 220*b7579f77SDag-Erling Smørgrav if(!result || result->addrlen != addrlen) 221*b7579f77SDag-Erling Smørgrav return 0; 222*b7579f77SDag-Erling Smørgrav /* count number of bits matched */ 223*b7579f77SDag-Erling Smørgrav m = addr_in_common(&result->addr, result->net, addr, 224*b7579f77SDag-Erling Smørgrav key.net, addrlen); 225*b7579f77SDag-Erling Smørgrav while(result) { /* go up until addr is inside netblock */ 226*b7579f77SDag-Erling Smørgrav if(result->net <= m) 227*b7579f77SDag-Erling Smørgrav break; 228*b7579f77SDag-Erling Smørgrav result = result->parent; 229*b7579f77SDag-Erling Smørgrav } 230*b7579f77SDag-Erling Smørgrav } 231*b7579f77SDag-Erling Smørgrav return result; 232*b7579f77SDag-Erling Smørgrav } 233*b7579f77SDag-Erling Smørgrav 234*b7579f77SDag-Erling Smørgrav int 235*b7579f77SDag-Erling Smørgrav name_tree_next_root(rbtree_t* tree, uint16_t* dclass) 236*b7579f77SDag-Erling Smørgrav { 237*b7579f77SDag-Erling Smørgrav struct name_tree_node key; 238*b7579f77SDag-Erling Smørgrav rbnode_t* n; 239*b7579f77SDag-Erling Smørgrav struct name_tree_node* p; 240*b7579f77SDag-Erling Smørgrav if(*dclass == 0) { 241*b7579f77SDag-Erling Smørgrav /* first root item is first item in tree */ 242*b7579f77SDag-Erling Smørgrav n = rbtree_first(tree); 243*b7579f77SDag-Erling Smørgrav if(n == RBTREE_NULL) 244*b7579f77SDag-Erling Smørgrav return 0; 245*b7579f77SDag-Erling Smørgrav p = (struct name_tree_node*)n; 246*b7579f77SDag-Erling Smørgrav if(dname_is_root(p->name)) { 247*b7579f77SDag-Erling Smørgrav *dclass = p->dclass; 248*b7579f77SDag-Erling Smørgrav return 1; 249*b7579f77SDag-Erling Smørgrav } 250*b7579f77SDag-Erling Smørgrav /* root not first item? search for higher items */ 251*b7579f77SDag-Erling Smørgrav *dclass = p->dclass + 1; 252*b7579f77SDag-Erling Smørgrav return name_tree_next_root(tree, dclass); 253*b7579f77SDag-Erling Smørgrav } 254*b7579f77SDag-Erling Smørgrav /* find class n in tree, we may get a direct hit, or if we don't 255*b7579f77SDag-Erling Smørgrav * this is the last item of the previous class so rbtree_next() takes 256*b7579f77SDag-Erling Smørgrav * us to the next root (if any) */ 257*b7579f77SDag-Erling Smørgrav key.node.key = &key; 258*b7579f77SDag-Erling Smørgrav key.name = (uint8_t*)"\000"; 259*b7579f77SDag-Erling Smørgrav key.len = 1; 260*b7579f77SDag-Erling Smørgrav key.labs = 0; 261*b7579f77SDag-Erling Smørgrav key.dclass = *dclass; 262*b7579f77SDag-Erling Smørgrav n = NULL; 263*b7579f77SDag-Erling Smørgrav if(rbtree_find_less_equal(tree, &key, &n)) { 264*b7579f77SDag-Erling Smørgrav /* exact */ 265*b7579f77SDag-Erling Smørgrav return 1; 266*b7579f77SDag-Erling Smørgrav } else { 267*b7579f77SDag-Erling Smørgrav /* smaller element */ 268*b7579f77SDag-Erling Smørgrav if(!n || n == RBTREE_NULL) 269*b7579f77SDag-Erling Smørgrav return 0; /* nothing found */ 270*b7579f77SDag-Erling Smørgrav n = rbtree_next(n); 271*b7579f77SDag-Erling Smørgrav if(n == RBTREE_NULL) 272*b7579f77SDag-Erling Smørgrav return 0; /* no higher */ 273*b7579f77SDag-Erling Smørgrav p = (struct name_tree_node*)n; 274*b7579f77SDag-Erling Smørgrav if(dname_is_root(p->name)) { 275*b7579f77SDag-Erling Smørgrav *dclass = p->dclass; 276*b7579f77SDag-Erling Smørgrav return 1; 277*b7579f77SDag-Erling Smørgrav } 278*b7579f77SDag-Erling Smørgrav /* not a root node, return next higher item */ 279*b7579f77SDag-Erling Smørgrav *dclass = p->dclass+1; 280*b7579f77SDag-Erling Smørgrav return name_tree_next_root(tree, dclass); 281*b7579f77SDag-Erling Smørgrav } 282*b7579f77SDag-Erling Smørgrav } 283