sdlz.c revision 0c27b3fe77ac1d5094ba3521e8142d9e7973133f
/*
* Portions Copyright (C) 1999-2001, 2005-2016 Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*
* Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*
* The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
* conceived and contributed by Rob Butler.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
/*! \file */
#include <config.h>
#include <string.h>
#include <dns/callbacks.h>
#include <dns/dbiterator.h>
#include <dns/fixedname.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/rdatatype.h>
#include "rdatalist_p.h"
/*
* Private Types
*/
struct dns_sdlzimplementation {
const dns_sdlzmethods_t *methods;
void *driverarg;
unsigned int flags;
};
struct dns_sdlz_db {
/* Unlocked */
void *dbdata;
/* Locked */
unsigned int references;
int dummy_version;
};
struct dns_sdlzlookup {
/* Unlocked */
unsigned int magic;
/* Locked */
unsigned int references;
};
typedef struct dns_sdlzlookup dns_sdlznode_t;
struct dns_sdlzallnodes {
};
typedef dns_sdlzallnodes_t sdlz_dbiterator_t;
typedef struct sdlz_rdatasetiter {
/*
* Note that "impmagic" is not the first four bytes of the struct, so
* ISC_MAGIC_VALID cannot be used.
*/
/* These values are taken from RFC 1537 */
/* This is a reasonable value */
#ifdef __COVERITY__
#else
#define MAYBE_LOCK(imp) \
do { \
if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
} while (0)
#define MAYBE_UNLOCK(imp) \
do { \
if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
} while (0)
#endif
/*
* Forward references.
*/
dns_dbnode_t **nodep);
dns_name_t *name);
dns_name_t *name);
dns_name_t *name);
static dns_dbiteratormethods_t dbiterator_methods = {
};
/*
* Utility functions
*/
/*
* Log a message at the given level
*/
static void
}
/*% Converts the input string to lowercase, in place. */
static void
dns_sdlz_tolower(char *str) {
unsigned int i;
for (i = 0; i < len; i++) {
str[i] += 32;
}
}
static inline unsigned int
initial_size(const char *data) {
}
/*
* Rdataset Iterator Methods. These methods were "borrowed" from the SDB
* driver interface. See the SDB driver interface documentation for more info.
*/
static void
(sdlz_rdatasetiter_t *)(*iteratorp);
sizeof(sdlz_rdatasetiter_t));
}
static isc_result_t
return (ISC_R_NOMORE);
return (ISC_R_SUCCESS);
}
static isc_result_t
return (ISC_R_NOMORE);
else
return (ISC_R_SUCCESS);
}
static void
rdataset);
}
static dns_rdatasetitermethods_t rdatasetiter_methods = {
};
/*
* DB routines. These methods were "borrowed" from the SDB driver interface.
* See the SDB driver interface documentation for more info.
*/
static void
sdlz->references++;
}
static void
}
static void
sdlz->references--;
if (sdlz->references == 0)
if (need_destroy)
}
static isc_result_t
return (ISC_R_NOTIMPLEMENTED);
}
static isc_result_t
return (ISC_R_NOTIMPLEMENTED);
}
static isc_result_t
{
return (ISC_R_NOTIMPLEMENTED);
}
static void
return;
}
static isc_result_t
return (ISC_R_NOTIMPLEMENTED);
if (result != ISC_R_SUCCESS) {
"sdlz newversion on origin %s failed : %s",
return (result);
}
return (ISC_R_SUCCESS);
}
static void
{
}
static void
return;
}
"sdlz closeversion on origin %s failed", origin);
}
static isc_result_t
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS) {
"isc_mutex_init() failed: %s",
return (ISC_R_UNEXPECTED);
}
return (ISC_R_SUCCESS);
}
static void
isc_buffer_t *b;
}
}
isc_buffer_free(&b);
}
}
}
static isc_result_t
{
isc_buffer_t b;
}
unsigned int labels;
if (result != ISC_R_SUCCESS)
return (result);
} else {
if (result != ISC_R_SUCCESS)
return (result);
}
isc_buffer_putuint8(&b, 0);
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_putuint8(&b2, 0);
if (result != ISC_R_SUCCESS)
return (result);
/* make sure strings are always lowercase */
/* try to lookup the host (namestr) */
/*
* If the name was not found and DNS_DBFIND_NOWILD is not
* set, then we try to find a wildcard entry.
*
* If DNS_DBFIND_NOZONECUT is set and there are multiple
* levels between the host and the zone origin, we also look
* for wildcards at each level.
*/
(options & DNS_DBFIND_NOWILD) == 0)
{
for (i = 0; i < dlabels; i++) {
if (i == dlabels)
else {
dlabels - i - 1,
wild);
if (result != ISC_R_SUCCESS)
return (result);
}
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_putuint8(&b, 0);
if (result == ISC_R_SUCCESS)
break;
}
}
if (result != ISC_R_SUCCESS) {
return (result);
}
if (result != ISC_R_SUCCESS &&
{
return (result);
}
}
sizeof(dns_name_t));
return (ISC_R_NOMEMORY);
}
if (result != ISC_R_SUCCESS) {
sizeof(dns_name_t));
return (result);
}
}
return (ISC_R_SUCCESS);
}
static isc_result_t
{
}
static isc_result_t
{
}
static isc_result_t
{
return (ISC_R_NOTIMPLEMENTED);
}
static void
node->references++;
}
static void
node->references--;
if (node->references == 0)
if (need_destroy)
}
static isc_result_t
INSIST(0);
return (ISC_R_UNEXPECTED);
}
static void
return;
}
static isc_result_t
{
isc_buffer_t b;
return (ISC_R_NOTIMPLEMENTED);
if ((options & DNS_DB_NSEC3ONLY) != 0 ||
(options & DNS_DB_NONSEC3) != 0)
return (ISC_R_NOTIMPLEMENTED);
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_putuint8(&b, 0);
return (ISC_R_NOMEMORY);
/* make sure strings are always lowercase */
if (result != ISC_R_SUCCESS) {
return (result);
}
}
return (ISC_R_SUCCESS);
}
static isc_result_t
{
return (ISC_R_NOTIMPLEMENTED);
break;
}
return (ISC_R_NOTFOUND);
return (ISC_R_SUCCESS);
}
static isc_result_t
{
unsigned int i;
return (DNS_R_NXDOMAIN);
}
/*
* If we're not walking down searching for zone
* cuts, we can cut straight to the chase
*/
if ((options & DNS_DBFIND_NOZONECUT) != 0) {
i = nlabels;
goto search;
}
/*
* Look up the next label.
*/
if (result == ISC_R_NOTFOUND) {
continue;
} else if (result != ISC_R_SUCCESS)
break;
/*
* Look for a DNAME at the current label, unless this is
* the qname.
*/
if (i < nlabels) {
dns_rdatatype_dname, 0, now,
if (result == ISC_R_SUCCESS) {
break;
}
}
/*
* Look for an NS at the current label, unless this is the
* origin, glue is ok, or there are known to be no zone cuts.
*/
(options & DNS_DBFIND_NOZONECUT) == 0)
{
dns_rdatatype_ns, 0, now,
if (result == ISC_R_SUCCESS &&
{
if (sigrdataset != NULL &&
break;
} else if (result == ISC_R_SUCCESS) {
break;
}
}
/*
* If the current name is not the qname, add another label
* and try again.
*/
if (i < nlabels) {
continue;
}
/*
* If we're looking for ANY, we're done.
*/
if (type == dns_rdatatype_any) {
break;
}
/*
* Look for the qtype.
*/
if (result == ISC_R_SUCCESS)
break;
/*
* Look for a CNAME
*/
if (type != dns_rdatatype_cname) {
dns_rdatatype_cname, 0, now,
if (result == ISC_R_SUCCESS) {
break;
}
}
break;
}
if (xresult != ISC_R_SUCCESS) {
return (DNS_R_BADDB);
}
}
return (result);
}
static isc_result_t
{
}
static isc_result_t
{
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
}
static isc_result_t
{
if (mod_function == NULL)
return (ISC_R_NOTIMPLEMENTED);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
goto cleanup;
}
goto cleanup;
}
return (result);
}
static isc_result_t
{
return (ISC_R_NOTIMPLEMENTED);
return (result);
}
static isc_result_t
{
return (ISC_R_NOTIMPLEMENTED);
}
return (result);
}
static isc_result_t
{
char b_type[DNS_RDATATYPE_FORMATSIZE];
return (ISC_R_NOTIMPLEMENTED);
return (result);
}
static isc_boolean_t
return (ISC_FALSE);
}
static unsigned int
return (0);
}
static isc_boolean_t
return (ISC_TRUE);
}
static void
}
static void
}
/*
* getoriginnode() is used by the update code to find the
* dns_rdatatype_dnskey record for a zone
*/
static isc_result_t
return (ISC_R_NOTIMPLEMENTED);
if (result != ISC_R_SUCCESS)
return (result);
}
static dns_dbmethods_t sdlzdb_methods = {
NULL,
dump,
find,
NULL, /* transfernode */
NULL, /* getnsec3parameters */
NULL, /* findnsec3node */
NULL, /* setsigningtime */
NULL, /* getsigningtime */
NULL, /* resigned */
NULL, /* isdnssec */
NULL, /* getrrsetstats */
NULL, /* rpz_attach */
NULL, /* rpz_ready */
NULL, /* setcachestats */
NULL /* hashsize */
};
/*
* Database Iterator Methods. These methods were "borrowed" from the SDB
* driver interface. See the SDB driver interface documentation for more info.
*/
static void
}
}
static isc_result_t
return (ISC_R_NOMORE);
else
return (ISC_R_SUCCESS);
}
static isc_result_t
return (ISC_R_NOMORE);
else
return (ISC_R_SUCCESS);
}
static isc_result_t
return (ISC_R_SUCCESS);
}
return (ISC_R_NOTFOUND);
}
static isc_result_t
return (ISC_R_NOMORE);
else
return (ISC_R_SUCCESS);
}
static isc_result_t
return (ISC_R_NOMORE);
else
return (ISC_R_SUCCESS);
}
static isc_result_t
{
return (ISC_R_SUCCESS);
}
static isc_result_t
return (ISC_R_SUCCESS);
}
static isc_result_t
}
/*
* Rdataset Methods. These methods were "borrowed" from the SDB driver
* interface. See the SDB driver interface documentation for more info.
*/
static void
}
static void
}
static dns_rdatasetmethods_t rdataset_methods = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static void
{
/*
* The sdlz rdataset is an rdatalist with some additions.
* - private1 & private2 are used by the rdatalist.
* - private3 & private 4 are unused.
* - private5 is the node.
*/
/* This should never fail. */
}
/*
* SDLZ core methods. This is the core of the new DLZ functionality.
*/
/*%
* Build a 'bind' database driver structure to be returned by
* either the find zone or the allow zone transfer method.
* This method is only available in this source file, it is
* not made available anywhere else.
*/
static isc_result_t
{
/* check that things are as we expect */
/* allocate and zero memory for driver structure */
return (ISC_R_NOMEMORY);
/* initialize and set origin */
if (result != ISC_R_SUCCESS)
goto mem_cleanup;
/* initialize the reference count mutex */
if (result != ISC_R_SUCCESS)
goto name_cleanup;
/* set the rest of the database structure attributes */
/* attach to the memory context */
/* mark structure as valid */
return (result);
/*
* reference count mutex could not be initialized, clean up
* name memory
*/
return (result);
}
static isc_result_t
{
isc_buffer_t b;
char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
+ 1];
/*
* Perform checks to make sure data is as we expect it to be.
*/
/* Convert DNS name to ascii text */
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_putuint8(&b, 0);
/* convert client address to ascii text */
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_putuint8(&b2, 0);
/* make sure strings are always lowercase */
/* Call SDLZ driver's find zone method */
/*
* if zone is supported and transfers allowed build a 'bind'
* database driver
*/
if (result == ISC_R_SUCCESS)
return (result);
}
return (ISC_R_NOTIMPLEMENTED);
}
static isc_result_t
{
/* Write debugging message to log */
/*
* Performs checks to make sure data is as we expect it to be.
*/
/* If the create method exists, call it. */
}
/* Write debugging message to log */
if (result == ISC_R_SUCCESS) {
} else {
}
return (result);
}
static void
/* Write debugging message to log */
imp = driverdata;
/* If the destroy method exists, call it. */
}
}
static isc_result_t
{
isc_buffer_t b;
/*
* Perform checks to make sure data is as we expect it to be.
*/
/* Convert DNS name to ascii text */
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_putuint8(&b, 0);
/* make sure strings are always lowercase */
/* Call SDLZ driver's find zone method */
/*
* if zone is supported build a 'bind' database driver
* structure to return
*/
if (result == ISC_R_SUCCESS)
return (result);
}
static isc_result_t
{
/* Call SDLZ driver's configure method */
} else {
}
return (result);
}
static isc_boolean_t
void *dbdata)
{
char b_signer[DNS_NAME_FORMATSIZE];
char b_name[DNS_NAME_FORMATSIZE];
char b_addr[ISC_NETADDR_FORMATSIZE];
char b_type[DNS_RDATATYPE_FORMATSIZE];
char b_key[DST_KEY_FORMATSIZE];
isc_uint32_t token_len = 0;
return (ISC_FALSE);
/*
* Format the request elements. sdlz operates on strings, not
* structures
*/
else
b_signer[0] = 0;
else
b_addr[0] = 0;
} else
b_key[0] = 0;
if (tkey_token != NULL) {
}
return (ret);
}
static dns_dlzmethods_t sdlzmethods = {
};
/*
* Public functions.
*/
const char *data)
{
isc_buffer_t b;
unsigned int size;
if (result != ISC_R_SUCCESS)
return (result);
break;
}
return (ISC_R_NOMEMORY);
} else
/*
* BIND9 doesn't enforce all RRs in an RRset
* having the same TTL, as per RFC 2136,
* section 7.12. If a DLZ backend has
* different TTLs, then the best
* we can do is return the lowest.
*/
}
return (ISC_R_NOMEMORY);
else
if (result != ISC_R_SUCCESS)
goto failure;
do {
if (result != ISC_R_SUCCESS)
goto failure;
if (result != ISC_R_SUCCESS)
goto failure;
if (result != ISC_R_SUCCESS)
if (size >= 65535)
break;
size *= 2;
if (size >= 65535)
size = 65535;
} while (result == ISC_R_NOSPACE);
if (result != ISC_R_SUCCESS)
goto failure;
return (ISC_R_SUCCESS);
return (result);
}
{
isc_buffer_t b;
else
if (result != ISC_R_SUCCESS)
return (result);
/* All names are relative to the root */
}
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_NOMEMORY);
}
if (result != ISC_R_SUCCESS) {
return (result);
}
}
}
{
int n;
if (n >= (int)sizeof(str) || n < 0)
return (ISC_R_NOSPACE);
}
{
/*
* Performs checks to make sure data is as we expect it to be.
*/
DNS_SDLZFLAG_THREADSAFE)) == 0);
/* Write debugging message to log */
/*
* Allocate memory for a sdlz_implementation object. Error if
* we cannot.
*/
return (ISC_R_NOMEMORY);
/* Make sure memory region is set to all 0's */
/* Store the data passed into this method */
/* attach the new sdlz_implementation object to a memory context */
/*
* initialize the driver lock, error if we cannot
* (used if a driver does not support multiple threads)
*/
if (result != ISC_R_SUCCESS) {
"isc_mutex_init() failed: %s",
goto cleanup_mctx;
}
/*
* register the DLZ driver. Pass in our "extra" sdlz information as
* a driverarg. (that's why we stored the passed in driver arg in our
* sdlz_implementation structure) Also, store the dlz_implementation
* structure in our sdlz_implementation.
*/
/* if registration fails, cleanup and get outta here. */
if (result != ISC_R_SUCCESS)
goto cleanup_mutex;
return (ISC_R_SUCCESS);
/* destroy the driver lock, we don't need it anymore */
/*
* return the memory back to the available memory pool and
* remove it from the memory context.
*/
return (result);
}
void
/* Write debugging message to log */
/*
* Performs checks to make sure data is as we expect it to be.
*/
/* Unregister the DLZ driver implementation */
/* destroy the driver lock, we don't need it anymore */
/*
* return the memory back to the available memory pool and
* remove it from the memory context.
*/
}
{
return (result);
}