/*
* Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
* Copyright (C) 2012 Vadim Goncharov, Russia, vadim_nuclight@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, 2013, 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/.
*/
/*
* This provides the externally loadable wildcard DLZ module.
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <dlz_minimal.h>
#include <dlz_list.h>
#include <dlz_dbi.h>
#include <ctype.h>
do { \
union { const void *k; void *v; } _u; \
} while (0)
/* fnmatch() return values. */
/* fnmatch() flags. */
/*
* Our data structures.
*/
typedef struct config_data {
char *zone_pattern;
char *axfr_pattern;
char *zone;
char *record;
char *client;
/* Helper functions from the dlz_dlopen driver */
struct named_rr {
char *name;
char *type;
int ttl;
};
/*
* Forward references
*/
static int
rangematch(const char *, char, int, char **);
static int
static void
static const char *
int i = 0;
/* Write info message to log */
"dlz_wildcard allnodes called for zone '%s'", zone);
if (querystring == NULL) {
goto done;
}
"dlz_wildcard allnodes entry num %d: calling "
"putnamedrr(name=%s type=%s ttl=%d qs=%s)",
if (result != ISC_R_SUCCESS)
goto done;
}
done:
if (querystring != NULL)
return (result);
}
/* Write info message to log */
"dlz_wildcard allowzonexfr called for client '%s'", client);
return (ISC_R_SUCCESS);
else
return (ISC_R_NOTFOUND);
}
#if DLZ_DLOPEN_VERSION < 3
#else
#endif
{
const char *p;
#if DLZ_DLOPEN_VERSION >= 3
#endif
if (p == NULL)
return (ISC_R_NOTFOUND);
/* Write info message to log */
"dlz_wildcard findzonedb matched '%s'", p);
return (ISC_R_SUCCESS);
}
#if DLZ_DLOPEN_VERSION == 1
#else
#endif
{
const char *p;
char *namebuf;
#if DLZ_DLOPEN_VERSION >= 2
#endif
if (p == NULL)
return (ISC_R_NOTFOUND);
{
return (ISC_R_NOMEMORY);
} else if (p == zone)
/* Write info message to log */
"dlz_wildcard_dynamic: lookup for '%s' in '%s': "
"trying '%s' in '%s'",
/* We handle authority data in dlz_authority() */
{
continue;
}
if (querystring == NULL) {
goto done;
}
if (result != ISC_R_SUCCESS)
goto done;
querystring = NULL;
}
}
done:
if (querystring != NULL)
return (result);
}
if (p == NULL)
return (ISC_R_NOTFOUND);
/* Write info message to log */
"dlz_wildcard_dynamic: authority for '%s'", zone);
if (querystring == NULL) {
goto done;
}
if (presult != ISC_R_SUCCESS) {
goto done;
}
querystring = NULL;
}
}
done:
if (querystring != NULL)
return (result);
}
static void
/* Get the next record, before we destroy this one. */
}
}
void **dbdata, ...)
{
char *endp;
int i, def_ttl;
const char *helper_name;
return (ISC_R_FAILURE);
return (ISC_R_NOMEMORY);
/* Fill in the helper functions */
/*
* Write info message to log
*/
"Loading '%s' using DLZ_wildcard driver. "
"Zone: %s, AXFR allowed for: %s, $TTL: %s",
/* initialize the records list here to simplify cleanup */
goto cleanup;
}
def_ttl = 3600;
}
goto full_cleanup;
/* Initialize the record link */
/* Append the record to the list */
goto full_cleanup;
goto full_cleanup;
/* If unsuccessful, log err msg and cleanup */
if (result != ISC_R_SUCCESS) {
"Could not build RR data list at argv[%d]",
i + 3);
goto full_cleanup;
}
}
return (ISC_R_SUCCESS);
return (result);
}
void
/*
* Write debugging message to log
*/
}
/*
* Return the version of the API
*/
int
/* XXX: ok to set DNS_SDLZFLAG_THREADSAFE here? */
return (DLZ_DLOPEN_VERSION);
}
/*
* Register a helper function from the bind9 dlz_dlopen driver
*/
static void
}
static const char *
const char *p = string;
return (NULL);
p += strlen(p);
while (p-- > string) {
if (*p == '.') {
return (p + 1);
}
}
return (string);
return (NULL);
}
/*
*
* 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 RANGE_NOMATCH 0
static int
const char *stringstart;
char *newp;
char c, test;
for (stringstart = string;;)
switch (c = *pattern++) {
case EOS:
return (0);
case '?':
return (FNM_NOMATCH);
return (FNM_NOMATCH);
(string == stringstart ||
return (FNM_NOMATCH);
++string;
break;
case '*':
c = *pattern;
/* Collapse multiple stars. */
while (c == '*')
c = *++pattern;
(string == stringstart ||
return (FNM_NOMATCH);
/* Optimize for pattern with * at end or before /. */
if (c == EOS)
if (flags & FNM_PATHNAME)
return ((flags & FNM_LEADING_DIR) ||
0 : FNM_NOMATCH);
else
return (0);
return (FNM_NOMATCH);
break;
}
/* General case, use recursion. */
flags & ~FNM_PERIOD))
return (0);
break;
++string;
}
return (FNM_NOMATCH);
case '[':
return (FNM_NOMATCH);
return (FNM_NOMATCH);
(string == stringstart ||
return (FNM_NOMATCH);
case RANGE_ERROR:
goto norm;
case RANGE_MATCH:
break;
case RANGE_NOMATCH:
return (FNM_NOMATCH);
}
++string;
break;
case '\\':
if (!(flags & FNM_NOESCAPE)) {
c = '\\';
--pattern;
}
}
/* FALLTHROUGH */
default:
norm:
if (c == *string)
;
else if ((flags & FNM_CASEFOLD) &&
(tolower((unsigned char)c) ==
;
else
return (FNM_NOMATCH);
string++;
break;
}
/* NOTREACHED */
}
static int
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 (conklin@ngai.kaleida.com)
*/
++pattern;
if (flags & FNM_CASEFOLD)
/*
* 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 {
c = *pattern++;
if (c == EOS)
return (RANGE_ERROR);
return (RANGE_NOMATCH);
if (flags & FNM_CASEFOLD)
c = tolower((unsigned char)c);
if (*pattern == '-'
pattern += 2;
return (RANGE_ERROR);
if (flags & FNM_CASEFOLD)
ok = 1;
} else if (c == test)
ok = 1;
} while ((c = *pattern++) != ']');
}