Hi,
I've written a new DLZ module, dlz_wildcard, which we use to serve one
static zone for a template FQDN, configured in named.conf just like a plain
zone, e.g.:
dlz "dlz_stub_zone" {
database "dlz_wildcard *porno*.com 10.0.* 1800
@ 3600 SOA {ns3-fwl2.nic.ru. support.nic.ru. 42 14400 7200
2592000 600}
@ 3600 NS ns3-fwl2.nic.ru.
@ 3600 NS ns4-fwl2.nic.ru.
@ 3600 NS ns8-fwl2.nic.ru.
@ 3600 MX {5 mf1.nic.ru.}
ftp 86400 A 1.2.3.4
sql 86400 A 9.8.7.6
tmp {} A 192.0.0.2
txt 300 TXT {\"you requested $record$ in $zone$\"}
* 86400 A 109.70.27.4
";
};
Here:
argv[1] = *porno*.com - standard unix shell-pattern of zone name
argv[2] = 10.0.* - shell-pattern of IP addrs who can AXFR
argv[3] = 1800 - is like $TTL, used as default ("{}") for "tmp"
Attached file is currently just a patch for DLZ_STUB, it is placed over it,
e.g. how to install for FreeBSD (must enable checkbox for DLZ_STUB):
cd /usr/ports/dns/bind98
make clean
make patch
cp /path/dlz_wildcard_driver.c
work/bind-9.8.4-P1/contrib/dlz/drivers/dlz_stub_driver.c
make WITH_DEBUG=1 install
Is anybody interested in inclusion of this new module in BIND distribution,
so that it could be made to be full separate new module available in
./configure (instead of patch to dlz_stub) ?
--
Vadim Goncharov <vgoncha...@nic.ru> RU-Center
NET Department http://www.nic.ru
NET-SYS Group phone:+7(495)737-7646 (ext.4019)
/*
* Copyright (C) 2002 Stichting NLnet, Netherlands, sticht...@nlnet.nl.
* Copyright (C) 2012 Vadim Goncharov, Russia, vadim_nucli...@mail.ru.
*
* 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.
*/
/*
* Copyright (C) 1999-2001 Internet Software Consortium.
*
* 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 INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM 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.
*/
#ifdef DLZ_STUB
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dns/log.h>
#include <dns/sdlz.h>
#include <dns/result.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/result.h>
#include <isc/util.h>
#include <named/globals.h>
#include <dlz/sdlz_helper.h>
#include <dlz/dlz_stub_driver.h>
/*
* Prototypes for used functions we stolen somewhere.
* XXX For some we go directly to SDLZH and (ab)use the not-exported
* (via sdlz_helper.h) query-helping functions from there (see end of file).
*/
#include <isc/string.h>
static isc_result_t
build_querylist(isc_mem_t *mctx, const char *query_str, char **zone,
char **record, char **client, query_list_t **querylist,
unsigned int flags);
static void
destroy_querylist(isc_mem_t *mctx, query_list_t **querylist);
#include <ctype.h>
/* fnmatch() return values. */
#define FNM_NOMATCH 1 /* Match failed. */
/* fnmatch() flags. */
#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
#define FNM_PERIOD 0x04 /* Period must be matched by period. */
#define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
#define FNM_CASEFOLD 0x10 /* Case insensitive search. */
#define FNM_IGNORECASE FNM_CASEFOLD
#define FNM_FILE_NAME FNM_PATHNAME
static int rangematch(const char *, char, int, char **);
int
fnmatch(const char *pattern, const char *string, int flags);
/*
* Our data structures.
*/
static dns_sdlzimplementation_t *dlz_stub = NULL;
typedef struct named_rr nrr_t;
typedef ISC_LIST(nrr_t) rr_list_t;
typedef struct config_data {
char *zone_pattern;
char *axfr_pattern;
rr_list_t rrs_list;
char *zone;
char *record;
char *client;
isc_mem_t *mctx;
} config_data_t;
struct named_rr {
char *name;
char *type;
int ttl;
query_list_t *data;
ISC_LINK(nrr_t) link;
};
/*
* SDLZ methods
*/
static isc_result_t
wildcard_dlz_allnodes(const char *zone, void *driverarg, void *dbdata,
dns_sdlzallnodes_t *allnodes)
{
config_data_t *cd;
isc_result_t result;
char *querystring = NULL;
nrr_t *nrec;
int i = 0;
UNUSED(driverarg);
cd = (config_data_t *) dbdata;
cd->zone = zone;
cd->client = "xn--i1atf";
/* Write info message to log */
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
"dlz_wildcard allnodes called for zone '%s'", zone);
result = ISC_R_FAILURE;
nrec = ISC_LIST_HEAD(cd->rrs_list);
while (nrec != NULL) {
cd->record = nrec->name;
querystring = build_querystring(ns_g_mctx, nrec->data);
if (querystring == NULL) {
result = ISC_R_NOMEMORY;
goto done;
}
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
"dlz_wildcard allnodes entry num %d: calling "
"putnamedrr(name=%s type=%s ttl=%d qs=%s)", i++,
nrec->name, nrec->type, nrec->ttl, querystring);
result = dns_sdlz_putnamedrr(allnodes, nrec->name, nrec->type,
nrec->ttl, querystring);
if (result != ISC_R_SUCCESS)
goto done;
nrec = ISC_LIST_NEXT(nrec, link);
}
done:
cd->zone = NULL;
if (querystring != NULL)
isc_mem_free(ns_g_mctx, querystring);
return (result);
}
static isc_result_t
wildcard_dlz_allowzonexfr(void *driverarg, void *dbdata, const char *name,
const char *client)
{
config_data_t *cd;
UNUSED(name);
UNUSED(driverarg);
cd = (config_data_t *) dbdata;
/* Write info message to log */
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
"dlz_wildcard allowzonexfr called for client '%s'",
client);
if (fnmatch(cd->axfr_pattern, client, FNM_CASEFOLD) == 0)
return (ISC_R_SUCCESS);
else
return (ISC_R_NOTFOUND);
}
static isc_result_t
wildcard_dlz_findzonedb(void *driverarg, void *dbdata, const char *name)
{
config_data_t *cd;
UNUSED(driverarg);
cd = (config_data_t *) dbdata;
/* Write info message to log */
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
"dlz_wildcard findzone looking for '%s'", name);
if (fnmatch(cd->zone_pattern, name, FNM_CASEFOLD) == 0)
return (ISC_R_SUCCESS);
else
return (ISC_R_NOTFOUND);
}
static isc_result_t
wildcard_dlz_lookup(const char *zone, const char *name, void *driverarg,
void *dbdata, dns_sdlzlookup_t *lookup)
{
isc_result_t result;
config_data_t *cd;
char *querystring = NULL;
nrr_t *nrec;
UNUSED(driverarg);
cd = (config_data_t *) dbdata;
cd->zone = zone;
cd->record = name;
cd->client = "xn--i1atf";
/* Write info message to log */
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
"dlz_wildcard lookup called for '%s' in zone '%s'",
name, zone);
result = ISC_R_FAILURE;
nrec = ISC_LIST_HEAD(cd->rrs_list);
while (nrec != NULL) {
if (strcmp(name, nrec->name) == 0) {
querystring = build_querystring(ns_g_mctx, nrec->data);
if (querystring == NULL) {
result = ISC_R_NOMEMORY;
goto done;
}
result = dns_sdlz_putrr(lookup, nrec->type,
nrec->ttl, querystring);
if (result != ISC_R_SUCCESS)
goto done;
result = ISC_R_SUCCESS;
isc_mem_free(ns_g_mctx, querystring);
querystring = NULL;
}
nrec = ISC_LIST_NEXT(nrec, link);
}
done:
cd->zone = NULL;
cd->record = NULL;
if (querystring != NULL)
isc_mem_free(ns_g_mctx, querystring);
return (result);
}
static void
destroy_rrlist(config_data_t *cd)
{
nrr_t *trec, *nrec;
REQUIRE(cd != NULL);
nrec = ISC_LIST_HEAD(cd->rrs_list);
while (nrec != NULL) {
trec = nrec;
destroy_querylist(cd->mctx, &trec->data);
if (trec->name != NULL)
isc_mem_free(ns_g_mctx, trec->name);
if (trec->type != NULL)
isc_mem_free(ns_g_mctx, trec->type);
/* Get the next record, before we destroy this one. */
nrec = ISC_LIST_NEXT(nrec, link);
isc_mem_put(ns_g_mctx, trec, sizeof(nrr_t));
}
}
static isc_result_t
wildcard_dlz_create(const char *dlzname, unsigned int argc, char *argv[],
void *driverarg, void **dbdata)
{
config_data_t *cd;
char *endp;
int i, def_ttl;
nrr_t *trec = NULL;
isc_result_t result;
UNUSED(driverarg);
if (argc < 8 || argc % 4 != 0)
return (ISC_R_FAILURE);
/*
* Write info message to log
*/
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
"Loading '%s' using DLZ_wildcard driver. "
"Zone: %s, AXFR allowed for: %s, $TTL: %s",
dlzname, argv[1], argv[2], argv[3]);
cd = isc_mem_get(ns_g_mctx, sizeof(config_data_t));
if (cd == NULL)
return (ISC_R_NOMEMORY);
memset(cd, 0, sizeof(config_data_t));
/* initialize the records list here to simplify cleanup */
ISC_LIST_INIT(cd->rrs_list);
cd->zone_pattern = isc_mem_strdup(ns_g_mctx, argv[1]);
if (cd->zone_pattern == NULL)
goto cleanup;
cd->axfr_pattern = isc_mem_strdup(ns_g_mctx, argv[2]);
if (cd->axfr_pattern == NULL)
goto cleanup;
def_ttl = strtol(argv[3], &endp, 10);
if (*endp != '\0' || def_ttl < 0) {
def_ttl = 3600;
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"default TTL invalid, using 3600");
}
for (i = 4; i < argc; i += 4) {
result = ISC_R_NOMEMORY;
trec = isc_mem_get(ns_g_mctx, sizeof(nrr_t));
if (trec == NULL)
goto full_cleanup;
memset(trec, 0, sizeof(nrr_t));
/* Initialize the record link */
ISC_LINK_INIT(trec, link);
/* Append the record to the list */
ISC_LIST_APPEND(cd->rrs_list, trec, link);
trec->name = isc_mem_strdup(ns_g_mctx, argv[i]);
if (trec->name == NULL)
goto full_cleanup;
trec->type = isc_mem_strdup(ns_g_mctx, argv[i + 2]);
if (trec->type == NULL)
goto full_cleanup;
trec->ttl = strtol(argv[i + 1], &endp, 10);
if (argv[i + 1][0] == '\0' || *endp != '\0' || trec->ttl < 0)
trec->ttl = def_ttl;
result = build_querylist(ns_g_mctx, argv[i + 3], &cd->zone,
&cd->record, &cd->client,
&trec->data, 0);
/* If unsuccessful, log err msg and cleanup */
if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Could not build RR data list at
argv[%d]",
i + 3);
goto full_cleanup;
}
}
isc_mem_attach(ns_g_mctx, &cd->mctx);
*dbdata = cd;
return (ISC_R_SUCCESS);
full_cleanup:
destroy_rrlist(cd);
cleanup:
if (cd->zone_pattern != NULL)
isc_mem_free(ns_g_mctx, cd->zone_pattern);
if (cd->axfr_pattern != NULL)
isc_mem_free(ns_g_mctx, cd->axfr_pattern);
isc_mem_put(ns_g_mctx, cd, sizeof(config_data_t));
return (result);
}
static void
wildcard_dlz_destroy(void *driverarg, void *dbdata)
{
config_data_t *cd;
isc_mem_t *mctx;
UNUSED(driverarg);
cd = (config_data_t *) dbdata;
/*
* Write debugging message to log
*/
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
"Unloading DLZ_wildcard driver.");
destroy_rrlist(cd);
isc_mem_free(ns_g_mctx, cd->zone_pattern);
isc_mem_free(ns_g_mctx, cd->axfr_pattern);
mctx = cd->mctx;
isc_mem_put(mctx, cd, sizeof(config_data_t));
isc_mem_detach(&mctx);
}
static dns_sdlzmethods_t dlz_wildcard_methods = {
wildcard_dlz_create,
wildcard_dlz_destroy,
wildcard_dlz_findzonedb,
wildcard_dlz_lookup,
NULL,
wildcard_dlz_allnodes,
wildcard_dlz_allowzonexfr,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
/*%
* Wrapper around dns_sdlzregister().
*/
isc_result_t
dlz_stub_init(void) {
isc_result_t result;
/*
* Write debugging message to log
*/
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
"Registering DLZ_wildcard driver.");
result = dns_sdlzregister("dlz_wildcard", &dlz_wildcard_methods, NULL,
DNS_SDLZFLAG_RELATIVEOWNER |
DNS_SDLZFLAG_RELATIVERDATA,
ns_g_mctx, &dlz_stub);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"dns_sdlzregister() failed: %s",
isc_result_totext(result));
result = ISC_R_UNEXPECTED;
}
return result;
}
/*
* Wrapper around dns_sdlzunregister().
*/
void
dlz_stub_clear(void) {
/*
* Write debugging message to log
*/
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
"Unregistering DLZ_wildcard driver.");
if (dlz_stub != NULL)
dns_sdlzunregister(&dlz_stub);
}
/*
* The helper functions stolen from the FreeBSD kernel (sys/libkern/fnmatch.c).
*
* Why don't we use fnmatch(3) from libc? Because it is not thread-safe, and
* it is not thread-safe because it supports multibyte characters. But here,
* in BIND, we want to be thread-safe and don't need multibyte - DNS names are
* always ASCII.
*/
#define EOS '\0'
#define RANGE_MATCH 1
#define RANGE_NOMATCH 0
#define RANGE_ERROR (-1)
int
fnmatch(const char *pattern, const char *string, int flags)
{
const char *stringstart;
char *newp;
char c, test;
for (stringstart = string;;)
switch (c = *pattern++) {
case EOS:
if ((flags & FNM_LEADING_DIR) && *string == '/')
return (0);
return (*string == EOS ? 0 : FNM_NOMATCH);
case '?':
if (*string == EOS)
return (FNM_NOMATCH);
if (*string == '/' && (flags & FNM_PATHNAME))
return (FNM_NOMATCH);
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
++string;
break;
case '*':
c = *pattern;
/* Collapse multiple stars. */
while (c == '*')
c = *++pattern;
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
/* Optimize for pattern with * at end or before /. */
if (c == EOS)
if (flags & FNM_PATHNAME)
return ((flags & FNM_LEADING_DIR) ||
index(string, '/') == NULL ?
0 : FNM_NOMATCH);
else
return (0);
else if (c == '/' && flags & FNM_PATHNAME) {
if ((string = index(string, '/')) == NULL)
return (FNM_NOMATCH);
break;
}
/* General case, use recursion. */
while ((test = *string) != EOS) {
if (!fnmatch(pattern, string, flags &
~FNM_PERIOD))
return (0);
if (test == '/' && flags & FNM_PATHNAME)
break;
++string;
}
return (FNM_NOMATCH);
case '[':
if (*string == EOS)
return (FNM_NOMATCH);
if (*string == '/' && (flags & FNM_PATHNAME))
return (FNM_NOMATCH);
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
switch (rangematch(pattern, *string, flags, &newp)) {
case RANGE_ERROR:
goto norm;
case RANGE_MATCH:
pattern = newp;
break;
case RANGE_NOMATCH:
return (FNM_NOMATCH);
}
++string;
break;
case '\\':
if (!(flags & FNM_NOESCAPE)) {
if ((c = *pattern++) == EOS) {
c = '\\';
--pattern;
}
}
/* FALLTHROUGH */
default:
norm:
if (c == *string)
;
else if ((flags & FNM_CASEFOLD) &&
(tolower((unsigned char)c) ==
tolower((unsigned char)*string)))
;
else
return (FNM_NOMATCH);
string++;
break;
}
/* NOTREACHED */
}
static int
rangematch(const char *pattern, char test, int flags, char **newp)
{
int negate, ok;
char c, c2;
/*
* A bracket expression starting with an unquoted circumflex
* character produces unspecified results (IEEE 1003.2-1992,
* 3.13.2). This implementation treats it like '!', for
* consistency with the regular expression syntax.
* J.T. Conklin (conk...@ngai.kaleida.com)
*/
if ( (negate = (*pattern == '!' || *pattern == '^')) )
++pattern;
if (flags & FNM_CASEFOLD)
test = tolower((unsigned char)test);
/*
* A right bracket shall lose its special meaning and represent
* itself in a bracket expression if it occurs first in the list.
* -- POSIX.2 2.8.3.2
*/
ok = 0;
c = *pattern++;
do {
if (c == '\\' && !(flags & FNM_NOESCAPE))
c = *pattern++;
if (c == EOS)
return (RANGE_ERROR);
if (c == '/' && (flags & FNM_PATHNAME))
return (RANGE_NOMATCH);
if (flags & FNM_CASEFOLD)
c = tolower((unsigned char)c);
if (*pattern == '-'
&& (c2 = *(pattern+1)) != EOS && c2 != ']') {
pattern += 2;
if (c2 == '\\' && !(flags & FNM_NOESCAPE))
c2 = *pattern++;
if (c2 == EOS)
return (RANGE_ERROR);
if (flags & FNM_CASEFOLD)
c2 = tolower((unsigned char)c2);
if (c <= test && test <= c2)
ok = 1;
} else if (c == test)
ok = 1;
} while ((c = *pattern++) != ']');
*newp = (char *)(uintptr_t)pattern;
return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
}
/*
* The helper functions from sdlz_helper.c - copy-pasted here to avoid
* patching that file - they are 'static' there.
*/
static void
destroy_querylist(isc_mem_t *mctx, query_list_t **querylist)
{
query_segment_t *tseg = NULL;
query_segment_t *nseg = NULL;
REQUIRE(mctx != NULL);
/* if query list is null, nothing to do */
if (*querylist == NULL)
return;
/* start at the top of the list */
nseg = ISC_LIST_HEAD(**querylist);
while (nseg != NULL) { /* loop, until end of list */
tseg = nseg;
/*
* free the query segment's text string but only if it
* was really a query segment, and not a pointer to
* %zone%, or %record%, or %client%
*/
if (tseg->sql != NULL && tseg->direct == isc_boolean_true)
isc_mem_free(mctx, tseg->sql);
/* get the next query segment, before we destroy this one. */
nseg = ISC_LIST_NEXT(nseg, link);
/* deallocate this query segment. */
isc_mem_put(mctx, tseg, sizeof(query_segment_t));
}
/* deallocate the query segment list */
isc_mem_put(mctx, *querylist, sizeof(query_list_t));
}
/*% constructs a query list by parsing a string into query segments */
static isc_result_t
build_querylist(isc_mem_t *mctx, const char *query_str, char **zone,
char **record, char **client, query_list_t **querylist,
unsigned int flags)
{
isc_result_t result;
isc_boolean_t foundzone = isc_boolean_false;
isc_boolean_t foundrecord = isc_boolean_false;
isc_boolean_t foundclient = isc_boolean_false;
char *temp_str = NULL;
char *right_str = NULL;
query_list_t *tql;
query_segment_t *tseg = NULL;
REQUIRE(querylist != NULL && *querylist == NULL);
REQUIRE(mctx != NULL);
/* if query string is null, or zero length */
if (query_str == NULL || strlen(query_str) < 1) {
if ((flags & SDLZH_REQUIRE_QUERY) == 0)
/* we don't need it were ok. */
return (ISC_R_SUCCESS);
else
/* we did need it, PROBLEM!!! */
return (ISC_R_FAILURE);
}
/* allocate memory for query list */
tql = isc_mem_get(mctx, sizeof(query_list_t));
/* couldn't allocate memory. Problem!! */
if (tql == NULL)
return (ISC_R_NOMEMORY);
/* initialize the query segment list */
ISC_LIST_INIT(*tql);
/* make a copy of query_str so we can chop it up */
temp_str = right_str = isc_mem_strdup(mctx, query_str);
/* couldn't make a copy, problem!! */
if (right_str == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup;
}
/* loop through the string and chop it up */
while (right_str != NULL) {
/* allocate memory for tseg */
tseg = isc_mem_get(mctx, sizeof(query_segment_t));
if (tseg == NULL) { /* no memory, clean everything up. */
result = ISC_R_NOMEMORY;
goto cleanup;
}
tseg->sql = NULL;
tseg->direct = isc_boolean_false;
/* initialize the query segment link */
ISC_LINK_INIT(tseg, link);
/* append the query segment to the list */
ISC_LIST_APPEND(*tql, tseg, link);
/*
* split string at the first "$". set query segment to
* left portion
*/
tseg->sql = isc_mem_strdup(mctx,
isc_string_separate(&right_str,
"$"));
if (tseg->sql == NULL) {
/* no memory, clean everything up. */
result = ISC_R_NOMEMORY;
goto cleanup;
}
/* tseg->sql points directly to a string. */
tseg->direct = isc_boolean_true;
tseg->strlen = strlen(tseg->sql);
/* check if we encountered "$zone$" token */
if (strcasecmp(tseg->sql, "zone") == 0) {
/*
* we don't really need, or want the "zone"
* text, so get rid of it.
*/
isc_mem_free(mctx, tseg->sql);
/* set tseg->sql to in-direct zone string */
tseg->sql = (char**) zone;
tseg->strlen = 0;
/* tseg->sql points in-directly to a string */
tseg->direct = isc_boolean_false;
foundzone = isc_boolean_true;
/* check if we encountered "$record$" token */
} else if (strcasecmp(tseg->sql, "record") == 0) {
/*
* we don't really need, or want the "record"
* text, so get rid of it.
*/
isc_mem_free(mctx, tseg->sql);
/* set tseg->sql to in-direct record string */
tseg->sql = (char**) record;
tseg->strlen = 0;
/* tseg->sql points in-directly poinsts to a string */
tseg->direct = isc_boolean_false;
foundrecord = isc_boolean_true;
/* check if we encountered "$client$" token */
} else if (strcasecmp(tseg->sql, "client") == 0) {
/*
* we don't really need, or want the "client"
* text, so get rid of it.
*/
isc_mem_free(mctx, tseg->sql);
/* set tseg->sql to in-direct record string */
tseg->sql = (char**) client;
tseg->strlen = 0;
/* tseg->sql points in-directly poinsts to a string */
tseg->direct = isc_boolean_false;
foundclient = isc_boolean_true;
}
}
/* we don't need temp_str any more */
isc_mem_free(mctx, temp_str);
/*
* add checks later to verify zone and record are found if
* necessary.
*/
/* if this query requires %client%, make sure we found it */
if (((flags & SDLZH_REQUIRE_CLIENT) != 0) && (!foundclient) ) {
/* Write error message to log */
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Required token $client$ not found.");
result = ISC_R_FAILURE;
goto flag_fail;
}
/* if this query requires %record%, make sure we found it */
if (((flags & SDLZH_REQUIRE_RECORD) != 0) && (!foundrecord) ) {
/* Write error message to log */
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Required token $record$ not found.");
result = ISC_R_FAILURE;
goto flag_fail;
}
/* if this query requires %zone%, make sure we found it */
if (((flags & SDLZH_REQUIRE_ZONE) != 0) && (!foundzone) ) {
/* Write error message to log */
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Required token $zone$ not found.");
result = ISC_R_FAILURE;
goto flag_fail;
}
/* pass back the query list */
*querylist = (query_list_t *) tql;
/* return success */
return (ISC_R_SUCCESS);
cleanup:
/* get rid of temp_str */
if (temp_str != NULL)
isc_mem_free(mctx, temp_str);
flag_fail:
/* get rid of what was build of the query list */
if (tql != NULL)
destroy_querylist(mctx, &tql);
return result;
}
#endif
_______________________________________________
Please visit https://lists.isc.org/mailman/listinfo/bind-users to unsubscribe
from this list
bind-users mailing list
bind-users@lists.isc.org
https://lists.isc.org/mailman/listinfo/bind-users