1/* 2 * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000, 2001 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: forward.c,v 1.14 2009/09/02 23:48:02 tbox Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <isc/magic.h> 25#include <isc/mem.h> 26#include <isc/rwlock.h> 27#include <isc/sockaddr.h> 28#include <isc/util.h> 29 30#include <dns/forward.h> 31#include <dns/rbt.h> 32#include <dns/result.h> 33#include <dns/types.h> 34 35struct dns_fwdtable { 36 /* Unlocked. */ 37 unsigned int magic; 38 isc_mem_t *mctx; 39 isc_rwlock_t rwlock; 40 /* Locked by lock. */ 41 dns_rbt_t *table; 42}; 43 44#define FWDTABLEMAGIC ISC_MAGIC('F', 'w', 'd', 'T') 45#define VALID_FWDTABLE(ft) ISC_MAGIC_VALID(ft, FWDTABLEMAGIC) 46 47static void 48auto_detach(void *, void *); 49 50isc_result_t 51dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep) { 52 dns_fwdtable_t *fwdtable; 53 isc_result_t result; 54 55 REQUIRE(fwdtablep != NULL && *fwdtablep == NULL); 56 57 fwdtable = isc_mem_get(mctx, sizeof(dns_fwdtable_t)); 58 if (fwdtable == NULL) 59 return (ISC_R_NOMEMORY); 60 61 fwdtable->table = NULL; 62 result = dns_rbt_create(mctx, auto_detach, fwdtable, &fwdtable->table); 63 if (result != ISC_R_SUCCESS) 64 goto cleanup_fwdtable; 65 66 result = isc_rwlock_init(&fwdtable->rwlock, 0, 0); 67 if (result != ISC_R_SUCCESS) 68 goto cleanup_rbt; 69 70 fwdtable->mctx = NULL; 71 isc_mem_attach(mctx, &fwdtable->mctx); 72 fwdtable->magic = FWDTABLEMAGIC; 73 *fwdtablep = fwdtable; 74 75 return (ISC_R_SUCCESS); 76 77 cleanup_rbt: 78 dns_rbt_destroy(&fwdtable->table); 79 80 cleanup_fwdtable: 81 isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t)); 82 83 return (result); 84} 85 86isc_result_t 87dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name, 88 isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy) 89{ 90 isc_result_t result; 91 dns_forwarders_t *forwarders; 92 isc_sockaddr_t *sa, *nsa; 93 94 REQUIRE(VALID_FWDTABLE(fwdtable)); 95 96 forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t)); 97 if (forwarders == NULL) 98 return (ISC_R_NOMEMORY); 99 100 ISC_LIST_INIT(forwarders->addrs); 101 for (sa = ISC_LIST_HEAD(*addrs); 102 sa != NULL; 103 sa = ISC_LIST_NEXT(sa, link)) 104 { 105 nsa = isc_mem_get(fwdtable->mctx, sizeof(isc_sockaddr_t)); 106 if (nsa == NULL) { 107 result = ISC_R_NOMEMORY; 108 goto cleanup; 109 } 110 *nsa = *sa; 111 ISC_LINK_INIT(nsa, link); 112 ISC_LIST_APPEND(forwarders->addrs, nsa, link); 113 } 114 forwarders->fwdpolicy = fwdpolicy; 115 116 RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write); 117 result = dns_rbt_addname(fwdtable->table, name, forwarders); 118 RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write); 119 120 if (result != ISC_R_SUCCESS) 121 goto cleanup; 122 123 return (ISC_R_SUCCESS); 124 125 cleanup: 126 while (!ISC_LIST_EMPTY(forwarders->addrs)) { 127 sa = ISC_LIST_HEAD(forwarders->addrs); 128 ISC_LIST_UNLINK(forwarders->addrs, sa, link); 129 isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t)); 130 } 131 isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t)); 132 return (result); 133} 134 135isc_result_t 136dns_fwdtable_delete(dns_fwdtable_t *fwdtable, dns_name_t *name) { 137 isc_result_t result; 138 139 REQUIRE(VALID_FWDTABLE(fwdtable)); 140 141 RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write); 142 result = dns_rbt_deletename(fwdtable->table, name, ISC_FALSE); 143 RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write); 144 145 if (result == DNS_R_PARTIALMATCH) 146 result = ISC_R_NOTFOUND; 147 148 return (result); 149} 150 151isc_result_t 152dns_fwdtable_find(dns_fwdtable_t *fwdtable, dns_name_t *name, 153 dns_forwarders_t **forwardersp) 154{ 155 return (dns_fwdtable_find2(fwdtable, name, NULL, forwardersp)); 156} 157 158isc_result_t 159dns_fwdtable_find2(dns_fwdtable_t *fwdtable, dns_name_t *name, 160 dns_name_t *foundname, dns_forwarders_t **forwardersp) 161{ 162 isc_result_t result; 163 164 REQUIRE(VALID_FWDTABLE(fwdtable)); 165 166 RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read); 167 168 result = dns_rbt_findname(fwdtable->table, name, 0, foundname, 169 (void **)forwardersp); 170 if (result == DNS_R_PARTIALMATCH) 171 result = ISC_R_SUCCESS; 172 173 RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read); 174 175 return (result); 176} 177 178void 179dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) { 180 dns_fwdtable_t *fwdtable; 181 isc_mem_t *mctx; 182 183 REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep)); 184 185 fwdtable = *fwdtablep; 186 187 dns_rbt_destroy(&fwdtable->table); 188 isc_rwlock_destroy(&fwdtable->rwlock); 189 fwdtable->magic = 0; 190 mctx = fwdtable->mctx; 191 isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t)); 192 isc_mem_detach(&mctx); 193 194 *fwdtablep = NULL; 195} 196 197/*** 198 *** Private 199 ***/ 200 201static void 202auto_detach(void *data, void *arg) { 203 dns_forwarders_t *forwarders = data; 204 dns_fwdtable_t *fwdtable = arg; 205 isc_sockaddr_t *sa; 206 207 UNUSED(arg); 208 209 while (!ISC_LIST_EMPTY(forwarders->addrs)) { 210 sa = ISC_LIST_HEAD(forwarders->addrs); 211 ISC_LIST_UNLINK(forwarders->addrs, sa, link); 212 isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t)); 213 } 214 isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t)); 215} 216