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

Reply via email to