1 /* 2 * services/view.c - named views containing local zones authority service. 3 * 4 * Copyright (c) 2016, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains functions to enable named views that can hold local zone 40 * authority service. 41 */ 42 #include "config.h" 43 #include "services/view.h" 44 #include "services/localzone.h" 45 #include "util/config_file.h" 46 47 int 48 view_cmp(const void* v1, const void* v2) 49 { 50 struct view* a = (struct view*)v1; 51 struct view* b = (struct view*)v2; 52 53 return strcmp(a->name, b->name); 54 } 55 56 struct views* 57 views_create(void) 58 { 59 struct views* v = (struct views*)calloc(1, 60 sizeof(*v)); 61 if(!v) 62 return NULL; 63 rbtree_init(&v->vtree, &view_cmp); 64 lock_rw_init(&v->lock); 65 lock_protect(&v->lock, &v->vtree, sizeof(v->vtree)); 66 return v; 67 } 68 69 /* \noop (ignore this comment for doxygen) 70 * This prototype is defined in in respip.h, but we want to avoid 71 * unnecessary dependencies */ 72 void respip_set_delete(struct respip_set *set); 73 74 void 75 view_delete(struct view* v) 76 { 77 if(!v) 78 return; 79 lock_rw_destroy(&v->lock); 80 local_zones_delete(v->local_zones); 81 respip_set_delete(v->respip_set); 82 free(v->name); 83 free(v); 84 } 85 86 static void 87 delviewnode(rbnode_type* n, void* ATTR_UNUSED(arg)) 88 { 89 struct view* v = (struct view*)n; 90 view_delete(v); 91 } 92 93 void 94 views_delete(struct views* v) 95 { 96 if(!v) 97 return; 98 lock_rw_destroy(&v->lock); 99 traverse_postorder(&v->vtree, delviewnode, NULL); 100 free(v); 101 } 102 103 /** create a new view */ 104 static struct view* 105 view_create(char* name) 106 { 107 struct view* v = (struct view*)calloc(1, sizeof(*v)); 108 if(!v) 109 return NULL; 110 v->node.key = v; 111 if(!(v->name = strdup(name))) { 112 free(v); 113 return NULL; 114 } 115 lock_rw_init(&v->lock); 116 lock_protect(&v->lock, &v->name, sizeof(*v)-sizeof(rbnode_type)); 117 return v; 118 } 119 120 /** enter a new view returns with WRlock */ 121 static struct view* 122 views_enter_view_name(struct views* vs, char* name) 123 { 124 struct view* v = view_create(name); 125 if(!v) { 126 log_err("out of memory"); 127 return NULL; 128 } 129 130 /* add to rbtree */ 131 lock_rw_wrlock(&vs->lock); 132 lock_rw_wrlock(&v->lock); 133 if(!rbtree_insert(&vs->vtree, &v->node)) { 134 log_warn("duplicate view: %s", name); 135 lock_rw_unlock(&v->lock); 136 view_delete(v); 137 lock_rw_unlock(&vs->lock); 138 return NULL; 139 } 140 lock_rw_unlock(&vs->lock); 141 return v; 142 } 143 144 int 145 views_apply_cfg(struct views* vs, struct config_file* cfg) 146 { 147 struct config_view* cv; 148 struct view* v; 149 struct config_file lz_cfg; 150 /* Check existence of name in first view (last in config). Rest of 151 * views are already checked when parsing config. */ 152 if(cfg->views && !cfg->views->name) { 153 log_err("view without a name"); 154 return 0; 155 } 156 for(cv = cfg->views; cv; cv = cv->next) { 157 /* create and enter view */ 158 if(!(v = views_enter_view_name(vs, cv->name))) 159 return 0; 160 v->isfirst = cv->isfirst; 161 if(cv->local_zones || cv->local_data) { 162 if(!(v->local_zones = local_zones_create())){ 163 lock_rw_unlock(&v->lock); 164 return 0; 165 } 166 memset(&lz_cfg, 0, sizeof(lz_cfg)); 167 lz_cfg.local_zones = cv->local_zones; 168 lz_cfg.local_data = cv->local_data; 169 lz_cfg.local_zones_nodefault = 170 cv->local_zones_nodefault; 171 if(v->isfirst) { 172 /* Do not add defaults to view-specific 173 * local-zone when global local zone will be 174 * used. */ 175 struct config_strlist* nd; 176 lz_cfg.local_zones_disable_default = 1; 177 /* Add nodefault zones to list of zones to add, 178 * so they will be used as if they are 179 * configured as type transparent */ 180 for(nd = cv->local_zones_nodefault; nd; 181 nd = nd->next) { 182 char* nd_str, *nd_type; 183 nd_str = strdup(nd->str); 184 if(!nd_str) { 185 log_err("out of memory"); 186 lock_rw_unlock(&v->lock); 187 return 0; 188 } 189 nd_type = strdup("nodefault"); 190 if(!nd_type) { 191 log_err("out of memory"); 192 free(nd_str); 193 lock_rw_unlock(&v->lock); 194 return 0; 195 } 196 if(!cfg_str2list_insert( 197 &lz_cfg.local_zones, nd_str, 198 nd_type)) { 199 log_err("failed to insert " 200 "default zones into " 201 "local-zone list"); 202 lock_rw_unlock(&v->lock); 203 return 0; 204 } 205 } 206 } 207 if(!local_zones_apply_cfg(v->local_zones, &lz_cfg)){ 208 lock_rw_unlock(&v->lock); 209 return 0; 210 } 211 /* local_zones, local_zones_nodefault and local_data 212 * are free'd from config_view by local_zones_apply_cfg. 213 * Set pointers to NULL. */ 214 cv->local_zones = NULL; 215 cv->local_data = NULL; 216 cv->local_zones_nodefault = NULL; 217 } 218 lock_rw_unlock(&v->lock); 219 } 220 return 1; 221 } 222 223 /** find a view by name */ 224 struct view* 225 views_find_view(struct views* vs, const char* name, int write) 226 { 227 struct view* v; 228 struct view key; 229 key.node.key = &v; 230 key.name = (char *)name; 231 lock_rw_rdlock(&vs->lock); 232 if(!(v = (struct view*)rbtree_search(&vs->vtree, &key.node))) { 233 lock_rw_unlock(&vs->lock); 234 return 0; 235 } 236 if(write) { 237 lock_rw_wrlock(&v->lock); 238 } else { 239 lock_rw_rdlock(&v->lock); 240 } 241 lock_rw_unlock(&vs->lock); 242 return v; 243 } 244 245 void views_print(struct views* v) 246 { 247 /* TODO implement print */ 248 (void)v; 249 } 250