forward.c revision 1.1 1 1.1 christos /* $NetBSD: forward.c,v 1.1 2018/08/12 12:08:13 christos Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 1.1 christos *
6 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public
7 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this
8 1.1 christos * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 1.1 christos *
10 1.1 christos * See the COPYRIGHT file distributed with this work for additional
11 1.1 christos * information regarding copyright ownership.
12 1.1 christos */
13 1.1 christos
14 1.1 christos /*! \file */
15 1.1 christos
16 1.1 christos #include <config.h>
17 1.1 christos
18 1.1 christos #include <isc/magic.h>
19 1.1 christos #include <isc/mem.h>
20 1.1 christos #include <isc/rwlock.h>
21 1.1 christos #include <isc/util.h>
22 1.1 christos
23 1.1 christos #include <dns/forward.h>
24 1.1 christos #include <dns/rbt.h>
25 1.1 christos #include <dns/result.h>
26 1.1 christos #include <dns/types.h>
27 1.1 christos
28 1.1 christos struct dns_fwdtable {
29 1.1 christos /* Unlocked. */
30 1.1 christos unsigned int magic;
31 1.1 christos isc_mem_t *mctx;
32 1.1 christos isc_rwlock_t rwlock;
33 1.1 christos /* Locked by lock. */
34 1.1 christos dns_rbt_t *table;
35 1.1 christos };
36 1.1 christos
37 1.1 christos #define FWDTABLEMAGIC ISC_MAGIC('F', 'w', 'd', 'T')
38 1.1 christos #define VALID_FWDTABLE(ft) ISC_MAGIC_VALID(ft, FWDTABLEMAGIC)
39 1.1 christos
40 1.1 christos static void
41 1.1 christos auto_detach(void *, void *);
42 1.1 christos
43 1.1 christos isc_result_t
44 1.1 christos dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep) {
45 1.1 christos dns_fwdtable_t *fwdtable;
46 1.1 christos isc_result_t result;
47 1.1 christos
48 1.1 christos REQUIRE(fwdtablep != NULL && *fwdtablep == NULL);
49 1.1 christos
50 1.1 christos fwdtable = isc_mem_get(mctx, sizeof(dns_fwdtable_t));
51 1.1 christos if (fwdtable == NULL)
52 1.1 christos return (ISC_R_NOMEMORY);
53 1.1 christos
54 1.1 christos fwdtable->table = NULL;
55 1.1 christos result = dns_rbt_create(mctx, auto_detach, fwdtable, &fwdtable->table);
56 1.1 christos if (result != ISC_R_SUCCESS)
57 1.1 christos goto cleanup_fwdtable;
58 1.1 christos
59 1.1 christos result = isc_rwlock_init(&fwdtable->rwlock, 0, 0);
60 1.1 christos if (result != ISC_R_SUCCESS)
61 1.1 christos goto cleanup_rbt;
62 1.1 christos
63 1.1 christos fwdtable->mctx = NULL;
64 1.1 christos isc_mem_attach(mctx, &fwdtable->mctx);
65 1.1 christos fwdtable->magic = FWDTABLEMAGIC;
66 1.1 christos *fwdtablep = fwdtable;
67 1.1 christos
68 1.1 christos return (ISC_R_SUCCESS);
69 1.1 christos
70 1.1 christos cleanup_rbt:
71 1.1 christos dns_rbt_destroy(&fwdtable->table);
72 1.1 christos
73 1.1 christos cleanup_fwdtable:
74 1.1 christos isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
75 1.1 christos
76 1.1 christos return (result);
77 1.1 christos }
78 1.1 christos
79 1.1 christos isc_result_t
80 1.1 christos dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, const dns_name_t *name,
81 1.1 christos dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t fwdpolicy)
82 1.1 christos {
83 1.1 christos isc_result_t result;
84 1.1 christos dns_forwarders_t *forwarders;
85 1.1 christos dns_forwarder_t *fwd, *nfwd;
86 1.1 christos
87 1.1 christos REQUIRE(VALID_FWDTABLE(fwdtable));
88 1.1 christos
89 1.1 christos forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t));
90 1.1 christos if (forwarders == NULL)
91 1.1 christos return (ISC_R_NOMEMORY);
92 1.1 christos
93 1.1 christos ISC_LIST_INIT(forwarders->fwdrs);
94 1.1 christos for (fwd = ISC_LIST_HEAD(*fwdrs);
95 1.1 christos fwd != NULL;
96 1.1 christos fwd = ISC_LIST_NEXT(fwd, link))
97 1.1 christos {
98 1.1 christos nfwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t));
99 1.1 christos if (nfwd == NULL) {
100 1.1 christos result = ISC_R_NOMEMORY;
101 1.1 christos goto cleanup;
102 1.1 christos }
103 1.1 christos *nfwd = *fwd;
104 1.1 christos ISC_LINK_INIT(nfwd, link);
105 1.1 christos ISC_LIST_APPEND(forwarders->fwdrs, nfwd, link);
106 1.1 christos }
107 1.1 christos forwarders->fwdpolicy = fwdpolicy;
108 1.1 christos
109 1.1 christos RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
110 1.1 christos result = dns_rbt_addname(fwdtable->table, name, forwarders);
111 1.1 christos RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
112 1.1 christos
113 1.1 christos if (result != ISC_R_SUCCESS)
114 1.1 christos goto cleanup;
115 1.1 christos
116 1.1 christos return (ISC_R_SUCCESS);
117 1.1 christos
118 1.1 christos cleanup:
119 1.1 christos while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
120 1.1 christos fwd = ISC_LIST_HEAD(forwarders->fwdrs);
121 1.1 christos ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
122 1.1 christos isc_mem_put(fwdtable->mctx, fwd, sizeof(isc_sockaddr_t));
123 1.1 christos }
124 1.1 christos isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
125 1.1 christos return (result);
126 1.1 christos }
127 1.1 christos
128 1.1 christos isc_result_t
129 1.1 christos dns_fwdtable_add(dns_fwdtable_t *fwdtable, const dns_name_t *name,
130 1.1 christos isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy)
131 1.1 christos {
132 1.1 christos isc_result_t result;
133 1.1 christos dns_forwarders_t *forwarders;
134 1.1 christos dns_forwarder_t *fwd;
135 1.1 christos isc_sockaddr_t *sa;
136 1.1 christos
137 1.1 christos REQUIRE(VALID_FWDTABLE(fwdtable));
138 1.1 christos
139 1.1 christos forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t));
140 1.1 christos if (forwarders == NULL)
141 1.1 christos return (ISC_R_NOMEMORY);
142 1.1 christos
143 1.1 christos ISC_LIST_INIT(forwarders->fwdrs);
144 1.1 christos for (sa = ISC_LIST_HEAD(*addrs);
145 1.1 christos sa != NULL;
146 1.1 christos sa = ISC_LIST_NEXT(sa, link))
147 1.1 christos {
148 1.1 christos fwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t));
149 1.1 christos if (fwd == NULL) {
150 1.1 christos result = ISC_R_NOMEMORY;
151 1.1 christos goto cleanup;
152 1.1 christos }
153 1.1 christos fwd->addr = *sa;
154 1.1 christos fwd->dscp = -1;
155 1.1 christos ISC_LINK_INIT(fwd, link);
156 1.1 christos ISC_LIST_APPEND(forwarders->fwdrs, fwd, link);
157 1.1 christos }
158 1.1 christos forwarders->fwdpolicy = fwdpolicy;
159 1.1 christos
160 1.1 christos RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
161 1.1 christos result = dns_rbt_addname(fwdtable->table, name, forwarders);
162 1.1 christos RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
163 1.1 christos
164 1.1 christos if (result != ISC_R_SUCCESS)
165 1.1 christos goto cleanup;
166 1.1 christos
167 1.1 christos return (ISC_R_SUCCESS);
168 1.1 christos
169 1.1 christos cleanup:
170 1.1 christos while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
171 1.1 christos fwd = ISC_LIST_HEAD(forwarders->fwdrs);
172 1.1 christos ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
173 1.1 christos isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t));
174 1.1 christos }
175 1.1 christos isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
176 1.1 christos return (result);
177 1.1 christos }
178 1.1 christos
179 1.1 christos isc_result_t
180 1.1 christos dns_fwdtable_delete(dns_fwdtable_t *fwdtable, const dns_name_t *name) {
181 1.1 christos isc_result_t result;
182 1.1 christos
183 1.1 christos REQUIRE(VALID_FWDTABLE(fwdtable));
184 1.1 christos
185 1.1 christos RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
186 1.1 christos result = dns_rbt_deletename(fwdtable->table, name, ISC_FALSE);
187 1.1 christos RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
188 1.1 christos
189 1.1 christos if (result == DNS_R_PARTIALMATCH)
190 1.1 christos result = ISC_R_NOTFOUND;
191 1.1 christos
192 1.1 christos return (result);
193 1.1 christos }
194 1.1 christos
195 1.1 christos isc_result_t
196 1.1 christos dns_fwdtable_find(dns_fwdtable_t *fwdtable, const dns_name_t *name,
197 1.1 christos dns_forwarders_t **forwardersp)
198 1.1 christos {
199 1.1 christos return (dns_fwdtable_find2(fwdtable, name, NULL, forwardersp));
200 1.1 christos }
201 1.1 christos
202 1.1 christos isc_result_t
203 1.1 christos dns_fwdtable_find2(dns_fwdtable_t *fwdtable, const dns_name_t *name,
204 1.1 christos dns_name_t *foundname, dns_forwarders_t **forwardersp)
205 1.1 christos {
206 1.1 christos isc_result_t result;
207 1.1 christos
208 1.1 christos REQUIRE(VALID_FWDTABLE(fwdtable));
209 1.1 christos
210 1.1 christos RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
211 1.1 christos
212 1.1 christos result = dns_rbt_findname(fwdtable->table, name, 0, foundname,
213 1.1 christos (void **)forwardersp);
214 1.1 christos if (result == DNS_R_PARTIALMATCH)
215 1.1 christos result = ISC_R_SUCCESS;
216 1.1 christos
217 1.1 christos RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
218 1.1 christos
219 1.1 christos return (result);
220 1.1 christos }
221 1.1 christos
222 1.1 christos void
223 1.1 christos dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) {
224 1.1 christos dns_fwdtable_t *fwdtable;
225 1.1 christos isc_mem_t *mctx;
226 1.1 christos
227 1.1 christos REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep));
228 1.1 christos
229 1.1 christos fwdtable = *fwdtablep;
230 1.1 christos
231 1.1 christos dns_rbt_destroy(&fwdtable->table);
232 1.1 christos isc_rwlock_destroy(&fwdtable->rwlock);
233 1.1 christos fwdtable->magic = 0;
234 1.1 christos mctx = fwdtable->mctx;
235 1.1 christos isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
236 1.1 christos isc_mem_detach(&mctx);
237 1.1 christos
238 1.1 christos *fwdtablep = NULL;
239 1.1 christos }
240 1.1 christos
241 1.1 christos /***
242 1.1 christos *** Private
243 1.1 christos ***/
244 1.1 christos
245 1.1 christos static void
246 1.1 christos auto_detach(void *data, void *arg) {
247 1.1 christos dns_forwarders_t *forwarders = data;
248 1.1 christos dns_fwdtable_t *fwdtable = arg;
249 1.1 christos dns_forwarder_t *fwd;
250 1.1 christos
251 1.1 christos UNUSED(arg);
252 1.1 christos
253 1.1 christos while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
254 1.1 christos fwd = ISC_LIST_HEAD(forwarders->fwdrs);
255 1.1 christos ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
256 1.1 christos isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t));
257 1.1 christos }
258 1.1 christos isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
259 1.1 christos }
260