00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/magic.h>
00025 #include <isc/mem.h>
00026 #include <isc/rwlock.h>
00027 #include <isc/sockaddr.h>
00028 #include <isc/util.h>
00029
00030 #include <dns/forward.h>
00031 #include <dns/rbt.h>
00032 #include <dns/result.h>
00033 #include <dns/types.h>
00034
00035 struct dns_fwdtable {
00036
00037 unsigned int magic;
00038 isc_mem_t *mctx;
00039 isc_rwlock_t rwlock;
00040
00041 dns_rbt_t *table;
00042 };
00043
00044 #define FWDTABLEMAGIC ISC_MAGIC('F', 'w', 'd', 'T')
00045 #define VALID_FWDTABLE(ft) ISC_MAGIC_VALID(ft, FWDTABLEMAGIC)
00046
00047 static void
00048 auto_detach(void *, void *);
00049
00050 isc_result_t
00051 dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep) {
00052 dns_fwdtable_t *fwdtable;
00053 isc_result_t result;
00054
00055 REQUIRE(fwdtablep != NULL && *fwdtablep == NULL);
00056
00057 fwdtable = isc_mem_get(mctx, sizeof(dns_fwdtable_t));
00058 if (fwdtable == NULL)
00059 return (ISC_R_NOMEMORY);
00060
00061 fwdtable->table = NULL;
00062 result = dns_rbt_create(mctx, auto_detach, fwdtable, &fwdtable->table);
00063 if (result != ISC_R_SUCCESS)
00064 goto cleanup_fwdtable;
00065
00066 result = isc_rwlock_init(&fwdtable->rwlock, 0, 0);
00067 if (result != ISC_R_SUCCESS)
00068 goto cleanup_rbt;
00069
00070 fwdtable->mctx = NULL;
00071 isc_mem_attach(mctx, &fwdtable->mctx);
00072 fwdtable->magic = FWDTABLEMAGIC;
00073 *fwdtablep = fwdtable;
00074
00075 return (ISC_R_SUCCESS);
00076
00077 cleanup_rbt:
00078 dns_rbt_destroy(&fwdtable->table);
00079
00080 cleanup_fwdtable:
00081 isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
00082
00083 return (result);
00084 }
00085
00086 isc_result_t
00087 dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, dns_name_t *name,
00088 dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t fwdpolicy)
00089 {
00090 isc_result_t result;
00091 dns_forwarders_t *forwarders;
00092 dns_forwarder_t *fwd, *nfwd;
00093
00094 REQUIRE(VALID_FWDTABLE(fwdtable));
00095
00096 forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t));
00097 if (forwarders == NULL)
00098 return (ISC_R_NOMEMORY);
00099
00100 ISC_LIST_INIT(forwarders->fwdrs);
00101 for (fwd = ISC_LIST_HEAD(*fwdrs);
00102 fwd != NULL;
00103 fwd = ISC_LIST_NEXT(fwd, link))
00104 {
00105 nfwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t));
00106 if (nfwd == NULL) {
00107 result = ISC_R_NOMEMORY;
00108 goto cleanup;
00109 }
00110 *nfwd = *fwd;
00111 ISC_LINK_INIT(nfwd, link);
00112 ISC_LIST_APPEND(forwarders->fwdrs, nfwd, link);
00113 }
00114 forwarders->fwdpolicy = fwdpolicy;
00115
00116 RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
00117 result = dns_rbt_addname(fwdtable->table, name, forwarders);
00118 RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
00119
00120 if (result != ISC_R_SUCCESS)
00121 goto cleanup;
00122
00123 return (ISC_R_SUCCESS);
00124
00125 cleanup:
00126 while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
00127 fwd = ISC_LIST_HEAD(forwarders->fwdrs);
00128 ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
00129 isc_mem_put(fwdtable->mctx, fwd, sizeof(isc_sockaddr_t));
00130 }
00131 isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
00132 return (result);
00133 }
00134
00135 isc_result_t
00136 dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name,
00137 isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy)
00138 {
00139 isc_result_t result;
00140 dns_forwarders_t *forwarders;
00141 dns_forwarder_t *fwd;
00142 isc_sockaddr_t *sa;
00143
00144 REQUIRE(VALID_FWDTABLE(fwdtable));
00145
00146 forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t));
00147 if (forwarders == NULL)
00148 return (ISC_R_NOMEMORY);
00149
00150 ISC_LIST_INIT(forwarders->fwdrs);
00151 for (sa = ISC_LIST_HEAD(*addrs);
00152 sa != NULL;
00153 sa = ISC_LIST_NEXT(sa, link))
00154 {
00155 fwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t));
00156 if (fwd == NULL) {
00157 result = ISC_R_NOMEMORY;
00158 goto cleanup;
00159 }
00160 fwd->addr = *sa;
00161 fwd->dscp = -1;
00162 ISC_LINK_INIT(fwd, link);
00163 ISC_LIST_APPEND(forwarders->fwdrs, fwd, link);
00164 }
00165 forwarders->fwdpolicy = fwdpolicy;
00166
00167 RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
00168 result = dns_rbt_addname(fwdtable->table, name, forwarders);
00169 RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
00170
00171 if (result != ISC_R_SUCCESS)
00172 goto cleanup;
00173
00174 return (ISC_R_SUCCESS);
00175
00176 cleanup:
00177 while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
00178 fwd = ISC_LIST_HEAD(forwarders->fwdrs);
00179 ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
00180 isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t));
00181 }
00182 isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
00183 return (result);
00184 }
00185
00186 isc_result_t
00187 dns_fwdtable_delete(dns_fwdtable_t *fwdtable, dns_name_t *name) {
00188 isc_result_t result;
00189
00190 REQUIRE(VALID_FWDTABLE(fwdtable));
00191
00192 RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
00193 result = dns_rbt_deletename(fwdtable->table, name, ISC_FALSE);
00194 RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
00195
00196 if (result == DNS_R_PARTIALMATCH)
00197 result = ISC_R_NOTFOUND;
00198
00199 return (result);
00200 }
00201
00202 isc_result_t
00203 dns_fwdtable_find(dns_fwdtable_t *fwdtable, dns_name_t *name,
00204 dns_forwarders_t **forwardersp)
00205 {
00206 return (dns_fwdtable_find2(fwdtable, name, NULL, forwardersp));
00207 }
00208
00209 isc_result_t
00210 dns_fwdtable_find2(dns_fwdtable_t *fwdtable, dns_name_t *name,
00211 dns_name_t *foundname, dns_forwarders_t **forwardersp)
00212 {
00213 isc_result_t result;
00214
00215 REQUIRE(VALID_FWDTABLE(fwdtable));
00216
00217 RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
00218
00219 result = dns_rbt_findname(fwdtable->table, name, 0, foundname,
00220 (void **)forwardersp);
00221 if (result == DNS_R_PARTIALMATCH)
00222 result = ISC_R_SUCCESS;
00223
00224 RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
00225
00226 return (result);
00227 }
00228
00229 void
00230 dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) {
00231 dns_fwdtable_t *fwdtable;
00232 isc_mem_t *mctx;
00233
00234 REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep));
00235
00236 fwdtable = *fwdtablep;
00237
00238 dns_rbt_destroy(&fwdtable->table);
00239 isc_rwlock_destroy(&fwdtable->rwlock);
00240 fwdtable->magic = 0;
00241 mctx = fwdtable->mctx;
00242 isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
00243 isc_mem_detach(&mctx);
00244
00245 *fwdtablep = NULL;
00246 }
00247
00248
00249
00250
00251
00252 static void
00253 auto_detach(void *data, void *arg) {
00254 dns_forwarders_t *forwarders = data;
00255 dns_fwdtable_t *fwdtable = arg;
00256 dns_forwarder_t *fwd;
00257
00258 UNUSED(arg);
00259
00260 while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
00261 fwd = ISC_LIST_HEAD(forwarders->fwdrs);
00262 ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
00263 isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t));
00264 }
00265 isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
00266 }