4 * Portions Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 1999-2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
21 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
23 * Permission to use, copy, modify, and distribute this software for any
24 * purpose with or without fee is hereby granted, provided that the
25 * above copyright notice and this permission notice appear in all
28 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
29 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
32 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
34 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
35 * USE OR PERFORMANCE OF THIS SOFTWARE.
37 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
38 * conceived and contributed by Rob Butler.
40 * Permission to use, copy, modify, and distribute this software for any
41 * purpose with or without fee is hereby granted, provided that the
42 * above copyright notice and this permission notice appear in all
45 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
46 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
48 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
49 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
50 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
51 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
52 * USE OR PERFORMANCE OF THIS SOFTWARE.
55 /* Id: dlz.c,v 1.7 2009/01/17 23:47:42 tbox Exp */
65 #include <dns/fixedname.h>
67 #include <dns/master.h>
71 #include <isc/buffer.h>
72 #include <isc/magic.h>
75 #include <isc/rwlock.h>
76 #include <isc/string.h>
80 *** Supported DLZ DB Implementations Registry
83 static ISC_LIST(dns_dlzimplementation_t
) dlz_implementations
;
84 static isc_rwlock_t dlz_implock
;
85 static isc_once_t once
= ISC_ONCE_INIT
;
88 dlz_initialize(void) {
89 RUNTIME_CHECK(isc_rwlock_init(&dlz_implock
, 0, 0) == ISC_R_SUCCESS
);
90 ISC_LIST_INIT(dlz_implementations
);
94 * Searches the dlz_implementations list for a driver matching name.
96 static inline dns_dlzimplementation_t
*
97 dlz_impfind(const char *name
) {
98 dns_dlzimplementation_t
*imp
;
100 for (imp
= ISC_LIST_HEAD(dlz_implementations
);
102 imp
= ISC_LIST_NEXT(imp
, link
))
103 if (strcasecmp(name
, imp
->name
) == 0)
109 *** Basic DLZ Methods
113 dns_dlzallowzonexfr(dns_view_t
*view
, dns_name_t
*name
,
114 isc_sockaddr_t
*clientaddr
, dns_db_t
**dbp
)
117 dns_dlzallowzonexfr_t allowzonexfr
;
118 dns_dlzdb_t
*dlzdatabase
;
121 * Performs checks to make sure data is as we expect it to be.
123 REQUIRE(DNS_DLZ_VALID(view
->dlzdatabase
));
124 REQUIRE(name
!= NULL
);
125 REQUIRE(dbp
!= NULL
&& *dbp
== NULL
);
127 /* ask driver if the zone is supported */
128 dlzdatabase
= view
->dlzdatabase
;
129 allowzonexfr
= dlzdatabase
->implementation
->methods
->allowzonexfr
;
130 result
= (*allowzonexfr
)(dlzdatabase
->implementation
->driverarg
,
131 dlzdatabase
->dbdata
, dlzdatabase
->mctx
,
132 view
->rdclass
, name
, clientaddr
, dbp
);
134 if (result
== ISC_R_NOTIMPLEMENTED
)
135 return (ISC_R_NOTFOUND
);
140 dns_dlzcreate(isc_mem_t
*mctx
, const char *dlzname
, const char *drivername
,
141 unsigned int argc
, char *argv
[], dns_dlzdb_t
**dbp
)
143 dns_dlzimplementation_t
*impinfo
;
147 * initialize the dlz_implementations list, this is guaranteed
148 * to only really happen once.
150 RUNTIME_CHECK(isc_once_do(&once
, dlz_initialize
) == ISC_R_SUCCESS
);
153 * Performs checks to make sure data is as we expect it to be.
155 REQUIRE(dbp
!= NULL
&& *dbp
== NULL
);
156 REQUIRE(dlzname
!= NULL
);
157 REQUIRE(drivername
!= NULL
);
158 REQUIRE(mctx
!= NULL
);
160 /* write log message */
161 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
162 DNS_LOGMODULE_DLZ
, ISC_LOG_INFO
,
163 "Loading '%s' using driver %s", dlzname
, drivername
);
165 /* lock the dlz_implementations list so we can search it. */
166 RWLOCK(&dlz_implock
, isc_rwlocktype_read
);
168 /* search for the driver implementation */
169 impinfo
= dlz_impfind(drivername
);
170 if (impinfo
== NULL
) {
171 RWUNLOCK(&dlz_implock
, isc_rwlocktype_read
);
173 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
174 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
175 "unsupported DLZ database driver '%s'."
177 drivername
, dlzname
);
179 return (ISC_R_NOTFOUND
);
182 /* Allocate memory to hold the DLZ database driver */
183 (*dbp
) = isc_mem_get(mctx
, sizeof(dns_dlzdb_t
));
184 if ((*dbp
) == NULL
) {
185 RWUNLOCK(&dlz_implock
, isc_rwlocktype_read
);
186 return (ISC_R_NOMEMORY
);
189 /* Make sure memory region is set to all 0's */
190 memset((*dbp
), 0, sizeof(dns_dlzdb_t
));
192 (*dbp
)->implementation
= impinfo
;
194 /* Create a new database using implementation 'drivername'. */
195 result
= ((impinfo
->methods
->create
)(mctx
, dlzname
, argc
, argv
,
199 /* mark the DLZ driver as valid */
200 if (result
== ISC_R_SUCCESS
) {
201 RWUNLOCK(&dlz_implock
, isc_rwlocktype_read
);
202 (*dbp
)->magic
= DNS_DLZ_MAGIC
;
203 isc_mem_attach(mctx
, &(*dbp
)->mctx
);
204 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
205 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
206 "DLZ driver loaded successfully.");
207 return (ISC_R_SUCCESS
);
209 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
210 DNS_LOGMODULE_DLZ
, ISC_LOG_ERROR
,
211 "DLZ driver failed to load.");
214 /* impinfo->methods->create failed. */
215 RWUNLOCK(&dlz_implock
, isc_rwlocktype_read
);
216 isc_mem_put(mctx
, (*dbp
), sizeof(dns_dlzdb_t
));
221 dns_dlzdestroy(dns_dlzdb_t
**dbp
) {
223 dns_dlzdestroy_t destroy
;
225 /* Write debugging message to log */
226 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
227 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
228 "Unloading DLZ driver.");
231 * Perform checks to make sure data is as we expect it to be.
233 REQUIRE(dbp
!= NULL
&& DNS_DLZ_VALID(*dbp
));
235 /* call the drivers destroy method */
236 if ((*dbp
) != NULL
) {
238 destroy
= (*dbp
)->implementation
->methods
->destroy
;
239 (*destroy
)((*dbp
)->implementation
->driverarg
,(*dbp
)->dbdata
);
241 isc_mem_put(mctx
, (*dbp
), sizeof(dns_dlzdb_t
));
242 isc_mem_detach(&mctx
);
250 dns_dlzfindzone(dns_view_t
*view
, dns_name_t
*name
, unsigned int minlabels
,
253 dns_fixedname_t fname
;
254 dns_name_t
*zonename
;
255 unsigned int namelabels
;
258 dns_dlzfindzone_t findzone
;
259 dns_dlzdb_t
*dlzdatabase
;
262 * Performs checks to make sure data is as we expect it to be.
264 REQUIRE(DNS_DLZ_VALID(view
->dlzdatabase
));
265 REQUIRE(name
!= NULL
);
266 REQUIRE(dbp
!= NULL
&& *dbp
== NULL
);
268 /* setup a "fixed" dns name */
269 dns_fixedname_init(&fname
);
270 zonename
= dns_fixedname_name(&fname
);
272 /* count the number of labels in the name */
273 namelabels
= dns_name_countlabels(name
);
276 * loop through starting with the longest domain name and
277 * trying shorter names portions of the name until we find a
278 * match, have an error, or are below the 'minlabels'
279 * threshold. minlabels is 0, if the standard database didn't
280 * have a zone name match. Otherwise minlabels is the number
281 * of labels in that name. We need to beat that for a
282 * "better" match for the DLZ database to be authoritative
283 * instead of the standard database.
285 for (i
= namelabels
; i
> minlabels
&& i
> 1; i
--) {
286 if (i
== namelabels
) {
287 result
= dns_name_copy(name
, zonename
, NULL
);
288 if (result
!= ISC_R_SUCCESS
)
291 dns_name_split(name
, i
, NULL
, zonename
);
293 /* ask SDLZ driver if the zone is supported */
294 dlzdatabase
= view
->dlzdatabase
;
295 findzone
= dlzdatabase
->implementation
->methods
->findzone
;
296 result
= (*findzone
)(dlzdatabase
->implementation
->driverarg
,
297 dlzdatabase
->dbdata
, dlzdatabase
->mctx
,
298 view
->rdclass
, zonename
, dbp
);
299 if (result
!= ISC_R_NOTFOUND
)
302 return (ISC_R_NOTFOUND
);
306 * Registers a DLZ driver. This basically just adds the dlz
307 * driver to the list of available drivers in the dlz_implementations list.
310 dns_dlzregister(const char *drivername
, const dns_dlzmethods_t
*methods
,
311 void *driverarg
, isc_mem_t
*mctx
,
312 dns_dlzimplementation_t
**dlzimp
)
315 dns_dlzimplementation_t
*dlz_imp
;
317 /* Write debugging message to log */
318 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
319 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
320 "Registering DLZ driver '%s'", drivername
);
323 * Performs checks to make sure data is as we expect it to be.
325 REQUIRE(drivername
!= NULL
);
326 REQUIRE(methods
!= NULL
);
327 REQUIRE(methods
->create
!= NULL
);
328 REQUIRE(methods
->destroy
!= NULL
);
329 REQUIRE(methods
->findzone
!= NULL
);
330 REQUIRE(mctx
!= NULL
);
331 REQUIRE(dlzimp
!= NULL
&& *dlzimp
== NULL
);
334 * initialize the dlz_implementations list, this is guaranteed
335 * to only really happen once.
337 RUNTIME_CHECK(isc_once_do(&once
, dlz_initialize
) == ISC_R_SUCCESS
);
339 /* lock the dlz_implementations list so we can modify it. */
340 RWLOCK(&dlz_implock
, isc_rwlocktype_write
);
343 * check that another already registered driver isn't using
346 dlz_imp
= dlz_impfind(drivername
);
347 if (dlz_imp
!= NULL
) {
348 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
349 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
350 "DLZ Driver '%s' already registered",
352 RWUNLOCK(&dlz_implock
, isc_rwlocktype_write
);
353 return (ISC_R_EXISTS
);
357 * Allocate memory for a dlz_implementation object. Error if
360 dlz_imp
= isc_mem_get(mctx
, sizeof(dns_dlzimplementation_t
));
361 if (dlz_imp
== NULL
) {
362 RWUNLOCK(&dlz_implock
, isc_rwlocktype_write
);
363 return (ISC_R_NOMEMORY
);
366 /* Make sure memory region is set to all 0's */
367 memset(dlz_imp
, 0, sizeof(dns_dlzimplementation_t
));
369 /* Store the data passed into this method */
370 dlz_imp
->name
= drivername
;
371 dlz_imp
->methods
= methods
;
372 dlz_imp
->mctx
= NULL
;
373 dlz_imp
->driverarg
= driverarg
;
375 /* attach the new dlz_implementation object to a memory context */
376 isc_mem_attach(mctx
, &dlz_imp
->mctx
);
379 * prepare the dlz_implementation object to be put in a list,
380 * and append it to the list
382 ISC_LINK_INIT(dlz_imp
, link
);
383 ISC_LIST_APPEND(dlz_implementations
, dlz_imp
, link
);
385 /* Unlock the dlz_implementations list. */
386 RWUNLOCK(&dlz_implock
, isc_rwlocktype_write
);
388 /* Pass back the dlz_implementation that we created. */
391 return (ISC_R_SUCCESS
);
395 * Helper function for dns_dlzstrtoargv().
396 * Pardon the gratuitous recursion.
399 dns_dlzstrtoargvsub(isc_mem_t
*mctx
, char *s
, unsigned int *argcp
,
400 char ***argvp
, unsigned int n
)
405 /* Discard leading whitespace. */
406 while (*s
== ' ' || *s
== '\t')
410 /* We have reached the end of the string. */
412 *argvp
= isc_mem_get(mctx
, n
* sizeof(char *));
414 return (ISC_R_NOMEMORY
);
417 while (*p
!= ' ' && *p
!= '\t' && *p
!= '\0' && *p
!= '{') {
425 /* do "grouping", items between { and } are one arg */
429 * shift all characters to left by 1 to get rid of '{'
435 while (*p
!= '\0' && *p
!= '}') {
438 /* get rid of '}' character */
443 /* normal case, no "grouping" */
444 } else if (*p
!= '\0')
447 result
= dns_dlzstrtoargvsub(mctx
, p
, argcp
, argvp
, n
+ 1);
448 if (result
!= ISC_R_SUCCESS
)
452 return (ISC_R_SUCCESS
);
456 * Tokenize the string "s" into whitespace-separated words,
457 * return the number of words in '*argcp' and an array
458 * of pointers to the words in '*argvp'. The caller
459 * must free the array using isc_mem_put(). The string
460 * is modified in-place.
463 dns_dlzstrtoargv(isc_mem_t
*mctx
, char *s
,
464 unsigned int *argcp
, char ***argvp
)
466 return(dns_dlzstrtoargvsub(mctx
, s
, argcp
, argvp
, 0));
470 * Unregisters a DLZ driver. This basically just removes the dlz
471 * driver from the list of available drivers in the dlz_implementations list.
474 dns_dlzunregister(dns_dlzimplementation_t
**dlzimp
) {
475 dns_dlzimplementation_t
*dlz_imp
;
478 /* Write debugging message to log */
479 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
480 DNS_LOGMODULE_DLZ
, ISC_LOG_DEBUG(2),
481 "Unregistering DLZ driver.");
484 * Performs checks to make sure data is as we expect it to be.
486 REQUIRE(dlzimp
!= NULL
&& *dlzimp
!= NULL
);
489 * initialize the dlz_implementations list, this is guaranteed
490 * to only really happen once.
492 RUNTIME_CHECK(isc_once_do(&once
, dlz_initialize
) == ISC_R_SUCCESS
);
496 /* lock the dlz_implementations list so we can modify it. */
497 RWLOCK(&dlz_implock
, isc_rwlocktype_write
);
499 /* remove the dlz_implementation object from the list */
500 ISC_LIST_UNLINK(dlz_implementations
, dlz_imp
, link
);
501 mctx
= dlz_imp
->mctx
;
504 * return the memory back to the available memory pool and
505 * remove it from the memory context.
507 isc_mem_put(mctx
, dlz_imp
, sizeof(dns_dlzimplementation_t
));
508 isc_mem_detach(&mctx
);
510 /* Unlock the dlz_implementations list. */
511 RWUNLOCK(&dlz_implock
, isc_rwlocktype_write
);