[master] DNS Response Policy Service API

4713.	[func]		Added support for the DNS Response Policy Service
			(DNSRPS) API, which allows named to use an external
			response policy daemon when built with
			"configure --enable-dnsrps".  Thanks to Vernon
			Schryver and Farsight Security. [RT #43376]
This commit is contained in:
Evan Hunt 2017-09-11 11:53:42 -07:00
parent 8e014c45ae
commit 3363f3147a
53 changed files with 4443 additions and 310 deletions

View file

@ -1,3 +1,9 @@
4713. [func] Added support for the DNS Response Policy Service
(DNSRPS) API, which allows named to use an external
response policy daemon when built with
"configure --enable-dnsrps". Thanks to Vernon
Schryver and Farsight Security. [RT #43376]
4712. [bug] "dig +domain" and "dig +search" didn't retain the
search domain when retrying with TCP. [RT #45547]

View file

@ -59,6 +59,7 @@
#include <dns/db.h>
#include <dns/dispatch.h>
#include <dns/dlz.h>
#include <dns/dnsrps.h>
#include <dns/dns64.h>
#include <dns/dyndb.h>
#include <dns/events.h>
@ -1862,6 +1863,230 @@ cleanup:
return (result);
}
typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
struct conf_dnsrps_ctx {
isc_result_t result;
char *cstr;
size_t cstr_size;
isc_mem_t *mctx;
};
/*
* Add to the DNSRPS configuration string.
*/
static isc_boolean_t
conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
size_t new_len, cur_len, new_cstr_size;
char *new_cstr;
va_list args;
if (ctx->cstr == NULL) {
ctx->cstr = isc_mem_get(ctx->mctx, 256);
if (ctx->cstr == NULL) {
ctx->result = ISC_R_NOMEMORY;
return (ISC_FALSE);
}
ctx->cstr[0] = '\0';
ctx->cstr_size = 256;
}
cur_len = strlen(ctx->cstr);
va_start(args, p);
new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len,
p, args) + 1;
va_end(args);
if (cur_len + new_len <= ctx->cstr_size)
return (ISC_TRUE);
new_cstr_size = ((cur_len + new_len)/256 + 1) * 256;
new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
if (new_cstr == NULL) {
ctx->result = ISC_R_NOMEMORY;
return (ISC_FALSE);
}
memmove(new_cstr, ctx->cstr, cur_len);
isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
ctx->cstr_size = new_cstr_size;
ctx->cstr = new_cstr;
/* cannot use args twice after a single va_start()on some systems */
va_start(args, p);
vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
va_end(args);
return (ISC_TRUE);
}
/*
* Get an DNSRPS configuration value using the global and view options
* for the default. Return ISC_FALSE upon failure.
*/
static isc_boolean_t
conf_dnsrps_get(const cfg_obj_t **sub_obj,
const cfg_obj_t **maps ,const cfg_obj_t *obj,
const char *name, conf_dnsrps_ctx_t *ctx)
{
if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
*sub_obj = NULL;
return (ISC_FALSE);
}
*sub_obj = cfg_tuple_get(obj, name);
if (cfg_obj_isvoid(*sub_obj)) {
*sub_obj = NULL;
if (maps != NULL &&
ISC_R_SUCCESS != named_config_get(maps, name, sub_obj))
*sub_obj = NULL;
}
return (ISC_TRUE);
}
/*
* Handle a DNSRPS boolean configuration value with the global and view
* options providing the default.
*/
static void
conf_dnsrps_yes_no(const cfg_obj_t *obj, const char* name,
conf_dnsrps_ctx_t *ctx)
{
const cfg_obj_t *sub_obj;
if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx))
return;
if (sub_obj == NULL)
return;
if (ctx == NULL) {
cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
"\"%s\" without \"dnsrps-enable yes\"",
name);
return;
}
conf_dnsrps_sadd(ctx, " %s %s", name,
cfg_obj_asboolean(sub_obj) ? "yes" : "no");
}
static void
conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
conf_dnsrps_ctx_t *ctx)
{
const cfg_obj_t *sub_obj;
if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx))
return;
if (sub_obj == NULL)
return;
if (ctx == NULL) {
cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
"\"%s\" without \"dnsrps-enable yes\"",
name);
return;
}
conf_dnsrps_sadd(ctx, " %s %d", name, cfg_obj_asuint32(sub_obj));
}
/*
* Convert the parsed RPZ configuration statement to a string for
* dns_rpz_new_zones().
*/
static isc_result_t
conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps,
isc_boolean_t nsip_enabled, isc_boolean_t nsdname_enabled,
dns_rpz_zbits_t *nsip_on, dns_rpz_zbits_t *nsdname_on,
char **rps_cstr, size_t *rps_cstr_size,
const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element)
{
conf_dnsrps_ctx_t ctx;
const cfg_obj_t *zone_obj, *obj;
dns_rpz_num_t rpz_num;
isc_boolean_t on;
const char *s;
memset(&ctx, 0, sizeof(ctx));
ctx.result = ISC_R_SUCCESS;
ctx.mctx = view->mctx;
for (rpz_num = 0;
zone_element != NULL && ctx.result == ISC_R_SUCCESS;
++rpz_num) {
zone_obj = cfg_listelt_value(zone_element);
s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
obj = cfg_tuple_get(zone_obj, "policy");
if (!cfg_obj_isvoid(obj)) {
s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
conf_dnsrps_sadd(&ctx, " policy %s", s);
if (strcasecmp(s, "cname") == 0) {
s = cfg_obj_asstring(cfg_tuple_get(obj,
"cname"));
conf_dnsrps_sadd(&ctx, " %s", s);
}
}
conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
conf_dnsrps_yes_no(zone_obj, "log", &ctx);
conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
obj = cfg_tuple_get(rpz_obj, "nsip-enable");
if (!cfg_obj_isvoid(obj)) {
if (cfg_obj_asboolean(obj))
*nsip_on |= DNS_RPZ_ZBIT(rpz_num);
else
*nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
}
on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
if (nsip_enabled != on)
conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes " :
" nsip-enable no ");
obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
if (!cfg_obj_isvoid(obj)) {
if (cfg_obj_asboolean(obj))
*nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
else
*nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
}
on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
if (nsdname_enabled != on)
conf_dnsrps_sadd(&ctx, on
? " nsdname-enable yes "
: " nsdname-enable no ");
conf_dnsrps_sadd(&ctx, ";\n");
zone_element = cfg_list_next(zone_element);
}
conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
if (!nsip_enabled)
conf_dnsrps_sadd(&ctx, " nsip-enable no ");
if (!nsdname_enabled)
conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
/*
* Get the general dnsrpzd parameters from the response-policy
* statement in the view and the general options.
*/
if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
obj != NULL)
conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
if (ctx.result == ISC_R_SUCCESS) {
*rps_cstr = ctx.cstr;
*rps_cstr_size = ctx.cstr_size;
} else {
if (ctx.cstr != NULL)
isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
*rps_cstr = NULL;
*rps_cstr_size = 0;
}
return (ctx.result);
}
static isc_result_t
configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
const char *str, const char *msg)
@ -1960,13 +2185,19 @@ configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
"invalid zone name '%s'", str);
return (DNS_R_EMPTYLABEL);
}
for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones-1; ++rpz_num) {
if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
&zone->origin)) {
cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
"duplicate '%s'", str);
result = DNS_R_DUPLICATE;
return (result);
if (!view->rpzs->p.dnsrps_enabled) {
for (rpz_num = 0;
rpz_num < view->rpzs->p.num_zones - 1;
++rpz_num)
{
if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
&zone->origin)) {
cfg_obj_log(rpz_obj, named_g_lctx,
DNS_RPZ_ERROR_LEVEL,
"duplicate '%s'", str);
result = DNS_R_DUPLICATE;
return (result);
}
}
}
if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin))
@ -2030,12 +2261,17 @@ configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
}
static isc_result_t
configure_rpz(dns_view_t *view, const cfg_obj_t *rpz_obj,
isc_boolean_t *old_rpz_okp)
configure_rpz(dns_view_t *view, const cfg_obj_t **maps,
const cfg_obj_t *rpz_obj, isc_boolean_t *old_rpz_okp)
{
isc_boolean_t dnsrps_enabled;
const cfg_listelt_t *zone_element;
char *rps_cstr;
size_t rps_cstr_size;
const cfg_obj_t *sub_obj;
isc_boolean_t recursive_only_def;
isc_boolean_t nsip_enabled, nsdname_enabled;
dns_rpz_zbits_t nsip_on, nsdname_on;
dns_ttl_t ttl_def;
isc_uint32_t minupdateint_def;
dns_rpz_zones_t *zones;
@ -2051,13 +2287,80 @@ configure_rpz(dns_view_t *view, const cfg_obj_t *rpz_obj,
if (zone_element == NULL)
return (ISC_R_SUCCESS);
result = dns_rpz_new_zones(&view->rpzs, view->mctx,
#ifdef ENABLE_RPZ_NSIP
nsip_enabled = ISC_TRUE;
nsdname_enabled = ISC_TRUE;
#else
nsip_enabled = ISC_FALSE;
nsdname_enabled = ISC_FALSE;
#endif
sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
if (!cfg_obj_isvoid(sub_obj))
nsip_enabled = cfg_obj_asboolean(sub_obj);
nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
if (!cfg_obj_isvoid(sub_obj))
nsdname_enabled = cfg_obj_asboolean(sub_obj);
nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
/*
* "dnsrps-enable yes|no" can be either a global or response-policy
* clause.
*/
dnsrps_enabled = ISC_FALSE;
rps_cstr = NULL;
rps_cstr_size = 0;
sub_obj = NULL;
(void)named_config_get(maps, "dnsrps-enable", &sub_obj);
if (sub_obj != NULL) {
dnsrps_enabled = cfg_obj_asboolean(sub_obj);
}
sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
if (!cfg_obj_isvoid(sub_obj)) {
dnsrps_enabled = cfg_obj_asboolean(sub_obj);
}
#ifdef USE_DNSRPS
if (dnsrps_enabled && librpz == NULL) {
cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
"\"dnsrps-enable yes\" but %s",
librpz_lib_open_emsg.c);
return (ISC_R_FAILURE);
}
#else
if (dnsrps_enabled) {
cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
"\"dnsrps-enable yes\" but"
" with `./configure --enable-dnsrps`");
return (ISC_R_FAILURE);
}
#endif
if (dnsrps_enabled) {
/*
* Generate the DNS Response Policy Service
* configuration string.
*/
result = conf_dnsrps(view, maps,
nsip_enabled, nsdname_enabled,
&nsip_on, &nsdname_on,
&rps_cstr, &rps_cstr_size,
rpz_obj, zone_element);
if (result != ISC_R_SUCCESS)
return (result);
}
result = dns_rpz_new_zones(&view->rpzs, rps_cstr,
rps_cstr_size, view->mctx,
named_g_taskmgr, named_g_timermgr);
if (result != ISC_R_SUCCESS)
return (result);
zones = view->rpzs;
zones->p.nsip_on = nsip_on;
zones->p.nsdname_on = nsdname_on;
sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
if (!cfg_obj_isvoid(sub_obj) &&
!cfg_obj_asboolean(sub_obj))
@ -2141,15 +2444,33 @@ configure_rpz(dns_view_t *view, const cfg_obj_t *rpz_obj,
* zones are unchanged, then use the same policy data.
* Data for individual zones that must be reloaded will be merged.
*/
if (old != NULL && memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
if (*old_rpz_okp &&
old != NULL && memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
{
*old_rpz_okp = ISC_FALSE;
}
if (*old_rpz_okp &&
(old == NULL ||
old->rps_cstr == NULL) != (zones->rps_cstr == NULL))
{
*old_rpz_okp = ISC_FALSE;
}
if (*old_rpz_okp &&
(zones->rps_cstr != NULL &&
strcmp(old->rps_cstr, zones->rps_cstr) != 0))
{
*old_rpz_okp = ISC_FALSE;
}
if (*old_rpz_okp) {
dns_rpz_detach_rpzs(&view->rpzs);
dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
} else if (old != NULL && pview != NULL) {
pview->rpzs->rpz_ver += 1;
++pview->rpzs->rpz_ver;
view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
cfg_obj_log(rpz_obj, named_g_lctx, ISC_LOG_DEBUG(1),
cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
"updated RPZ policy: version %d",
view->rpzs->rpz_ver);
}
@ -3429,7 +3750,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
obj = NULL;
if (view->rdclass == dns_rdataclass_in && need_hints &&
named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) {
CHECK(configure_rpz(view, obj, &old_rpz_ok));
CHECK(configure_rpz(view, maps, obj, &old_rpz_ok));
}
obj = NULL;
@ -3460,6 +3781,32 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
ISC_FALSE));
}
/*
* Check that a master or slave zone was found for each
* zone named in the response policy statement
* unless we are using RPZ service interface.
*/
if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
dns_rpz_num_t n;
for (n = 0; n < view->rpzs->p.num_zones; ++n) {
if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
char namebuf[DNS_NAME_FORMATSIZE];
dns_name_format(&view->rpzs->zones[n]->origin,
namebuf, sizeof(namebuf));
isc_log_write(named_g_lctx,
NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER,
DNS_RPZ_ERROR_LEVEL, "rpz '%s'"
" is not a master or slave zone",
namebuf);
result = ISC_R_NOTFOUND;
goto cleanup;
}
}
}
/*
* If we're allowing added zones, then load zone configuration
* from the newzone file for zones that were added during previous
@ -5567,10 +5914,14 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
}
/*
* Note whether this is a response policy zone and which one if so.
* Note whether this is a response policy zone and which one if so,
* unless we are using RPZ service interface. In that case, the
* BIND zone database has nothing to do with rpz and so we don't care.
*/
for (rpz_num = 0; ; ++rpz_num) {
if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones) {
if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
view->rpzs->p.dnsrps_enabled)
{
rpz_num = DNS_RPZ_INVALID_NUM;
break;
}
@ -8315,6 +8666,22 @@ load_configuration(const char *filename, named_server_t *server,
(void) named_server_loadnta(server);
#ifdef USE_DNSRPS
/*
* Start and connect to the DNS Response Policy Service
* daemon, dnsrpzd, for each view that uses DNSRPS.
*/
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = ISC_LIST_NEXT(view, link)) {
result = dns_dnsrps_connect(view->rpzs);
if (result != ISC_R_SUCCESS) {
view = NULL;
goto cleanup;
}
}
#endif
result = ISC_R_SUCCESS;
cleanup:
@ -8757,6 +9124,12 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
server->mctx = mctx;
server->task = NULL;
server->zonemgr = NULL;
#ifdef USE_DNSRPS
CHECKFATAL(dns_dnsrps_server_create(),
"initializing RPZ service interface");
#endif
/* Initialize server data structures. */
server->interfacemgr = NULL;
ISC_LIST_INIT(server->viewlist);
@ -8913,6 +9286,10 @@ named_server_destroy(named_server_t **serverp) {
dns_dt_detach(&server->dtenv);
#endif /* HAVE_DNSTAP */
#ifdef USE_DNSRPS
dns_dnsrps_server_destroy();
#endif
named_controls_destroy(&server->controls);
isc_stats_detach(&server->zonestats);

View file

@ -12,7 +12,7 @@ VERSION=@BIND9_VERSION@
@BIND9_MAKE_INCLUDES@
SUBDIRS = dlzexternal dyndb pipelined rndc rsabigexponent tkey
SUBDIRS = dlzexternal dyndb pipelined rndc rpz rsabigexponent tkey
CINCLUDES = ${ISC_INCLUDES} ${DNS_INCLUDES}

View file

@ -35,6 +35,7 @@ usage() {
fprintf(stderr, "usage: feature-test <arg>\n");
fprintf(stderr, "args:\n");
fprintf(stderr, " --edns-version\n");
fprintf(stderr, " --enable-dnsrps\n");
fprintf(stderr, " --enable-filter-aaaa\n");
fprintf(stderr, " --gethostname\n");
fprintf(stderr, " --gssapi\n");
@ -54,6 +55,14 @@ main(int argc, char **argv) {
return (1);
}
if (strcmp(argv[1], "--enable-dnsrps") == 0) {
#ifdef USE_DNSRPS
return (0);
#else
return (1);
#endif
}
if (strcmp(argv[1], "--enable-filter-aaaa") == 0) {
#ifdef ALLOW_FILTER_AAAA
return (0);

2
bin/tests/system/rpz/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
alt-dnsrpzd-license.conf
dnsrps

View file

@ -0,0 +1,45 @@
# Copyright (C) 2011-2013, 2015, 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/.
srcdir = @srcdir@
VPATH = @srcdir@
top_srcdir = @top_srcdir@
VERSION=@BIND9_VERSION@
@BIND9_MAKE_INCLUDES@
CINCLUDES = ${ISC_INCLUDES} ${DNS_INCLUDES}
CDEFINES =
CWARNINGS =
DNSLIBS =
ISCLIBS = ../../../../lib/isc/libisc.@A@
DNSDEPLIBS =
ISCDEPLIBS = ../../../../lib/isc/libisc.@A@
DEPLIBS = ${ISCDEPLIBS}
LIBS = ${ISCLIBS} @LIBS@
TARGETS = dnsrps@EXEEXT@
DNSRPSOBJS = dnsrps.@O@
SRCS = dnsrps.c
@BIND9_MAKE_RULES@
all: dnsrps@EXEEXT@
dnsrps@EXEEXT@: ${DNSRPSOBJS} ${DEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${DNSRPSOBJS} ${LIBS}
clean distclean::
rm -f ${TARGETS}

View file

@ -0,0 +1,161 @@
#! /bin/sh
#
# Copyright (C) 2017 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/.
set -e
# Say on stdout whether to test DNSRPS
# and create dnsrps.conf and dnsrps-slave.conf
# Note that dnsrps.conf and dnsrps-slave.conf are included in named.conf
# and differ from dnsrpz.conf which is used by dnsrpzd.
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
DNSRPS_CMD=../rpz/dnsrps
AS_NS=
TEST_DNSRPS=
MCONF=dnsrps.conf
SCONF=dnsrps-slave.conf
USAGE="$0: [-xAD] [-M dnsrps.conf] [-S dnsrps-slave.conf]"
while getopts "xADM:S:" c; do
case $c in
x) set -x; DEBUG=-x;;
A) AS_NS=yes;;
D) TEST_DNSRPS=yes;;
M) MCONF="$OPTARG";;
S) SCONF="$OPTARG";;
*) echo "$USAGE" 1>&2; exit 1;;
esac
done
shift `expr $OPTIND - 1 || true`
if [ "$#" -ne 0 ]; then
echo "$USAGE" 1>&2
exit 1
fi
# erase any existing conf files
cat /dev/null > $MCONF
cat /dev/null > $SCONF
add_conf () {
echo "$*" >>$MCONF
echo "$*" >>$SCONF
}
if ! $FEATURETEST --enable-dnsrps; then
if [ -n "$TEST_DNSRPS" ]; then
add_conf "## DNSRPS disabled at compile time"
fi
add_conf "#skip"
exit 0
fi
if [ -z "$TEST_DNSRPS" ]; then
add_conf "## DNSRPS testing is disabled"
add_conf '#skip'
exit 0
fi
if [ ! -x $DNSRPS_CMD ]; then
add_conf "## make $DNSRPS_CMD to test DNSRPS"
add_conf '#skip'
exit 0
fi
if $DNSRPS_CMD -a >/dev/null; then :
else
add_conf "## DNSRPS provider library is not available"
add_conf '#skip'
exit 0
fi
CMN=" dnsrps-options { dnsrpzd-conf ../dnsrpzd.conf
dnsrpzd-sock ../dnsrpzd.sock
dnsrpzd-rpzf ../dnsrpzd.rpzf
dnsrpzd-args '-dddd -L stdout'
log-level 3"
MASTER="$CMN"
if [ -n "$AS_NS" ]; then
MASTER="$MASTER
qname-as-ns yes
ip-as-ns yes"
fi
# write dnsrps setttings for master resolver
cat <<EOF >>$MCONF
$MASTER };
EOF
# write dnsrps setttings for resolvers that should not start dnsrpzd
cat <<EOF >>$SCONF
$CMN
dnsrpzd '' }; # do not start dnsrpzd
EOF
# DNSRPS is available.
# The test should fail if the license is bad.
add_conf "dnsrps-enable yes;"
# Use alt-dnsrpzd-license.conf if it exists
CUR_L=dnsrpzd-license-cur.conf
ALT_L=alt-dnsrpzd-license.conf
# try ../rpz/alt-dnsrpzd-license.conf if alt-dnsrpzd-license.conf does not exist
[ -s $ALT_L ] || ALT_L=../rpz/alt-dnsrpzd-license.conf
if [ -s $ALT_L ]; then
SRC_L=$ALT_L
USE_ALT=
else
SRC_L=../rpz/dnsrpzd-license.conf
USE_ALT="## consider installing alt-dnsrpzd-license.conf"
fi
cp $SRC_L $CUR_L
# parse $CUR_L for the license zone name, master IP addresses, and optional
# transfer-source IP addresses
eval `sed -n -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'\
-e 's/.*zone *\([-a-z0-9]*.license.fastrpz.com\).*/NAME=\1/p' \
-e 's/.*farsight_fastrpz_license *\([0-9.]*\);.*/IPV4=\1/p' \
-e 's/.*farsight_fastrpz_license *\([0-9a-f:]*\);.*/IPV6=\1/p' \
-e 's/.*transfer-source *\([0-9.]*\);.*/TS4=-b\1/p' \
-e 's/.*transfer-source *\([0-9a-f:]*\);.*/TS6=-b\1/p' \
-e 's/.*transfer-source-v6 *\([0-9a-f:]*\);.*/TS6=-b\1/p' \
$CUR_L`
if [ -z "$NAME" ]; then
add_conf "## no DNSRPS tests; no license domain name in $SRC_L"
add_conf '#fail'
exit 0
fi
if [ -z "$IPV4" ]; then
IPV4=license1.fastrpz.com
TS4=
fi
if [ -z "$IPV6" ]; then
IPV6=license1.fastrpz.com
TS6=
fi
# This TSIG key is common and NOT a secret
KEY='hmac-sha256:farsight_fastrpz_license:f405d02b4c8af54855fcebc1'
# Try IPv4 and then IPv6 to deal with IPv6 tunnel and connectivity problems
if `$DIG -4 -t axfr -y$KEY $TS4 $NAME @$IPV4 \
| grep -i "^$NAME.*TXT" >/dev/null`; then
exit 0
fi
if `$DIG -6 -t axfr -y$KEY $TS6 $NAME @$IPV6 \
| grep -i "^$NAME.*TXT" >/dev/null`; then
exit 0
fi
add_conf "## DNSRPS lacks a valid license via $SRC_L"
[ -z "$USE_ALT" ] || add_conf "$USE_ALT"
add_conf '#fail'

View file

@ -10,7 +10,9 @@ rm -f proto.* dsset-* trusted.conf dig.out* nsupdate.tmp ns*/*tmp
rm -f ns*/*.key ns*/*.private ns2/tld2s.db ns2/bl.tld2.db
rm -f ns3/bl*.db ns*/*switch ns*/empty.db ns*/empty.db.jnl
rm -f ns5/requests ns5/example.db ns5/bl.db ns5/*.perf
rm -f */named.memstats */named.run */named.stats */session.key
rm -f */*.jnl */*.core */*.pid
rm -f */named.memstats */*.run */named.stats */session.key
rm -f */*.log */*.jnl */*core */*.pid
rm -f */policy2.db
rm -f ns*/named.lock
rm -f dnsrps*.conf
rm -f dnsrpzd-license-cur.conf dnsrpzd.rpzf dnsrpzd.sock dnsrpzd.pid

View file

@ -0,0 +1,164 @@
/*
* Copyright (C) 2011-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/.
*/
/*
* -a exit(0) if dnsrps is available or dlopen() msg if not
* -p print the path to dnsrpzd configured in dnsrps so that
* dnsrpzd can be run by a setup.sh script.
* Exit(1) if dnsrps is not available
* -n domain print the serial number of a domain to check if a new
* version of a policy zone has been transferred to dnsrpzd.
* Exit(1) if dnsrps is not available
* -w sec.ond wait for seconds, because `sleep 0.1` is not portable
*/
#include <config.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <isc/boolean.h>
#include <isc/util.h>
#ifdef USE_DNSRPS
#define LIBRPZ_LIB_OPEN DNSRPS_LIB_OPEN
#include <dns/librpz.h>
librpz_t *librpz;
#else
typedef struct {char c[120];} librpz_emsg_t;
#endif
static isc_boolean_t link_dnsrps(librpz_emsg_t *emsg);
#define USAGE "usage: [-ap] [-n domain] [-w sec.onds]\n"
int
main(int argc, char **argv) {
#ifdef USE_DNSRPS
char cstr[sizeof("zone ")+1024+10];
librpz_clist_t *clist;
librpz_client_t *client;
librpz_rsp_t *rsp;
uint32_t serial;
#endif
double seconds;
librpz_emsg_t emsg;
char *p;
int i;
while ((i = getopt(argc, argv, "apn:w:")) != -1) {
switch (i) {
case 'a':
if (!link_dnsrps(&emsg)) {
printf("I:%s\n", emsg.c);
return (1);
}
return (0);
case 'p':
if (!link_dnsrps(&emsg)) {
fprintf(stderr, "## %s\n", emsg.c);
return (1);
}
#ifdef USE_DNSRPS
printf("%s\n", librpz->dnsrpzd_path);
return (0);
#else
INSIST(0);
#endif
case 'n':
if (!link_dnsrps(&emsg)) {
fprintf(stderr, "## %s\n", emsg.c);
return (1);
}
#ifdef USE_DNSRPS
/*
* Get the serial number of a policy zone from
* a running dnsrpzd daemon.
*/
clist = librpz->clist_create(&emsg, NULL, NULL,
NULL, NULL, NULL);
if (clist == NULL) {
fprintf(stderr, "## %s: %s\n", optarg, emsg.c);
return (1);
}
snprintf(cstr, sizeof(cstr),
"zone %s; dnsrpzd \"\";"
" dnsrpzd-sock dnsrpzd.sock;"
" dnsrpzd-rpzf dnsrpzd.rpzf",
optarg);
client = librpz->client_create(&emsg, clist,
cstr, true);
if (client == NULL) {
fprintf(stderr, "## %s\n", emsg.c);
return (1);
}
rsp = NULL;
if (!librpz->rsp_create(&emsg, &rsp, NULL,
client, true, false) ||
rsp == NULL) {
fprintf(stderr, "## %s\n", emsg.c);
librpz->client_detach(&client);
return (1);
}
if (!librpz->soa_serial(&emsg, &serial, optarg, rsp)) {
fprintf(stderr, "## %s\n", emsg.c);
librpz->client_detach(&client);
return (1);
}
librpz->rsp_detach(&rsp);
librpz->client_detach(&client);
printf("%d\n", serial);
return (0);
#else
INSIST(0);
#endif
case 'w':
seconds = strtod(optarg, &p);
if (seconds <= 0 || *p != '\0') {
fputs(USAGE, stderr);
return (1);
}
usleep((int)(seconds*1000.0*1000.0));
return (0);
default:
fputs(USAGE, stderr);
return (1);
}
}
fputs(USAGE, stderr);
return (1);
}
static isc_boolean_t
link_dnsrps(librpz_emsg_t *emsg) {
#ifdef USE_DNSRPS
librpz = librpz_lib_open(emsg, NULL, DNSRPS_LIBRPZ_PATH);
if (librpz == NULL)
return (ISC_FALSE);
return (ISC_TRUE);
#else
snprintf(emsg->c, sizeof(emsg->c), "DNSRPS not configured");
return (ISC_FALSE);
#endif
}

View file

@ -0,0 +1,10 @@
zone isc.license.fastrpz.com {
masters port 53 {
KEY farsight_fastrpz_license 104.244.14.176;
KEY farsight_fastrpz_license 2620:11c:f008::176;
};
};
key farsight_fastrpz_license {
algorithm hmac-sha256; secret "f405d02b4c8af54855fcebc1";
};

View file

@ -0,0 +1,49 @@
# dnsrpzd configuration.
pid-file ../dnsrpzd.pid
include ../dnsrpzd-license-cur.conf
# configure NOTIFY and zone transfers
port 5301;
listen-on port 5301 { 10.53.0.3; };
allow-notify { 10.53.0.0/24; };
zone "bl0" {type master; file "../ns5/bl.db"; };
zone "bl1" {type master; file "../ns5/bl.db"; };
zone "bl2" {type master; file "../ns5/bl.db"; };
zone "bl3" {type master; file "../ns5/bl.db"; };
zone "bl4" {type master; file "../ns5/bl.db"; };
zone "bl5" {type master; file "../ns5/bl.db"; };
zone "bl6" {type master; file "../ns5/bl.db"; };
zone "bl7" {type master; file "../ns5/bl.db"; };
zone "bl8" {type master; file "../ns5/bl.db"; };
zone "bl9" {type master; file "../ns5/bl.db"; };
zone "bl10" {type master; file "../ns5/bl.db"; };
zone "bl11" {type master; file "../ns5/bl.db"; };
zone "bl12" {type master; file "../ns5/bl.db"; };
zone "bl13" {type master; file "../ns5/bl.db"; };
zone "bl14" {type master; file "../ns5/bl.db"; };
zone "bl15" {type master; file "../ns5/bl.db"; };
zone "bl16" {type master; file "../ns5/bl.db"; };
zone "bl17" {type master; file "../ns5/bl.db"; };
zone "bl18" {type master; file "../ns5/bl.db"; };
zone "bl19" {type master; file "../ns5/bl.db"; };
zone "bl" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-2" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-given" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-passthru" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-no-op" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-disabled" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-nodata" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-nxdomain" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-cname" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-wildcname" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-garden" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-drop" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl-tcp-only" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "bl.tld2" {type slave; masters port 5300 { 10.53.0.3; }; };
zone "policy1" {type slave; masters port 5300 { 10.53.0.6; }; };
zone "policy2" {type slave; masters port 5300 { 10.53.0.7; }; };

View file

@ -0,0 +1,3 @@
NAME='isc.license.fastrpz.com'
KEY='hmac-sha256:farsight_fastrpz_license:f405d02b4c8af54855fcebc1'
LSERVER=license1.fastrpz.com

View file

@ -43,4 +43,5 @@ zone "subsub.sub3.tld2." {type master; file "tld2.db";};
zone "tld2s." {type master; file "tld2s.db";};
zone "bl.tld2." {type master; file "bl.tld2.db"; notify yes; notify-delay 1;};
zone "bl.tld2." {type master; file "bl.tld2.db";
notify yes; notify-delay 0;};

View file

@ -15,3 +15,5 @@ $TTL 300
; regression testing for some old crashes
example.com NS example.org.
domain.com cname foobar.com

View file

@ -21,7 +21,7 @@ options {
session-keyfile "session.key";
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
notify no;
notify yes;
minimal-responses no;
response-policy {
@ -43,9 +43,17 @@ options {
min-ns-dots 0
qname-wait-recurse yes
min-update-interval 0
nsdname-enable yes
nsip-enable yes
;
include "../dnsrps.conf";
also-notify { 10.53.0.3 port 5301; };
notify-delay 0;
};
logging { category rpz { default_debug; }; };
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
@ -87,5 +95,5 @@ zone "bl-tcp-only." {type master; file "bl-tcp-only.db";
zone "bl.tld2." {type slave; file "bl.tld2.db"; masters {10.53.0.2;};
request-ixfr no; masterfile-format text;};
zone "crash1.tld2" {type master; file "crash1";};
zone "crash2.tld3." {type master; file "crash2";};
zone "crash1.tld2" {type master; file "crash1"; notify no;};
zone "crash2.tld3." {type master; file "crash2"; notify no;};

View file

@ -22,12 +22,14 @@ options {
listen-on { 10.53.0.5; };
listen-on-v6 { none; };
ixfr-from-differences yes;
notify-delay 1;
notify-delay 0;
notify yes;
minimal-responses no;
# turn rpz on or off
include "rpz-switch";
include "../dnsrps-slave.conf";
};
key rndc_key {

View file

@ -25,3 +25,5 @@ example.tld5. NS ns
NS ns1
ns A 10.53.0.5
ns1 A 10.53.0.5
as-ns TXT "rewritten with ip-as-ns and qname-as-ns"

View file

@ -20,9 +20,17 @@ options {
forwarders { 10.53.0.3; };
minimal-responses no;
response-policy { zone "policy1" min-update-interval 0; };
response-policy {
zone "policy1" min-update-interval 0;
} qname-wait-recurse yes
nsip-enable yes
nsdname-enable yes;
include "../dnsrps-slave.conf";
};
logging { category rpz { default_debug; }; };
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
@ -38,5 +46,7 @@ zone "policy1" {
type slave;
masters { 10.53.0.5; };
file "empty.db";
also-notify { 10.53.0.3 port 5301; };
notify-delay 0;
allow-transfer { any; };
};

View file

@ -18,11 +18,18 @@ options {
listen-on-v6 { none; };
minimal-responses no;
response-policy { zone "policy2"; }
qname-wait-recurse no
min-update-interval 0;
response-policy {
zone "policy2";
} qname-wait-recurse no
nsip-enable yes
nsdname-enable yes
min-update-interval 0;
include "../dnsrps-slave.conf";
};
logging { category rpz { default_debug; }; };
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
@ -38,6 +45,8 @@ zone "policy2" {
type slave;
masters { 10.53.0.5; };
file "policy2.db";
also-notify { 10.53.0.3 port 5301; };
notify-delay 0;
allow-transfer { any; };
request-ixfr no; // force axfr on rndc reload
};

View file

@ -6,6 +6,8 @@
# 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/.
# touch dnsrps-off to not test with DNSRPS
set -e
SYSTEMTESTTOP=..
@ -13,7 +15,28 @@ SYSTEMTESTTOP=..
QPERF=`$SHELL qperf.sh`
$SHELL clean.sh
USAGE="$0: [-Dx]"
DEBUG=
while getopts "Dx" c; do
case $c in
x) set -x; DEBUG=-x;;
D) TEST_DNSRPS="-D";;
*) echo "$USAGE" 1>&2; exit 1;;
esac
done
shift `expr $OPTIND - 1 || true`
if test "$#" -ne 0; then
echo "$USAGE" 1>&2
exit 1
fi
$SHELL clean.sh $DEBUG
# decide whether to test DNSRPS
# Note that dnsrps.conf and dnsrps-slave.conf are included in named.conf
# and differ from dnsrpz.conf which is used by dnsrpzd.
$SHELL ../rpz/ckdnsrps.sh -A $TEST_DNSRPS $DEBUG
test -z "`grep 'dnsrps-enable yes' dnsrps.conf`" && TEST_DNSRPS=
# set up test policy zones.
# bl is the main test zone
@ -48,9 +71,11 @@ response-policy {
zone "bl10"; zone "bl11"; zone "bl12"; zone "bl13"; zone "bl14";
zone "bl15"; zone "bl16"; zone "bl17"; zone "bl18"; zone "bl19";
} recursive-only no
qname-wait-recurse no
nsip-enable yes
nsdname-enable yes
max-policy-ttl 90
break-dnssec yes
qname-wait-recurse no
;
EOF
@ -110,3 +135,11 @@ $PERL -e 'for ($cnt = $val = 1; $cnt <= 3000; ++$cnt) {
cp ns2/bl.tld2.db.in ns2/bl.tld2.db
cp ns5/empty.db.in ns5/empty.db
cp ns5/empty.db.in ns5/policy2.db
# Run dnsrpzd to get the license and prime the static policy zones
if test -n "$TEST_DNSRPS"; then
DNSRPZD="`../rpz/dnsrps -p`"
cd ns3
"$DNSRPZ" -D../dnsrpzd.rpzf -S../dnsrpzd.sock -C../dnsrpzd.conf \
-w 0 -dddd -L stdout >./dnsrpzd.run 2>&1
fi

View file

@ -36,4 +36,7 @@ update add a4-1.tld2.bl. 300 A 12.12.12.12
; prefer policy for largest NS name
update add ns.sub3.tld2.rpz-nsdname.bl. 300 A 127.0.0.1
update add ns.subsub.sub3.tld2.rpz-nsdname.bl. 300 A 127.0.0.2
; ip-as-qname rewrites all of tld5
update add ns.tld5.bl. 300 A 12.12.12.12
send

View file

@ -25,4 +25,7 @@ update add 24.0.0.168.192.rpz-ip.bl 300 CNAME 24.0.0.168.192.
;
; prefer NSIP policy to NSDNAME policy
update add ns.tld2.rpz-nsdname.bl. 300 CNAME 10.0.0.1
; ip-as-ns rewrites all of tld5
update add 32.5.0.53.10.rpz-ip.bl. 300 A 12.12.12.12
send

View file

@ -1,14 +1,16 @@
#!/bin/sh
#
# Copyright (C) 2011-2017 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/.
# $Id$
# test response policy zones (RPZ)
# touch dnsrps-off to not test with DNSRPS
# touch dnsrps-only to not test with classic RPZ
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
@ -22,13 +24,20 @@ ns6=$ns.6 # a forwarding server
ns7=$ns.7 # another rewriting resolver
HAVE_CORE=
status=0
DEBUG=
SAVE_RESULTS=
DNSRPS_TEST_MODE= # "" to test with and then without DNSRPS
ARGS=
USAGE="$0: [-x]"
while getopts "x" c; do
USAGE="$0: [-xS] [-D {1,2}]"
while getopts "xSD:" c; do
case $c in
x) set -x;;
x) set -x; DEBUG=-x; ARGS="$ARGS -x";;
S) SAVE_RESULTS=-S; ARGS="$ARGS -S";;
D) DNSRPS_TEST_MODE="$OPTARG";; # with or without DNSRPZ
*) echo "$USAGE" 1>&2; exit 1;;
esac
done
@ -48,8 +57,51 @@ comment () {
fi
}
DNSRPSCMD=./dnsrps
RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s"
# Run the tests twice, first without DNSRPS and then with if it is available
if [ -z "$DNSRPS_TEST_MODE" ]; then
if [ -e dnsrps-only ]; then
echo "I:'dnsrps-only' found: skipping native RPZ sub-test"
else
echo "I:running native RPZ sub-test"
$SHELL ./$0 -D1 $ARGS || status=1
fi
if [ -e dnsrps-off ]; then
echo "I:'dnsrps-off' found: skipping DNSRPS sub-test"
else
echo "I:attempting to configure servers with DNSRPS..."
$PERL $SYSTEMTESTTOP/stop.pl .
$SHELL ./setup.sh -D $DEBUG
sed -n 's/^## /I:/p' dnsrps.conf
if grep '^#fail' dnsrps.conf >/dev/null; then
echo "I:exit status: 1"
exit 1
fi
if test -z "`grep '^#skip' dnsrps.conf`"; then
echo "I:running DNSRPS sub-test"
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart .
$SHELL ./$0 $ARGS -D2 || status=1
else
echo "I:DNSRPS sub-test skipped"
fi
fi
echo "I:exit status: $status"
exit $status
fi
if test -x $DNSRPSCMD; then
# speed up the many delays for dnsrpzd by waiting only 0.1 seconds
WAIT_CMD="$DNSRPSCMD -w 0.1"
TEN_SECS=100
else
WAIT_CMD="sleep 1"
TEN_SECS=10
fi
digcmd () {
if test "$1" = TCP; then
shift
@ -57,9 +109,9 @@ digcmd () {
# Default to +noauth and @$ns3
# Also default to -bX where X is the @value so that OS X will choose
# the right IP source address.
digcmd_args=`echo "+noadd +time=2 +tries=1 -p 5300 $*" | \
sed -e "/@/!s/.*/& @$ns3/" \
-e '/-b/!s/@\([^ ]*\)/@\1 -b\1/' \
digcmd_args=`echo "+nocookie +noadd +time=2 +tries=1 -p 5300 $*" | \
sed -e "/@/!s/.*/& @$ns3/" \
-e '/-b/!s/@\([^ ]*\)/@\1 -b\1/' \
-e '/+n?o?auth/!s/.*/+noauth &/'`
#echo I:dig $digcmd_args 1>&2
$DIG $digcmd_args
@ -69,6 +121,7 @@ digcmd () {
GROUP_NM=
TEST_NUM=0
make_dignm () {
TEST_NUM=`expr $TEST_NUM : '\([0-9]*\).*'` # trim '+' characters
TEST_NUM=`expr $TEST_NUM + 1`
DIGNM=dig.out$GROUP_NM-$TEST_NUM
while test -f $DIGNM; do
@ -83,6 +136,72 @@ setret () {
echo "$*"
}
# set $SN to the SOA serial number of a zone
# $1=domain $2=DNS server and client IP address
get_sn() {
SOA=`$DIG -p 5300 +short +norecurse soa "$1" "@$2" "-b$2"`
SN=`expr "$SOA" : '[^ ]* [^ ]* \([^ ]*\) .*'`
test "$SN" != "" && return
echo "I:no serial number from \`dig -p 5300 soa $1 @$2\` in \"$SOA\""
exit 1
}
get_sn_fast () {
RSN=`$DNSRPSCMD -n "$1"`
#echo "dnsrps serial for $1 is $RSN"
if test -z "$RSN"; then
echo "I:dnsrps failed to get SOA serial number for $1"
exit 1
fi
}
# check that dnsrpzd has loaded its zones
# $1=domain $2=DNS server IP address
FZONES=`sed -n -e 's/^zone "\(.*\)".*\(10.53.0..\).*/Z=\1;M=\2/p' dnsrpzd.conf`
dnsrps_loaded() {
test "$DNSRPS_TEST_MODE" = 2 || return
n=0
for V in $FZONES; do
eval "$V"
get_sn $Z $M
while true; do
get_sn_fast "$Z"
if test "$SN" -eq "0$RSN"; then
#echo "$Z @$M serial=$SN"
break
fi
n=`expr $n + 1`
if test "$n" -gt $TEN_SECS; then
echo "I:dnsrps serial for $Z is $RSN instead of $SN"
exit 1
fi
$WAIT_CMD
done
done
}
# check the serial number in an SOA to ensure that a policy zone has
# been (re)loaded
# $1=serial number $2=domain $3=DNS server
ck_soa() {
n=0
while true; do
if test "$DNSRPS_TEST_MODE" = 2; then
get_sn_fast "$2"
test "$RSN" -eq "$1" && return
else
get_sn "$2" "$3"
test "$SN" -eq "$1" && return
fi
n=`expr $n + 1`
if test "$n" -gt $TEN_SECS; then
echo "I:got serial number \"$SN\" instead of \"$1\" from $2 @$3"
return
fi
$WAIT_CMD
done
}
# (re)load the reponse policy zones with the rules in the file $TEST_FILE
load_db () {
if test -n "$TEST_FILE"; then
@ -118,6 +237,7 @@ restart () {
fi
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart . ns$1
load_db
dnsrps_loaded
}
# $1=server and irrelevant args $2=error message
@ -179,6 +299,7 @@ start_group () {
else
GROUP_NM=
fi
dnsrps_loaded
TEST_NUM=0
}
@ -189,6 +310,7 @@ end_group () {
TEST_FILE=
fi
ckalive $ns3 "I:failed; ns3 server crashed and restarted"
dnsrps_loaded
GROUP_NM=
}
@ -257,7 +379,7 @@ addr () {
digcmd $2 >$DIGNM
#ckalive "$2" "I:server crashed by 'dig $2'" || return 1
ADDR_ESC=`echo "$ADDR" | sed -e 's/\./\\\\./g'`
ADDR_TTL=`sed -n -e "s/^[-.a-z0-9]\{1,\} *\([0-9]*\) IN AA* ${ADDR_ESC}\$/\1/p" $DIGNM`
ADDR_TTL=`sed -n -e "s/^[-.a-z0-9]\{1,\}[ ]*\([0-9]*\) IN AA* ${ADDR_ESC}\$/\1/p" $DIGNM`
if test -z "$ADDR_TTL"; then
setret "I:'dig $2' wrong; no address $ADDR record in $DIGNM"
return 1
@ -306,9 +428,6 @@ drop () {
digcmd nonexistent @$ns2 >proto.nxdomain
digcmd txt-only.tld2 @$ns2 >proto.nodata
status=0
start_group "QNAME rewrites" test1
nochange . # 1 do not crash or rewrite root
nxdomain a0-1.tld2 # 2
@ -353,29 +472,28 @@ ckstats $ns5 test1 ns5 1
ckstats $ns6 test1 ns6 0
start_group "NXDOMAIN/NODATA action on QNAME trigger" test1
nxdomain a0-1.tld2 @$ns6 # 1
nodata a3-1.tld2 @$ns6 # 2
nodata a3-2.tld2 @$ns6 # 3 nodata at DNAME itself
nxdomain a4-2.tld2 @$ns6 # 4 rewrite based on CNAME target
nxdomain a4-2-cname.tld2 @$ns6 # 5
nodata a4-3-cname.tld2 @$ns6 # 6
nxdomain a0-1.tld2 @$ns6 # 1
nodata a3-1.tld2 @$ns6 # 2
nodata a3-2.tld2 @$ns6 # 3 nodata at DNAME itself
nxdomain a4-2.tld2 @$ns6 # 4 rewrite based on CNAME target
nxdomain a4-2-cname.tld2 @$ns6 # 5
nodata a4-3-cname.tld2 @$ns6 # 6
addr 12.12.12.12 "a4-1.sub1.tld2 @$ns6" # 7 A replacement
addr 12.12.12.12 "a4-1.sub2.tld2 @$ns6" # 8 A replacement with wildcard
addr 127.4.4.1 "a4-4.tld2 @$ns6" # 9 prefer 1st conflicting QNAME zone
addr 127.4.4.1 "a4-4.tld2 @$ns6" # 9 prefer 1st conflicting QNAME zone
addr 12.12.12.12 "nxc1.sub1.tld2 @$ns6" # 10 replace NXDOMAIN w/ CNAME
addr 12.12.12.12 "nxc2.sub1.tld2 @$ns6" # 11 replace NXDOMAIN w/ CNAME chain
addr 127.6.2.1 "a6-2.tld2 @$ns6" # 12
addr 56.56.56.56 "a3-6.tld2 @$ns6" # 13 wildcard CNAME
addr 127.6.2.1 "a6-2.tld2 @$ns6" # 12
addr 56.56.56.56 "a3-6.tld2 @$ns6" # 13 wildcard CNAME
addr 57.57.57.57 "a3-7.sub1.tld2 @$ns6" # 14 wildcard CNAME
addr 127.0.0.16 "a4-5-cname3.tld2 @$ns6" # 15 CNAME chain
addr 127.0.0.17 "a4-6-cname3.tld2 @$ns6" # 16 stop short in CNAME chain
nxdomain c1.crash2.tld3 @$ns6 # 17 assert in rbtdb.c
nxdomain a0-1.tld2 +dnssec @$ns6 # 18 simple DO=1 without sigs
nxdomain c1.crash2.tld3 @$ns6 # 17 assert in rbtdb.c
nxdomain a0-1.tld2 +dnssec @$ns6 # 18 simple DO=1 without sigs
nxdomain a0-1s-cname.tld2s +dnssec @$ns6 # 19
drop a3-8.tld2 any @$ns6 # 20 drop
drop a3-8.tld2 any @$ns6 # 20 drop
end_group
ckstatsrange $ns3 test1 ns3 22 28
ckstatsrange $ns3 test1 ns3 22 30
ckstats $ns5 test1 ns5 0
ckstats $ns6 test1 ns6 0
@ -399,25 +517,13 @@ nxdomain c2.crash2.tld3 # 16 assert in rbtdb.c
addr 127.0.0.17 "a4-4.tld2 -b $ns1" # 17 client-IP address trigger
nxdomain a7-1.tld2 # 18 slave policy zone (RT34450)
cp ns2/blv2.tld2.db.in ns2/bl.tld2.db
$RNDCCMD 10.53.0.2 reload bl.tld2
goodsoa="rpz.tld2. hostmaster.ns.tld2. 2 3600 1200 604800 60"
for i in 0 1 2 3 4 5 6 7 8 9 10
do
soa=`$DIG -p 5300 +short soa bl.tld2 @10.53.0.3 -b10.53.0.3`
test "$soa" = "$goodsoa" && break
sleep 1
done
$RNDCCMD $ns2 reload bl.tld2
ck_soa 2 bl.tld2 $ns3
nochange a7-1.tld2 # 19 PASSTHRU
sleep 1 # ensure that a clock tick has occured so that the reload takes effect
sleep 1 # ensure that a clock tick has occured so that named will do the reload
cp ns2/blv3.tld2.db.in ns2/bl.tld2.db
goodsoa="rpz.tld2. hostmaster.ns.tld2. 3 3600 1200 604800 60"
$RNDCCMD 10.53.0.2 reload bl.tld2
for i in 0 1 2 3 4 5 6 7 8 9 10
do
soa=`$DIG -p 5300 +short soa bl.tld2 @10.53.0.3 -b10.53.0.3`
test "$soa" = "$goodsoa" && break
sleep 1
done
$RNDCCMD $ns2 reload bl.tld2
ck_soa 3 bl.tld2 $ns3
nxdomain a7-1.tld2 # 20 slave policy zone (RT34450)
end_group
ckstats $ns3 test2 ns3 12
@ -438,47 +544,53 @@ nochange a5-1-2.tld2
end_group
ckstats $ns3 'radix tree deletions' ns3 0
if $FEATURETEST --rpz-nsdname; then
# these tests assume "min-ns-dots 0"
start_group "NSDNAME rewrites" test3
nochange a3-1.tld2 # 1
nochange a3-1.tld2 +dnssec # 2 this once caused problems
nxdomain a3-1.sub1.tld2 # 3 NXDOMAIN *.sub1.tld2 by NSDNAME
nxdomain a3-1.subsub.sub1.tld2
nxdomain a3-1.subsub.sub1.tld2 -tany
addr 12.12.12.12 a4-2.subsub.sub2.tld2 # 6 walled garden for *.sub2.tld2
nochange a3-2.tld2. # 7 exempt rewrite by name
nochange a0-1.tld2. # 8 exempt rewrite by address block
addr 12.12.12.12 a4-1.tld2 # 9 prefer QNAME policy to NSDNAME
addr 127.0.0.1 a3-1.sub3.tld2 # 10 prefer policy for largest NSDNAME
addr 127.0.0.2 a3-1.subsub.sub3.tld2
nxdomain xxx.crash1.tld2 # 12 dns_db_detachnode() crash
end_group
ckstats $ns3 test3 ns3 7
# these tests assume "min-ns-dots 0"
start_group "NSDNAME rewrites" test3
nochange a3-1.tld2 # 1
nochange a3-1.tld2 +dnssec # 2 this once caused problems
nxdomain a3-1.sub1.tld2 # 3 NXDOMAIN *.sub1.tld2 by NSDNAME
nxdomain a3-1.subsub.sub1.tld2
nxdomain a3-1.subsub.sub1.tld2 -tany
addr 12.12.12.12 a4-2.subsub.sub2.tld2 # 6 walled garden for *.sub2.tld2
nochange a3-2.tld2. # 7 exempt rewrite by name
nochange a0-1.tld2. # 8 exempt rewrite by address block
addr 12.12.12.12 a4-1.tld2 # 9 prefer QNAME policy to NSDNAME
addr 127.0.0.1 a3-1.sub3.tld2 # 10 prefer policy for largest NSDNAME
addr 127.0.0.2 a3-1.subsub.sub3.tld2
nxdomain xxx.crash1.tld2 # 12 dns_db_detachnode() crash
if [ "$DNSRPS_TEST_MODE" = 2 ]; then
addr 12.12.12.12 as-ns.tld5. # 13 qname-as-ns
fi
end_group
if [ "$DNSRPS_TEST_MODE" = 2 ]; then
ckstats $ns3 test3 ns3 8
else
echo "I:NSDNAME not checked; named configured with --disable-rpz-nsdname"
ckstats $ns3 test3 ns3 7
fi
if $FEATURETEST --rpz-nsip; then
# these tests assume "min-ns-dots 0"
start_group "NSIP rewrites" test4
nxdomain a3-1.tld2 # 1 NXDOMAIN for all of tld2
nochange a3-2.tld2. # 2 exempt rewrite by name
nochange a0-1.tld2. # 3 exempt rewrite by address block
nochange a3-1.tld4 # 4 different NS IP address
end_group
# these tests assume "min-ns-dots 0"
start_group "NSIP rewrites" test4
nxdomain a3-1.tld2 # 1 NXDOMAIN for all of tld2
nochange a3-2.tld2. # 2 exempt rewrite by name
nochange a0-1.tld2. # 3 exempt rewrite by address block
nochange a3-1.tld4 # 4 different NS IP address
if [ "$DNSRPS_TEST_MODE" = 2 ]; then
addr 12.12.12.12 as-ns.tld5. # 5 ip-as-ns
fi
end_group
start_group "walled garden NSIP rewrites" test4a
addr 41.41.41.41 a3-1.tld2 # 1 walled garden for all of tld2
addr 2041::41 'a3-1.tld2 AAAA' # 2 walled garden for all of tld2
here a3-1.tld2 TXT <<'EOF' # 3 text message for all of tld2
start_group "walled garden NSIP rewrites" test4a
addr 41.41.41.41 a3-1.tld2 # 1 walled garden for all of tld2
addr 2041::41 'a3-1.tld2 AAAA' # 2 walled garden for all of tld2
here a3-1.tld2 TXT <<'EOF' # 3 text message for all of tld2
;; status: NOERROR, x
a3-1.tld2. x IN TXT "NSIP walled garden"
EOF
end_group
ckstats $ns3 test4 ns3 4
end_group
if [ "$DNSRPS_TEST_MODE" = 2 ]; then
ckstats $ns3 test4 ns3 5
else
echo "I:NSIP not checked; named configured with --disable-rpz-nsip"
ckstats $ns3 test4 ns3 4
fi
# policies in ./test5 overridden by response-policy{} in ns3/named.conf
@ -530,7 +642,6 @@ end_group
ckstats $ns3 bugs ns3 8
# superficial test for major performance bugs
QPERF=`sh qperf.sh`
if test -n "$QPERF"; then
@ -538,10 +649,10 @@ if test -n "$QPERF"; then
date "+I:${TS}checking performance $1"
# Dry run to prime everything
comment "before dry run $1"
$RNDCCMD $ns5 notrace
$QPERF -c -1 -l30 -d ns5/requests -s $ns5 -p 5300 >/dev/null
comment "before real test $1"
PFILE="ns5/$2.perf"
$RNDCCMD $ns5 notrace
$QPERF -c -1 -l30 -d ns5/requests -s $ns5 -p 5300 >$PFILE
comment "after test $1"
X=`sed -n -e 's/.*Returned *\([^ ]*:\) *\([0-9]*\) .*/\1\2/p' $PFILE \
@ -558,7 +669,6 @@ if test -n "$QPERF"; then
# get qps with rpz
perf 'with RPZ' rpz 'NOERROR:2900 NXDOMAIN:100 '
RPZ=`trim rpz`
# turn off rpz and measure qps again
echo "# RPZ off" >ns5/rpz-switch
RNDCCMD_OUT=`$RNDCCMD $ns5 reload`
@ -583,6 +693,27 @@ else
echo "I:performance not checked; queryperf not available"
fi
if [ "$DNSRPS_TEST_MODE" = 2 ]; then
echo "I:checking that dnsrpzd is automatically restarted"
OLD_PID=`cat dnsrpzd.pid`
$KILL "$OLD_PID"
n=0
while true; do
NEW_PID=`cat dnsrpzd.pid 2>/dev/null`
if test -n "$NEW_PID" -a "0$OLD_PID" -ne "0$NEW_PID"; then
#echo "OLD_PID=$OLD_PID NEW_PID=$NEW_PID"
break;
fi
$DIG -p 5300 +short +norecurse a0-1.tld2 @$ns3 >/dev/null
n=`expr $n + 1`
if test "$n" -gt $TEN_SECS; then
setret "I:dnsrpzd did not restart"
break
fi
$WAIT_CMD
done
fi
# restart the main test RPZ server to see if that creates a core file
if test -z "$HAVE_CORE"; then
@ -604,7 +735,9 @@ $DIG +noall +answer -p 5300 @$ns3 any a3-2.tld2 > dig.out.any
ttl=`awk '/a3-2 tld2 text/ {print $2}' dig.out.any`
if test ${ttl:=0} -eq 0; then setret I:failed; fi
echo "I:checking rpz updates/transfers with parent nodes added after children"
echo "I:checking rpz updates/transfers with parent nodes added after children" \
| tr -d '\n'
# regression test for RT #36272: the success condition
# is the slave server not crashing.
nsd() {
@ -617,26 +750,40 @@ send
EOF
sleep 2
}
for i in 1 2 3 4 5; do
nsd $ns5 add example.com.policy1. '*.example.com.policy1.'
echo . | tr -d '\n'
nsd $ns5 delete example.com.policy1. '*.example.com.policy1.'
echo . | tr -d '\n'
done
for i in 1 2 3 4 5; do
nsd $ns5 add '*.example.com.policy1.' example.com.policy1.
echo . | tr -d '\n'
nsd $ns5 delete '*.example.com.policy1.' example.com.policy1.
echo . | tr -d '\n'
done
echo
echo "I:checking that going from a empty policy zone works"
echo "I:checking that going from an empty policy zone works"
nsd $ns5 add '*.x.servfail.policy2.' x.servfail.policy2.
sleep 1
$RNDCCMD $ns7 reload policy2
$DIG z.x.servfail -p 5300 @$ns7 > dig.out.ns7
grep NXDOMAIN dig.out.ns7 > /dev/null || setret I:failed;
grep NXDOMAIN dig.out.ns7 > /dev/null || setret I:failed
echo "I:checking rpz with delegation fails correctly"
$DIG -p 5300 @$ns3 ns example.com > dig.out.delegation
grep "status: SERVFAIL" dig.out.delegation > /dev/null || setret "I:failed"
# dnsrps does not allow NS RRs in policy zones, so this check
# with dnsrps results in no rewriting.
if [ "$DNSRPS_TEST_MODE" = 1 ]; then
echo "I:checking rpz with delegation fails correctly"
$DIG -p 5300 @$ns3 ns example.com > dig.out.delegation
grep "status: SERVFAIL" dig.out.delegation > /dev/null || setret "I:failed"
fi
echo "I:exit status: $status"
[ $status -ne 0 ] && pf=fail || pf=pass
case $DNSRPS_TEST_MODE in
1) echo "I:status (native RPZ sub-test): $status ($pf)";;
2) echo "I:status (DNSRPS sub-test): $status ($pf)";;
*) echo "I:invalid test mode";;
esac
[ $status -eq 0 ] || exit 1

View file

@ -9,9 +9,11 @@
rm -f dig.out.*
rm -f ns*/named.lock
rm -f ns*/named.memstats
rm -f ns*/named.run
rm -f ns*/*.run
rm -f ns2/*.local
rm -f ns2/*.queries
rm -f ns2/named.[0-9]*.conf
rm -f ns2/named.conf
rm -f ns3/named.conf
rm -f ns*/*core *core
rm -f dnsrps*.conf dnsrpzd*

View file

@ -11,6 +11,7 @@ options {
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
port 5300;
session-keyfile "session.key";
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };

View file

@ -19,7 +19,9 @@ view "recursive" {
response-policy {
zone "clientip1";
zone "clientip2";
} qname-wait-recurse no;
} qname-wait-recurse no
nsdname-enable yes
nsip-enable yes;
# policy zones to be tested
zone "clientip1" { type master; file "db.clientip1"; };

View file

@ -20,7 +20,9 @@ view "recursive" {
# policy configuration to be tested
response-policy {
zone "clientip21";
} qname-wait-recurse no;
} qname-wait-recurse no
nsdname-enable yes
nsip-enable yes;
# policy zones to be tested
zone "clientip21" { type master; file "db.clientip21"; };

View file

@ -13,11 +13,15 @@ options {
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port 5300;
session-keyfile "session.key";
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion yes;
querylog yes;
# let ns3 start dnsrpzd
include "../dnsrps-slave.conf";
};
key rndc_key {

View file

@ -20,7 +20,9 @@ view "recursive" {
zone "log1" log no;
zone "log2" log yes;
zone "log3"; # missing log clause
} qname-wait-recurse no;
} qname-wait-recurse no
nsdname-enable yes
nsip-enable yes;
# policy zones to be tested
zone "log1" { type master; file "db.log1"; };

View file

@ -18,7 +18,9 @@ view "recursive" {
# policy configuration to be tested
response-policy {
zone "wildcard1" policy NXDOMAIN;
};
} qname-wait-recurse yes
nsdname-enable yes
nsip-enable yes;
# policy zones to be tested
zone "wildcard1" { type master; file "db.wildcard1"; };

View file

@ -19,7 +19,9 @@ view "recursive" {
response-policy {
zone "wildcard2a" policy NXDOMAIN;
zone "wildcard2b" policy NXDOMAIN;
};
} qname-wait-recurse yes
nsdname-enable yes
nsip-enable yes;
# policy zones to be tested
zone "wildcard2a" { type master; file "db.wildcard2a"; };

View file

@ -18,7 +18,9 @@ view "recursive" {
# policy configuration to be tested
response-policy {
zone "wildcard3" policy NXDOMAIN;
};
} qname-wait-recurse yes
nsdname-enable yes
nsip-enable yes;
# policy zones to be tested
zone "wildcard3" { type master; file "db.wildcard3"; };

View file

@ -17,11 +17,17 @@ options {
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port 5300;
session-keyfile "session.key";
pid-file "named.pid";
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
response-policy { zone "policy"; };
response-policy { zone "policy"; }
qname-wait-recurse yes
nsip-enable yes
nsdname-enable yes;
include "../dnsrps.conf";
};
zone "policy" { type master; file "policy.db"; };

View file

@ -21,7 +21,12 @@ options {
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
response-policy { zone "policy"; } nsip-wait-recurse no;
response-policy { zone "policy"; } nsip-wait-recurse no
qname-wait-recurse yes
nsip-enable yes
nsdname-enable yes;
include "../dnsrps.conf";
};
zone "policy" { type master; file "policy.db"; };

View file

@ -13,6 +13,7 @@ options {
notify-source 10.53.0.4;
transfer-source 10.53.0.4;
port 5300;
session-keyfile "session.key";
pid-file "named.pid";
listen-on { 10.53.0.4; };
listen-on-v6 { none; };

View file

@ -9,13 +9,4 @@
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
ret=0
$FEATURETEST --rpz-nsdname || ret=1
$FEATURETEST --rpz-nsip || ret=1
if [ $ret != 0 ]; then
echo "I:This test requires NSIP AND NSDNAME support in RPZ." >&2
exit 1
fi
exec $SHELL ../testcrypto.sh

View file

@ -6,9 +6,52 @@
# 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/.
# touch dnsrps-off to not test with DNSRPS
set -e
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
perl testgen.pl
USAGE="$0: [-xD]"
DEBUG=
while getopts "xD" c; do
case $c in
x) set -x; DEBUG=-x;;
D) TEST_DNSRPS="-D";;
*) echo "$USAGE" 1>&2; exit 1;;
esac
done
shift `expr $OPTIND - 1 || true`
if test "$#" -ne 0; then
echo "$USAGE" 1>&2
exit 1
fi
$SHELL clean.sh $DEBUG
$PERL testgen.pl
cp -f ns2/named.default.conf ns2/named.conf
cp -f ns3/named1.conf ns3/named.conf
# decide whether to test DNSRPS
$SHELL ../rpz/ckdnsrps.sh $TEST_DNSRPS $DEBUG
test -z "`grep 'dnsrps-enable yes' dnsrps.conf`" && TEST_DNSRPS=
CWD=`pwd`
cat <<EOF >dnsrpzd.conf
PID-FILE $CWD/dnsrpzd.pid;
include $CWD/dnsrpzd-license-cur.conf
zone "policy" { type master; file "`pwd`/ns3/policy.db"; };
EOF
sed -n -e 's/^ *//' -e "/zone.*.*master/s@file \"@&$CWD/ns2/@p" ns2/*.conf \
>>dnsrpzd.conf
# Run dnsrpzd to get the license and prime the static policy zones
if test -n "$TEST_DNSRPS"; then
DNSRPZD="`../rpz/dnsrps -p`"
"$DNSRPZD" -D./dnsrpzd.rpzf -S./dnsrpzd.sock -C./dnsrpzd.conf \
-w 0 -dddd -L stdout >./dnsrpzd.run 2>&1
fi

View file

@ -1,10 +1,18 @@
#!/usr/bin/env perl
#
# Copyright (C) 2015, 2016 Internet Systems Consortium, Inc. ("ISC")
# Copyright (C) 2015 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/.
# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC 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.
use strict;
use warnings;
@ -24,13 +32,13 @@ view "recursive" {
EOB
my $no_option = <<'EOB';
};
} nsdname-enable yes nsip-enable yes;
# policy zones to be tested
EOB
my $qname_wait_recurse = <<'EOB';
} qname-wait-recurse no;
} nsdname-enable yes nsip-enable yes qname-wait-recurse no;
# policy zones to be tested
EOB

View file

@ -6,12 +6,75 @@
# 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/.
# touch dnsrps-off to not test with DNSRPS
# touch dnsrps-only to not test with classic RPZ
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
status=0
t=0
DEBUG=
DNSRPS_TEST_MODE= # "" to test with and then without DNSRPS
ARGS=
USAGE="$0: [-xS] [-D {1,2}]"
while getopts "xSD:" c; do
case $c in
x) set -x; DEBUG=-x; ARGS="$ARGS -x";;
D) DNSRPS_TEST_MODE="$OPTARG";; # with or without DNSRPS
*) echo "$USAGE" 1>&2; exit 1;;
esac
done
shift `expr $OPTIND - 1 || true`
if test "$#" -ne 0; then
echo "$USAGE" 1>&2
exit 1
fi
# really quit on control-C
trap 'exit 1' 1 2 15
DNSRPSCMD=../rpz/dnsrps
RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s"
# Run the tests twice, first without DNSRPS and then with if it is available
if [ -z "$DNSRPS_TEST_MODE" ]; then
if [ -e dnsrps-only ]; then
echo "I:'dnsrps-only' found: skipping native RPZ sub-test"
else
echo "I:running native RPZ sub-test"
$SHELL ./$0 -D1 $ARGS || status=1
fi
if [ -e dnsrps-off ]; then
echo "I:'dnsrps-off' found: skipping DNSRPS sub-test"
else
echo "I:attempting to configure servers with DNSRPS..."
$SHELL ./setup.sh -D $DEBUG
sed -n 's/^## /I:/p' dnsrps.conf
if grep '^#fail' dnsrps.conf >/dev/null; then
echo "I:exit status: 1"
exit 1
fi
if test -z "`grep '^#skip' dnsrps.conf`"; then
$RNDCCMD 10.53.0.2 reload
$RNDCCMD 10.53.0.3 reload
$RNDCCMD 10.53.0.2 flush
$RNDCCMD 10.53.0.3 flush
echo "I:running DNSRPS sub-test"
$SHELL ./$0 -D2 $ARGS || status=1
else
echo "I:DNSRPS sub-test skipped"
fi
fi
echo "I:exit status: $status"
exit $status
fi
# $1 = test name (such as 1a, 1b, etc. for which named.$1.conf exists)
run_server() {
TESTNAME=$1
@ -47,8 +110,8 @@ expect_norecurse() {
t=`expr $t + 1`
echo "I:testing $NAME doesn't recurse (${t})"
run_query $TESTNAME $LINE || {
echo "I:test ${t} failed"
status=1
echo "I:test ${t} failed"
status=1
}
}
@ -62,11 +125,14 @@ expect_recurse() {
t=`expr $t + 1`
echo "I:testing $NAME recurses (${t})"
run_query $TESTNAME $LINE && {
echo "I:test ${t} failed"
status=1
echo "I:test ${t} failed"
status=1
}
}
# show whether and why DNSRPS is enabled or disabled
sed -n 's/^## /I:/p' dnsrps.conf
t=`expr $t + 1`
echo "I:testing that l1.l0 exists without RPZ (${t})"
$DIG $DIGOPTS l1.l0 ns @10.53.0.2 -p 5300 > dig.out.${t}
@ -177,6 +243,7 @@ echo "I:adding an NSDNAME policy"
cp ns2/db.6a.00.policy.local ns2/saved.policy.local
cp ns2/db.6b.00.policy.local ns2/db.6a.00.policy.local
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 6a.00.policy.local 2>&1 | sed 's/^/I:ns2 /'
test -f dnsrpzd.pid && kill -USR1 `cat dnsrpzd.pid`
sleep 1
t=`expr $t + 1`
echo "I:running dig to follow CNAME (blocks, so runs in the background) (${t})"
@ -185,6 +252,7 @@ sleep 1
echo "I:removing the NSDNAME policy"
cp ns2/db.6c.00.policy.local ns2/db.6a.00.policy.local
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 6a.00.policy.local 2>&1 | sed 's/^/I:ns2 /'
test -f dnsrpzd.pid && kill -USR1 `cat dnsrpzd.pid`
sleep 1
echo "I:resuming authority server"
if [ "$CYGWIN" ]; then
@ -198,8 +266,8 @@ for n in 1 2 3 4 5 6 7 8 9; do
sleep 1
[ -s dig.out.${t} ] || continue
grep "status: NOERROR" dig.out.${t} > /dev/null 2>&1 || {
echo "I:test ${t} failed"
status=1
echo "I:test ${t} failed"
status=1
}
done
@ -222,6 +290,7 @@ kill -TSTP $PID
echo "I:adding an NSDNAME policy"
cp ns2/db.6b.00.policy.local ns2/db.6a.00.policy.local
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 6a.00.policy.local 2>&1 | sed 's/^/I:ns2 /'
test -f dnsrpzd.pid && kill -USR1 `cat dnsrpzd.pid`
sleep 1
t=`expr $t + 1`
echo "I:running dig to follow CNAME (blocks, so runs in the background) (${t})"
@ -230,6 +299,7 @@ sleep 1
echo "I:removing the policy zone"
cp ns2/named.default.conf ns2/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reconfig 2>&1 | sed 's/^/I:ns2 /'
test -f dnsrpzd.pid && kill -USR1 `cat dnsrpzd.pid`
sleep 1
echo "I:resuming authority server"
if [ "$CYGWIN" ]; then
@ -243,8 +313,8 @@ for n in 1 2 3 4 5 6 7 8 9; do
sleep 1
[ -s dig.out.${t} ] || continue
grep "status: NOERROR" dig.out.${t} > /dev/null 2>&1 || {
echo "I:test ${t} failed"
status=1
echo "I:test ${t} failed"
status=1
}
done
@ -381,5 +451,10 @@ if test $p1 -le $p2; then ret=1; fi
if test $ret != 0; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:exit status: $status"
[ $status -ne 0 ] && pf=fail || pf=pass
case $DNSRPS_TEST_MODE in
1) echo "I:status (native RPZ sub-test): $status ($pf)";;
2) echo "I:status (DNSRPS sub-test): $status ($pf)";;
*) echo "I:invalid test mode";;
esac
[ $status -eq 0 ] || exit 1

View file

@ -155,16 +155,22 @@ int sigwait(const unsigned int *set, int *sig);
/* Define if you cannot bind() before connect() for TCP sockets. */
#undef BROKEN_TCP_BIND_BEFORE_CONNECT
/* dnsrps $librpz_name */
#undef DNSRPS_LIBRPZ_PATH
/* 0=no DNSRPS 1=static link 2=dlopen() */
#undef DNSRPS_LIB_OPEN
/* Define to enable "rrset-order fixed" syntax. */
#undef DNS_RDATASET_FIXED
/* Define to enable American Fuzzy Lop test harness */
#undef ENABLE_AFL
/* Define to enable rpz-nsdname rules. */
/* Define to enable rpz nsdname rules. */
#undef ENABLE_RPZ_NSDNAME
/* Define to enable rpz-nsip rules. */
/* Define to enable rpz nsip rules. */
#undef ENABLE_RPZ_NSIP
/* Solaris hack to get select_large_fdset. */
@ -530,6 +536,9 @@ int sigwait(const unsigned int *set, int *sig);
/* Define to allow building of objects for dlopen(). */
#undef ISC_DLZ_DLOPEN
/* have __attribute__s used in librpz.h */
#undef LIBRPZ_HAVE_ATTR
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
@ -578,6 +587,9 @@ int sigwait(const unsigned int *set, int *sig);
/* Define to use large-system tuning. */
#undef TUNE_LARGE
/* Enable DNS Response Policy Service API */
#undef USE_DNSRPS
/* Defined if you need to use ioctl(FIONBIO) instead a fcntl call to make
non-blocking. */
#undef USE_FIONBIO_IOCTL

260
configure vendored
View file

@ -935,6 +935,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@ -1022,6 +1023,10 @@ enable_atomic
enable_fixed_rrset
enable_rpz_nsip
enable_rpz_nsdname
enable_dnsrps_dl
with_dnsrps_libname
with_dnsrps_dir
enable_dnsrps
enable_filter_aaaa
enable_dnstap
with_protobuf_c
@ -1092,6 +1097,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@ -1344,6 +1350,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1481,7 +1496,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@ -1634,6 +1649,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -1702,8 +1718,10 @@ Optional Features:
--enable-atomic enable machine specific atomic operations
[default=autodetect]
--enable-fixed-rrset enable fixed rrset ordering [default=no]
--disable-rpz-nsip disable rpz-nsip rules [default=enabled]
--disable-rpz-nsdname disable rpz-nsdname rules [default=enabled]
--disable-rpz-nsip disable rpz nsip rules [default=enabled]
--disable-rpz-nsdname disable rpz nsdname rules [default=enabled]
--enable-dnsrps-dl DNS Response Policy Service delayed link [default=$librpz_dl]
--enable-dnsrps enable DNS Response Policy Service API
--enable-filter-aaaa enable filtering of AAAA records [default=no]
--enable-dnstap enable dnstap support (requires fstrm, protobuf-c)
--enable-querytrace enable very verbose query trace logging [default=no]
@ -1743,6 +1761,8 @@ Optional Packages:
--with-kame=PATH use Kame IPv6 default path /usr/local/v6
--with-readline=LIBSPEC specify readline library default auto
--with-dnsrps-libname DNSRPS provider library name (librpz.so)
--with-dnsrps-dir path to DNSRPS provider library
--with-protobuf-c=path Path where protobuf-c is installed, for dnstap
--with-libfstrm=path Path where libfstrm is installed, for dnstap
--with-docbook-xsl=PATH specify path for Docbook-XSL stylesheets
@ -20613,6 +20633,232 @@ $as_echo "#define ENABLE_RPZ_NSDNAME 1" >>confdefs.h
;;
esac
#
# Response policy rewriting using DNS Response Policy Service (DNSRPS)
# interface.
#
# DNSRPS can be compiled into BIND everywhere with a reasonably
# modern C compiler. It is enabled on systems with dlopen() and librpz.so.
#
dnsrps_avail=yes
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for librpz __attribute__s" >&5
$as_echo_n "checking for librpz __attribute__s... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
extern void f(char *p __attribute__((unused)), ...)
__attribute__((format(printf,1,2))) __attribute__((__noreturn__));
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
librpz_have_attr=yes
$as_echo "#define LIBRPZ_HAVE_ATTR 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
librpz_have_attr=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
$as_echo_n "checking for library containing dlopen... " >&6; }
if ${ac_cv_search_dlopen+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char dlopen ();
int
main ()
{
return dlopen ();
;
return 0;
}
_ACEOF
for ac_lib in '' dl; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_dlopen=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_dlopen+:} false; then :
break
fi
done
if ${ac_cv_search_dlopen+:} false; then :
else
ac_cv_search_dlopen=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
$as_echo "$ac_cv_search_dlopen" >&6; }
ac_res=$ac_cv_search_dlopen
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
fi
librpz_dl=yes
for ac_func in dlopen dlclose dlsym
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
else
librpz_dl=no
fi
done
# Check whether --enable-dnsrps-dl was given.
if test "${enable_dnsrps_dl+set}" = set; then :
enableval=$enable_dnsrps_dl; enable_librpz_dl="$enableval"
else
enable_librpz_dl="$librpz_dl"
fi
# Check whether --with-dnsrps-libname was given.
if test "${with_dnsrps_libname+set}" = set; then :
withval=$with_dnsrps_libname; librpz_name="$withval"
else
librpz_name="librpz.so"
fi
# Check whether --with-dnsrps-dir was given.
if test "${with_dnsrps_dir+set}" = set; then :
withval=$with_dnsrps_dir; librpz_path="$withval/$librpz_name"
else
librpz_path="$librpz_name"
fi
cat >>confdefs.h <<_ACEOF
#define DNSRPS_LIBRPZ_PATH "$librpz_path"
_ACEOF
if test "x$enable_librpz_dl" = "xyes"; then
dnsrps_lib_open=2
else
dnsrps_lib_open=1
# Add librpz.so to linked libraries if we are not using dlopen()
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing librpz_client_create" >&5
$as_echo_n "checking for library containing librpz_client_create... " >&6; }
if ${ac_cv_search_librpz_client_create+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char librpz_client_create ();
int
main ()
{
return librpz_client_create ();
;
return 0;
}
_ACEOF
for ac_lib in '' rpz; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_librpz_client_create=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_librpz_client_create+:} false; then :
break
fi
done
if ${ac_cv_search_librpz_client_create+:} false; then :
else
ac_cv_search_librpz_client_create=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_librpz_client_create" >&5
$as_echo "$ac_cv_search_librpz_client_create" >&6; }
ac_res=$ac_cv_search_librpz_client_create
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
else
dnsrps_lib_open=0
dnsrps_avail=no
fi
fi
cat >>confdefs.h <<_ACEOF
#define DNSRPS_LIB_OPEN $dnsrps_lib_open
_ACEOF
# Check whether --enable-dnsrps was given.
if test "${enable_dnsrps+set}" = set; then :
enableval=$enable_dnsrps; enable_dnsrps=$enableval
else
enable_dnsrps=no
fi
if test "x$enable_dnsrps" != "xno"; then
if test "x$dnsrps_avail" != "xyes"; then
as_fn_error $? "dlopen and librpz.so needed for DNSRPS" "$LINENO" 5
fi
if test "x$dnsrps_lib_open" = "x0"; then
as_fn_error $? "dlopen and librpz.so needed for DNSRPS" "$LINENO" 5
fi
$as_echo "#define USE_DNSRPS 1" >>confdefs.h
fi
#
# Activate "filter-aaaa-on-v4/v6" or not?
#
@ -23306,7 +23552,7 @@ ac_config_commands="$ac_config_commands chmod"
# elsewhere if there's a good reason for doing so.
#
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/inline/checkdsa.sh bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/Makefile unit/unittest.sh"
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/inline/checkdsa.sh bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/Makefile unit/unittest.sh"
#
@ -24376,6 +24622,7 @@ do
"bin/tests/system/inline/checkdsa.sh") CONFIG_FILES="$CONFIG_FILES bin/tests/system/inline/checkdsa.sh" ;;
"bin/tests/system/pipelined/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/pipelined/Makefile" ;;
"bin/tests/system/rndc/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rndc/Makefile" ;;
"bin/tests/system/rpz/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rpz/Makefile" ;;
"bin/tests/system/rsabigexponent/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rsabigexponent/Makefile" ;;
"bin/tests/system/tkey/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/tkey/Makefile" ;;
"bin/tests/tasks/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/tasks/Makefile" ;;
@ -25805,6 +26052,8 @@ report() {
echo " ECDSA algorithm support (--with-ecdsa)"
test "yes" = "$OPENSSL_ED25519" -o "$PKCS11_ED25519" && \
echo " EDDSA algorithm support (--with-eddsa)"
test "yes" = "$enable_dnsrps" && \
echo " DNS Response Policy Service interface (--enable-dnsrps)"
test "yes" = "$enable_fixed" && \
echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)"
test "yes" = "$enable_filter" && \
@ -25851,6 +26100,9 @@ report() {
test "no" = "$use_geoip" && echo " GeoIP access control (--with-geoip)"
test "no" = "$use_gssapi" && echo " GSS-API (--with-gssapi)"
test "no" = "$enable_dnsrps" && \
echo " DNS Response Policy Service interface (--enable-dnsrps)"
test "yes" = "$enable_fixed" || \
echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)"

View file

@ -4235,13 +4235,13 @@ esac
# Enable response policy rewriting using NS IP addresses
#
AC_ARG_ENABLE(rpz-nsip,
[ --disable-rpz-nsip disable rpz-nsip rules [[default=enabled]]],
[ --disable-rpz-nsip disable rpz nsip rules [[default=enabled]]],
enable_nsip="$enableval",
enable_nsip="yes")
case "$enable_nsip" in
yes)
AC_DEFINE(ENABLE_RPZ_NSIP, 1,
[Define to enable rpz-nsip rules.])
[Define to enable rpz nsip rules.])
;;
no)
;;
@ -4253,13 +4253,13 @@ esac
# Enable response policy rewriting using NS name
#
AC_ARG_ENABLE(rpz-nsdname,
[ --disable-rpz-nsdname disable rpz-nsdname rules [[default=enabled]]],
[ --disable-rpz-nsdname disable rpz nsdname rules [[default=enabled]]],
enable_nsdname="$enableval",
enable_nsdname="yes")
case "$enable_nsdname" in
yes)
AC_DEFINE(ENABLE_RPZ_NSDNAME, 1,
[Define to enable rpz-nsdname rules.])
[Define to enable rpz nsdname rules.])
;;
no)
;;
@ -4267,6 +4267,66 @@ case "$enable_nsdname" in
;;
esac
#
# Response policy rewriting using DNS Response Policy Service (DNSRPS)
# interface.
#
# DNSRPS can be compiled into BIND everywhere with a reasonably
# modern C compiler. It is enabled on systems with dlopen() and librpz.so.
#
dnsrps_avail=yes
AC_MSG_CHECKING([for librpz __attribute__s])
AC_TRY_COMPILE(,[
extern void f(char *p __attribute__((unused)), ...)
__attribute__((format(printf,1,2))) __attribute__((__noreturn__));],
librpz_have_attr=yes
AC_DEFINE([LIBRPZ_HAVE_ATTR], 1, [have __attribute__s used in librpz.h])
AC_MSG_RESULT([yes]),
librpz_have_attr=no
AC_MSG_RESULT([no]))
AC_SEARCH_LIBS(dlopen, dl)
librpz_dl=yes
AC_CHECK_FUNCS(dlopen dlclose dlsym,,librpz_dl=no)
AC_ARG_ENABLE([dnsrps-dl],
[ --enable-dnsrps-dl DNS Response Policy Service delayed link [[default=$librpz_dl]]],
[enable_librpz_dl="$enableval"],
[enable_librpz_dl="$librpz_dl"])
AC_ARG_WITH([dnsrps-libname],
[ --with-dnsrps-libname DNSRPS provider library name (librpz.so)],
[librpz_name="$withval"], [librpz_name="librpz.so"])
AC_ARG_WITH([dnsrps-dir],
[ --with-dnsrps-dir path to DNSRPS provider library],
[librpz_path="$withval/$librpz_name"], [librpz_path="$librpz_name"])
AC_DEFINE_UNQUOTED([DNSRPS_LIBRPZ_PATH], ["$librpz_path"],
[dnsrps $librpz_name])
if test "x$enable_librpz_dl" = "xyes"; then
dnsrps_lib_open=2
else
dnsrps_lib_open=1
# Add librpz.so to linked libraries if we are not using dlopen()
AC_SEARCH_LIBS([librpz_client_create], [rpz], [],
[dnsrps_lib_open=0
dnsrps_avail=no])
fi
AC_DEFINE_UNQUOTED([DNSRPS_LIB_OPEN], [$dnsrps_lib_open],
[0=no DNSRPS 1=static link 2=dlopen()])
AC_ARG_ENABLE([dnsrps],
AS_HELP_STRING([--enable-dnsrps],
[enable DNS Response Policy Service API]),
[enable_dnsrps=$enableval],
[enable_dnsrps=no])
if test "x$enable_dnsrps" != "xno"; then
if test "x$dnsrps_avail" != "xyes"; then
AC_MSG_ERROR([[dlopen and librpz.so needed for DNSRPS]])
fi
if test "x$dnsrps_lib_open" = "x0"; then
AC_MSG_ERROR([[dlopen and librpz.so needed for DNSRPS]])
fi
AC_DEFINE([USE_DNSRPS], [1], [Enable DNS Response Policy Service API])
fi
#
# Activate "filter-aaaa-on-v4/v6" or not?
#
@ -5165,6 +5225,7 @@ AC_CONFIG_FILES([
bin/tests/system/inline/checkdsa.sh
bin/tests/system/pipelined/Makefile
bin/tests/system/rndc/Makefile
bin/tests/system/rpz/Makefile
bin/tests/system/rsabigexponent/Makefile
bin/tests/system/tkey/Makefile
bin/tests/tasks/Makefile
@ -5321,6 +5382,8 @@ report() {
echo " ECDSA algorithm support (--with-ecdsa)"
test "yes" = "$OPENSSL_ED25519" -o "$PKCS11_ED25519" && \
echo " EDDSA algorithm support (--with-eddsa)"
test "yes" = "$enable_dnsrps" && \
echo " DNS Response Policy Service interface (--enable-dnsrps)"
test "yes" = "$enable_fixed" && \
echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)"
test "yes" = "$enable_filter" && \
@ -5367,6 +5430,9 @@ report() {
test "no" = "$use_geoip" && echo " GeoIP access control (--with-geoip)"
test "no" = "$use_gssapi" && echo " GSS-API (--with-gssapi)"
test "no" = "$enable_dnsrps" && \
echo " DNS Response Policy Service interface (--enable-dnsrps)"
test "yes" = "$enable_fixed" || \
echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)"

View file

@ -4521,7 +4521,9 @@ badresp:1,adberr:0,findfail:0,valfail:0]
[ <command>recursive-only</command> <replaceable>yes_or_no</replaceable> ]
[ <command>log</command> <replaceable>yes_or_no</replaceable> ]
[ <command>max-policy-ttl</command> <replaceable>number</replaceable> ]
[ <command>min-update-interval</command> <replaceable>number</replaceable> ] ;
[ <command>min-update-interval</command> <replaceable>number</replaceable> ]
[ <command>nsip-enable <replaceable>yes_or_no</replaceable> ]
[ <command>nsdname-enable <replaceable>yes_or_no</replaceable> ] ;
...
<command>}</command> [ <command>recursive-only</command> <replaceable>yes_or_no</replaceable> ]
[ <command>max-policy-ttl</command> <replaceable>number</replaceable> ]
@ -4529,7 +4531,11 @@ badresp:1,adberr:0,findfail:0,valfail:0]
[ <command>break-dnssec</command> <replaceable>yes_or_no</replaceable> ]
[ <command>min-ns-dots</command> <replaceable>number</replaceable> ]
[ <command>nsip-wait-recurse</command> <replaceable>yes_or_no</replaceable> ]
[ <command>qname-wait-recurse</command> <replaceable>yes_or_no</replaceable> ] ; ]
[ <command>qname-wait-recurse</command> <replaceable>yes_or_no</replaceable> ]
[ <command>nsip-enable</command> <replaceable>yes_or_no</replaceable> ]
[ <command>nsdname-enable</command> <replaceable>yes_or_no</replaceable> ]
[ <command>dnsrps-enable</command> <replaceable>yes_or_no</replaceable> ]
[ <command>dnsrps-options</command> { <replaceable>parameters</replaceable> } ] ; ]
[ <command>catalog-zones {</command>
<command>zone</command> <replaceable>quoted_string</replaceable>
[ <option>default-masters</option> [ <command>port</command> <replaceable>ip_port</replaceable> ] [ <command>dscp</command> <replaceable>ip_dscp</replaceable> ] <command>{</command>
@ -10212,6 +10218,9 @@ deny-answer-aliases { "example.net"; };
NSIP triggers match IP addresses in A and
AAAA RRsets for domains that can be checked against NSDNAME
policy records.
The <command>nsdname-enable</command> phrase turns NSDNAME
triggers off or on for a single policy zone or all
zones.
</para>
</listitem>
</varlistentry>
@ -10227,6 +10236,9 @@ deny-answer-aliases { "example.net"; };
least <command>min-ns-dots</command> dots.
The default value of <command>min-ns-dots</command> is
1, to exclude top level domains.
The <command>nsip-enable</command> phrase turns NSIP
triggers off or on for a single policy zone or all
zones.
</para>
<para>
If a name server's IP address is not yet known,
@ -10475,11 +10487,11 @@ deny-answer-aliases { "example.net"; };
servers for listed names. To prevent that information leak, by
default any recursion needed for a request is done before any
policy triggers are considered. Because listed domains often
have slow authoritative servers, this default behavior can cost
have slow authoritative servers, this behavior can cost
significant time.
The <command>qname-wait-recurse no</command> option
overrides that default behavior when recursion cannot
change a non-error response.
The <command>qname-wait-recurse yes</command> option
overrides the default and enables that behavior
when recursion cannot change a non-error response.
The option does not affect QNAME or client-IP triggers
in policy zones listed
after other zones containing IP, NSIP and NSDNAME triggers, because
@ -10493,6 +10505,42 @@ deny-answer-aliases { "example.net"; };
discover problems at the authoritative server.
</para>
<para>
The <command>dnsrps-enable yes</command> option turns on
the DNS Rsponse Policy Service (DNSRPS) interface, if it has been
compiled in to <command>named</command> using
<command>configure --enable-dnsrps</command>.
</para>
<para>
The <command>dnsrps-options</command> block provides additional
RPZ configuration settings, which are passed through to the
DNSRPS provider library.
Multiple DNSRPS settings in an <command>dnsrps-options</command>
string should be separated with semi-colons.
The DNSRPS provider, librpz, is passed a configuration string
consisting of the <command>dnsrps-options</command> text,
concatenated with settings derived from the
<command>response-policy</command> statement.
</para>
<para>
Note: The <command>dnsrps-options</command> text should only include
configuration settings that are specific to the DNSRPS
provider. For example, the DNSRPS provider from
Farsight Security takes options such as
<command>dnsrpzd-conf</command>,
<command>dnsrpzd-sock</command>, and
<command>dnzrpzd-args</command> (for details of these options,
see the <command>librpz</command> documentation).
Other RPZ configuration settings could be included in
<command>dnsrps-options</command>
as well, but if <command>named</command> were switched
back to traditional RPZ by setting
<command>dnsrps-enable</command> to "no", those options would
be ignored.
</para>
<para>
The TTL of a record modified by RPZ policies is set from the
TTL of the relevant record in policy zone. It is then limited

View file

@ -181,6 +181,29 @@
<section xml:id="relnotes_features"><info><title>New Features</title></info>
<itemizedlist>
<listitem>
<para>
Added support for the DNS Response Policy Service (DNSRPS) API,
a mechanism to allow <command>named</command> to use an external
response policy provider. (One example of such a provider is
"FastRPZ" from Farsight Security, Inc.) This allows the same
types of policy filtering as standard RPZ, but can reduce the
workload for <command>named</command>, particularly when using
large and frequently-updated policy zones. It also enables
<command>named</command> to share response policy providers
with other DNS implementations such as Unbound.
</para>
<para>
This feature is avaiable if BIND is built with
<command>configure --enable-dnsrps</command>
and if <command>dnsrps-enable</command> is set to "yes" in
<filename>named.conf</filename>.
</para>
<para>
Thanks to Vernon Schryver and Farsight Security for the
contribution. [RT #43376]
</para>
</listitem>
<listitem>
<para>
Code implementing name server query processing has been moved

View file

@ -60,8 +60,9 @@ DNSTAPOBJS = dnstap.@O@ dnstap.pb-c.@O@
DNSOBJS = acl.@O@ adb.@O@ badcache.@O@ byaddr.@O@ \
cache.@O@ callbacks.@O@ catz.@O@ clientinfo.@O@ compress.@O@ \
db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \
dlz.@O@ dns64.@O@ dnssec.@O@ ds.@O@ dyndb.@O@ ecs.@O@ \
forward.@O@ ipkeylist.@O@ iptable.@O@ journal.@O@ keydata.@O@ \
dlz.@O@ dns64.@O@ dnsrps.@O@ dnssec.@O@ ds.@O@ dyndb.@O@ \
ecs.@O@ forward.@O@ \
ipkeylist.@O@ iptable.@O@ journal.@O@ keydata.@O@ \
keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \
master.@O@ masterdump.@O@ message.@O@ \
name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ nta.@O@ \
@ -103,7 +104,7 @@ DNSTAPSRCS = dnstap.c dnstap.pb-c.c
DNSSRCS = acl.c adb.c badcache. byaddr.c \
cache.c callbacks.c clientinfo.c compress.c \
db.c dbiterator.c dbtable.c diff.c dispatch.c \
dlz.c dns64.c dnssec.c ds.c dyndb.c ecs.c forward.c \
dlz.c dns64.c dnsrps.c dnssec.c ds.c dyndb.c ecs.c forward.c \
ipkeylist.c iptable.c journal.c keydata.c keytable.c lib.c \
log.c lookup.c master.c masterdump.c message.c \
name.c ncache.c nsec.c nsec3.c nta.c \

995
lib/dns/dnsrps.c Normal file
View file

@ -0,0 +1,995 @@
/*
* Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/*! \file */
#include <config.h>
#ifdef USE_DNSRPS
#include <isc/mem.h>
#include <isc/stdlib.h>
#include <isc/string.h>
#include <dns/db.h>
#define LIBRPZ_LIB_OPEN DNSRPS_LIB_OPEN
#include <dns/dnsrps.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/result.h>
#include <dns/rpz.h>
librpz_t *librpz;
librpz_emsg_t librpz_lib_open_emsg;
static void *librpz_handle;
#define RPSDB_MAGIC ISC_MAGIC('R', 'P', 'Z', 'F')
#define VALID_RPSDB(rpsdb) ((rpsdb)->common.impmagic == RPSDB_MAGIC)
#define RD_DB(r) ((r)->private1)
#define RD_CUR_RR(r) ((r)->private2)
#define RD_NEXT_RR(r) ((r)->resign)
#define RD_COUNT(r) ((r)->privateuint4)
typedef struct {
dns_rdatasetiter_t common;
dns_rdatatype_t type;
dns_rdataclass_t class;
uint32_t ttl;
uint count;
librpz_idx_t next_rr;
} rpsdb_rdatasetiter_t;
static dns_dbmethods_t rpsdb_db_methods;
static dns_rdatasetmethods_t rpsdb_rdataset_methods;
static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods;
static librpz_clist_t *clist;
static isc_mutex_t dnsrps_mutex;
static void
dnsrps_lock(void *mutex0) {
isc_mutex_t *mutex = mutex0;
LOCK(mutex);
}
static void
dnsrps_unlock(void *mutex0) {
isc_mutex_t *mutex = mutex0;
UNLOCK(mutex);
}
static void
dnsrps_mutex_destroy(void *mutex0) {
isc_mutex_t *mutex = mutex0;
DESTROYLOCK(mutex);
}
static void
dnsrps_log_fnc(librpz_log_level_t level, void *ctxt, const char *buf) {
int isc_level;
UNUSED(ctxt);
/* Setting librpz_log_level in the configuration overrides the
* BIND9 logging levels. */
if (level > LIBRPZ_LOG_TRACE1 &&
level <= librpz->log_level_val(LIBRPZ_LOG_INVALID))
level = LIBRPZ_LOG_TRACE1;
switch(level) {
case LIBRPZ_LOG_FATAL:
case LIBRPZ_LOG_ERROR: /* errors */
default:
isc_level = DNS_RPZ_ERROR_LEVEL;
break;
case LIBRPZ_LOG_TRACE1: /* big events such as dnsrpzd starts */
isc_level = DNS_RPZ_INFO_LEVEL;
break;
case LIBRPZ_LOG_TRACE2: /* smaller dnsrpzd zone transfers */
isc_level = DNS_RPZ_DEBUG_LEVEL1;
break;
case LIBRPZ_LOG_TRACE3: /* librpz hits */
isc_level = DNS_RPZ_DEBUG_LEVEL2;
break;
case LIBRPZ_LOG_TRACE4: /* librpz lookups */
isc_level = DNS_RPZ_DEBUG_LEVEL3;
break;
}
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
isc_level, "dnsrps: %s", buf);
}
/*
* Start dnsrps for the entire server.
* This is not thread safe, but it is called by a single thread.
*/
isc_result_t
dns_dnsrps_server_create(void) {
librpz_emsg_t emsg;
isc_result_t result;
INSIST(clist == NULL);
INSIST(librpz == NULL);
INSIST(librpz_handle == NULL);
/*
* Notice if librpz is available.
*/
librpz = librpz_lib_open(&librpz_lib_open_emsg,
&librpz_handle, DNSRPS_LIBRPZ_PATH);
/*
* Stop now without complaining if librpz is not available.
* Complain later if and when librpz is needed for a view with
* "dnsrps-enable yse" (including the default view).
*/
if (librpz == NULL)
return (ISC_R_SUCCESS);
result = isc_mutex_init(&dnsrps_mutex);
if (result != ISC_R_SUCCESS)
return (result);
librpz->set_log(&dnsrps_log_fnc, NULL);
clist = librpz->clist_create(&emsg, dnsrps_lock, dnsrps_unlock,
dnsrps_mutex_destroy, &dnsrps_mutex,
dns_lctx);
if (clist == NULL) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
"dnsrps: %s", emsg.c);
return (ISC_R_NOMEMORY);
}
return (ISC_R_SUCCESS);
}
/*
* Stop dnsrps for the entire server.
* This is not thread safe.
*/
void
dns_dnsrps_server_destroy(void) {
if (clist != NULL)
librpz->clist_detach(&clist);
#ifdef LIBRPZ_USE_DLOPEN
if (librpz != NULL) {
INSIST(librpz_handle != NULL);
if (dlclose(librpz_handle) != 0)
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
"dnsrps: dlclose(): %s", dlerror());
librpz_handle = NULL;
}
#endif
}
/*
* Ready dnsrps for a view.
*/
isc_result_t
dns_dnsrps_view_init(dns_rpz_zones_t *new, char *rps_cstr) {
librpz_emsg_t emsg;
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, DNS_RPZ_DEBUG_LEVEL3,
"dnsrps configuration \"%s\"", rps_cstr);
new->rps_client = librpz->client_create(&emsg, clist,
rps_cstr, ISC_FALSE);
if (new->rps_client == NULL) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
"librpz->client_create(): %s", emsg.c);
new->p.dnsrps_enabled = ISC_FALSE;
return (ISC_R_FAILURE);
}
new->p.dnsrps_enabled = ISC_TRUE;
return (ISC_R_SUCCESS);
}
/*
* Connect to and start the dnsrps daemon, dnsrpzd.
*/
isc_result_t
dns_dnsrps_connect(dns_rpz_zones_t *rpzs) {
librpz_emsg_t emsg;
if (rpzs == NULL || !rpzs->p.dnsrps_enabled)
return (ISC_R_SUCCESS);
/*
* Fail only if we failed to link to librpz.
*/
if (librpz == NULL) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
"librpz->connect(): %s", librpz_lib_open_emsg.c);
return (ISC_R_FAILURE);
}
if (!librpz->connect(&emsg, rpzs->rps_client, true)) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
"librpz->connect(): %s", emsg.c);
return (ISC_R_SUCCESS);
}
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
DNS_RPZ_INFO_LEVEL, "dnsrps: librpz version %s",
librpz->version);
return (ISC_R_SUCCESS);
}
/*
* Get ready to try RPZ rewriting.
*/
isc_result_t
dns_dnsrps_rewrite_init(librpz_emsg_t *emsg, dns_rpz_st_t *st,
dns_rpz_zones_t *rpzs, const dns_name_t *qname,
isc_mem_t *mctx, isc_boolean_t have_rd)
{
rpsdb_t *rpsdb;
rpsdb = isc_mem_get(mctx, sizeof(*rpsdb));
if (rpsdb == NULL) {
strlcpy(emsg->c, "no memory", sizeof(emsg->c));
return (ISC_R_NOMEMORY);
}
memset(rpsdb, 0, sizeof(*rpsdb));
if (!librpz->rsp_create(emsg, &rpsdb->rsp, NULL,
rpzs->rps_client, have_rd, false)) {
isc_mem_put(mctx, rpsdb, sizeof(*rpsdb));
return (DNS_R_SERVFAIL);
}
if (rpsdb->rsp == NULL) {
isc_mem_put(mctx, rpsdb, sizeof(*rpsdb));
return (DNS_R_DISALLOWED);
}
rpsdb->common.magic = DNS_DB_MAGIC;
rpsdb->common.impmagic = RPSDB_MAGIC;
rpsdb->common.methods = &rpsdb_db_methods;
rpsdb->common.rdclass = dns_rdataclass_in;
dns_name_init(&rpsdb->common.origin, NULL);
isc_mem_attach(mctx, &rpsdb->common.mctx);
rpsdb->ref_cnt = 1;
rpsdb->qname = qname;
st->rpsdb = &rpsdb->common;
return (ISC_R_SUCCESS);
}
/*
* Convert a dnsrps policy to a classic BIND9 RPZ policy.
*/
dns_rpz_policy_t
dns_dnsrps_2policy(librpz_policy_t rps_policy) {
switch (rps_policy) {
case LIBRPZ_POLICY_UNDEFINED:
return (DNS_RPZ_POLICY_MISS);
case LIBRPZ_POLICY_PASSTHRU:
return (DNS_RPZ_POLICY_PASSTHRU);
case LIBRPZ_POLICY_DROP:
return (DNS_RPZ_POLICY_DROP);
case LIBRPZ_POLICY_TCP_ONLY:
return (DNS_RPZ_POLICY_TCP_ONLY);
case LIBRPZ_POLICY_NXDOMAIN:
return (DNS_RPZ_POLICY_NXDOMAIN);
case LIBRPZ_POLICY_NODATA:
return (DNS_RPZ_POLICY_NODATA);
case LIBRPZ_POLICY_RECORD:
case LIBRPZ_POLICY_CNAME:
return (DNS_RPZ_POLICY_RECORD);
case LIBRPZ_POLICY_DELETED:
case LIBRPZ_POLICY_GIVEN:
case LIBRPZ_POLICY_DISABLED:
default:
INSIST(0);
}
}
/*
* Convert a dnsrps trigger to a classic BIND9 RPZ rewrite or trigger type.
*/
dns_rpz_type_t
dns_dnsrps_trig2type(librpz_trig_t trig) {
switch (trig) {
case LIBRPZ_TRIG_BAD:
default:
return (DNS_RPZ_TYPE_BAD);
case LIBRPZ_TRIG_CLIENT_IP:
return (DNS_RPZ_TYPE_CLIENT_IP);
case LIBRPZ_TRIG_QNAME:
return (DNS_RPZ_TYPE_QNAME);
case LIBRPZ_TRIG_IP:
return (DNS_RPZ_TYPE_IP);
case LIBRPZ_TRIG_NSDNAME:
return (DNS_RPZ_TYPE_NSDNAME);
case LIBRPZ_TRIG_NSIP:
return (DNS_RPZ_TYPE_NSIP);
}
}
/*
* Convert a classic BIND9 RPZ rewrite or trigger type to a librpz trigger type.
*/
librpz_trig_t
dns_dnsrps_type2trig(dns_rpz_type_t type) {
switch (type) {
case DNS_RPZ_TYPE_BAD:
default:
return (LIBRPZ_TRIG_BAD);
case DNS_RPZ_TYPE_CLIENT_IP:
return (LIBRPZ_TRIG_CLIENT_IP);
case DNS_RPZ_TYPE_QNAME:
return (LIBRPZ_TRIG_QNAME);
case DNS_RPZ_TYPE_IP:
return (LIBRPZ_TRIG_IP);
case DNS_RPZ_TYPE_NSDNAME:
return (LIBRPZ_TRIG_NSDNAME);
case DNS_RPZ_TYPE_NSIP:
return (LIBRPZ_TRIG_NSIP);
}
}
static void
rpsdb_attach(dns_db_t *source, dns_db_t **targetp) {
rpsdb_t *rpsdb = (rpsdb_t *)source;
REQUIRE(VALID_RPSDB(rpsdb));
/*
* Use a simple count because only one thread uses any single rpsdb_t
*/
++rpsdb->ref_cnt;
*targetp = source;
}
static void
rpsdb_detach(dns_db_t **dbp) {
rpsdb_t *rpsdb = (rpsdb_t *)*dbp;
REQUIRE(VALID_RPSDB(rpsdb));
REQUIRE(rpsdb->ref_cnt > 0);
*dbp = NULL;
/*
* Simple count because only one thread uses a rpsdb_t.
*/
if (--rpsdb->ref_cnt != 0)
return;
librpz->rsp_detach(&rpsdb->rsp);
rpsdb->common.impmagic = 0;
isc_mem_putanddetach(&rpsdb->common.mctx, rpsdb, sizeof(*rpsdb));
}
static void
rpsdb_attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
rpsdb_t *rpsdb = (rpsdb_t *)db;
REQUIRE(VALID_RPSDB(rpsdb));
REQUIRE(targetp != NULL && *targetp == NULL);
REQUIRE(source == &rpsdb->origin_node ||
source == &rpsdb->data_node);
/*
* Simple count because only one thread uses a rpsdb_t.
*/
++rpsdb->ref_cnt;
*targetp = source;
}
static void
rpsdb_detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
rpsdb_t *rpsdb = (rpsdb_t *)db;
REQUIRE(VALID_RPSDB(rpsdb));
REQUIRE(*targetp == &rpsdb->origin_node ||
*targetp == &rpsdb->data_node);
*targetp = NULL;
rpsdb_detach(&db);
}
static isc_result_t
rpsdb_findnode(dns_db_t *db, const dns_name_t *name, isc_boolean_t create,
dns_dbnode_t **nodep)
{
rpsdb_t *rpsdb = (rpsdb_t *)db;
dns_db_t *dbp;
REQUIRE(VALID_RPSDB(rpsdb));
REQUIRE(nodep != NULL && *nodep == NULL);
REQUIRE(!create);
/*
* A fake/shim rpsdb has two nodes.
* One is the origin to support query_addsoa() in bin/named/query.c.
* The other contains rewritten RRs.
*/
if (dns_name_equal(name, &db->origin))
*nodep = &rpsdb->origin_node;
else
*nodep = &rpsdb->data_node;
dbp = NULL;
rpsdb_attach(db, &dbp);
return (ISC_R_SUCCESS);
}
static void
rpsdb_bind_rdataset(dns_rdataset_t *rdataset, uint count, librpz_idx_t next_rr,
dns_rdatatype_t type, uint16_t class, uint32_t ttl,
rpsdb_t *rpsdb)
{
dns_db_t *dbp;
INSIST(rdataset->methods == NULL); /* We must be disassociated. */
REQUIRE(type != dns_rdatatype_none);
rdataset->methods = &rpsdb_rdataset_methods;
rdataset->rdclass = class;
rdataset->type = type;
rdataset->ttl = ttl;
dbp = NULL;
dns_db_attach(&rpsdb->common, &dbp);
RD_DB(rdataset) = dbp;
RD_COUNT(rdataset) = count;
RD_NEXT_RR(rdataset) = next_rr;
RD_CUR_RR(rdataset) = NULL;
}
static isc_result_t
rpsdb_bind_soa(dns_rdataset_t *rdataset, rpsdb_t *rpsdb) {
uint32_t ttl;
librpz_emsg_t emsg;
if (!librpz->rsp_soa(&emsg, &ttl, NULL, NULL,
&rpsdb->result, rpsdb->rsp)) {
librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
return (DNS_R_SERVFAIL);
}
rpsdb_bind_rdataset(rdataset, 1, LIBRPZ_IDX_BAD, dns_rdatatype_soa,
dns_rdataclass_in, ttl, rpsdb);
return (ISC_R_SUCCESS);
}
/*
* Forge an rdataset of the desired type from a librpz result.
* This is written for simplicity instead of speed, because RPZ rewriting
* should be rare compared to normal BIND operations.
*/
static isc_result_t
rpsdb_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_rdatatype_t type, dns_rdatatype_t covers,
isc_stdtime_t now, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset)
{
rpsdb_t *rpsdb = (rpsdb_t *)db;
dns_rdatatype_t foundtype;
dns_rdataclass_t class;
uint32_t ttl;
uint count;
librpz_emsg_t emsg;
UNUSED(version);
UNUSED(covers);
UNUSED(now);
UNUSED(sigrdataset);
REQUIRE(VALID_RPSDB(rpsdb));
if (node == &rpsdb->origin_node) {
if (type == dns_rdatatype_any)
return (ISC_R_SUCCESS);
if (type == dns_rdatatype_soa)
return (rpsdb_bind_soa(rdataset, rpsdb));
return (DNS_R_NXRRSET);
}
REQUIRE(node == &rpsdb->data_node);
switch (rpsdb->result.policy) {
case LIBRPZ_POLICY_UNDEFINED:
case LIBRPZ_POLICY_DELETED:
case LIBRPZ_POLICY_PASSTHRU:
case LIBRPZ_POLICY_DROP:
case LIBRPZ_POLICY_TCP_ONLY:
case LIBRPZ_POLICY_GIVEN:
case LIBRPZ_POLICY_DISABLED:
default:
librpz->log(LIBRPZ_LOG_ERROR, NULL,
"impossible dnsrps policy %d at %s:%d",
rpsdb->result.policy, __FILE__, __LINE__);
return (DNS_R_SERVFAIL);
case LIBRPZ_POLICY_NXDOMAIN:
return (DNS_R_NXDOMAIN);
case LIBRPZ_POLICY_NODATA:
return (DNS_R_NXRRSET);
case LIBRPZ_POLICY_RECORD:
case LIBRPZ_POLICY_CNAME:
break;
}
if (type == dns_rdatatype_soa)
return (rpsdb_bind_soa(rdataset, rpsdb));
/*
* There is little to do for an ANY query.
*/
if (type == dns_rdatatype_any)
return (ISC_R_SUCCESS);
/*
* Reset to the start of the RRs.
* This function is only used after a policy has been chosen,
* and so without caring whether it is after recursion.
*/
if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
return (DNS_R_SERVFAIL);
}
if (!librpz->rsp_rr(&emsg, &foundtype, &class, &ttl, NULL,
&rpsdb->result, rpsdb->qname->ndata,
rpsdb->qname->length, rpsdb->rsp)) {
librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
return (DNS_R_SERVFAIL);
}
REQUIRE(foundtype != dns_rdatatype_none);
/*
* Ho many of the target RR type are available?
*/
count = 0;
do {
if (type == foundtype || type == dns_rdatatype_any)
++count;
if (!librpz->rsp_rr(&emsg, &foundtype, NULL, NULL, NULL,
&rpsdb->result, rpsdb->qname->ndata,
rpsdb->qname->length, rpsdb->rsp)) {
librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
return (DNS_R_SERVFAIL);
}
} while (foundtype != dns_rdatatype_none);
if (count == 0)
return (DNS_R_NXRRSET);
rpsdb_bind_rdataset(rdataset, count, rpsdb->result.next_rr,
type, class, ttl, rpsdb);
return (ISC_R_SUCCESS);
}
static isc_result_t
rpsdb_finddb(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
dns_dbnode_t **nodep, dns_name_t *foundname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
dns_dbnode_t *node;
isc_result_t result;
UNUSED(version);
UNUSED(options);
UNUSED(now);
UNUSED(sigrdataset);
if (nodep == NULL) {
node = NULL;
nodep = &node;
}
rpsdb_findnode(db, name, false, nodep);
result = dns_name_copy(name, foundname, NULL);
if (result != ISC_R_SUCCESS)
return (result);
return (rpsdb_findrdataset(db, *nodep, NULL, type, 0, 0,
rdataset, sigrdataset));
}
static isc_result_t
rpsdb_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
{
rpsdb_t *rpsdb = (rpsdb_t *)db;
rpsdb_rdatasetiter_t *rpsdb_iter;
UNUSED(version);
UNUSED(now);
REQUIRE(VALID_RPSDB(rpsdb));
REQUIRE(node == &rpsdb->origin_node || node == &rpsdb->data_node);
rpsdb_iter = isc_mem_get(rpsdb->common.mctx, sizeof(*rpsdb_iter));
if (rpsdb_iter == NULL)
return (ISC_R_NOMEMORY);
memset(rpsdb_iter, 0, sizeof(*rpsdb_iter));
rpsdb_iter->common.magic = DNS_RDATASETITER_MAGIC;
rpsdb_iter->common.methods = &rpsdb_rdatasetiter_methods;
rpsdb_iter->common.db = db;
rpsdb_attachnode(db, node, &rpsdb_iter->common.node);
*iteratorp = &rpsdb_iter->common;
return (ISC_R_SUCCESS);
}
static isc_boolean_t
rpsdb_issecure(dns_db_t *db) {
UNUSED(db);
return (ISC_FALSE);
}
static isc_result_t
rpsdb_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
rpsdb_t *rpsdb = (rpsdb_t *)db;
REQUIRE(VALID_RPSDB(rpsdb));
REQUIRE(nodep != NULL && *nodep == NULL);
rpsdb_attachnode(db, &rpsdb->origin_node, nodep);
return (ISC_R_SUCCESS);
}
static void
rpsdb_rdataset_disassociate(dns_rdataset_t *rdataset) {
dns_db_t *db;
/*
* Detach the last RR delivered.
*/
if (RD_CUR_RR(rdataset) != NULL) {
free(RD_CUR_RR(rdataset));
RD_CUR_RR(rdataset) = NULL;
}
db = RD_DB(rdataset);
RD_DB(rdataset) = NULL;
dns_db_detach(&db);
}
static isc_result_t
rpsdb_rdataset_next(dns_rdataset_t *rdataset) {
rpsdb_t *rpsdb;
uint16_t type;
dns_rdataclass_t class;
librpz_rr_t *rr;
librpz_emsg_t emsg;
rpsdb = RD_DB(rdataset);
/*
* Detach the previous RR.
*/
if (RD_CUR_RR(rdataset) != NULL) {
free(RD_CUR_RR(rdataset));
RD_CUR_RR(rdataset) = NULL;
}
/*
* Get the next RR of the specified type.
* SOAs differ.
*/
if (rdataset->type == dns_rdatatype_soa) {
if (RD_NEXT_RR(rdataset) == LIBRPZ_IDX_NULL)
return (ISC_R_NOMORE);
RD_NEXT_RR(rdataset) = LIBRPZ_IDX_NULL;
if (!librpz->rsp_soa(&emsg, NULL, &rr, NULL,
&rpsdb->result, rpsdb->rsp)) {
librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
return (DNS_R_SERVFAIL);
}
RD_CUR_RR(rdataset) = rr;
return (ISC_R_SUCCESS);
}
rpsdb->result.next_rr = RD_NEXT_RR(rdataset);
for (;;) {
if (!librpz->rsp_rr(&emsg, &type, &class, NULL, &rr,
&rpsdb->result, rpsdb->qname->ndata,
rpsdb->qname->length, rpsdb->rsp)) {
librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
return (DNS_R_SERVFAIL);
}
if (rdataset->type == type &&
rdataset->rdclass == class) {
RD_CUR_RR(rdataset) = rr;
RD_NEXT_RR(rdataset) = rpsdb->result.next_rr;
return (ISC_R_SUCCESS);
}
if (type == dns_rdatatype_none)
return (ISC_R_NOMORE);
free(rr);
}
}
static isc_result_t
rpsdb_rdataset_first(dns_rdataset_t *rdataset) {
rpsdb_t *rpsdb;
librpz_emsg_t emsg;
rpsdb = RD_DB(rdataset);
REQUIRE(VALID_RPSDB(rpsdb));
if (RD_CUR_RR(rdataset) != NULL) {
free(RD_CUR_RR(rdataset));
RD_CUR_RR(rdataset) = NULL;
}
if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
return (DNS_R_SERVFAIL);
}
if (rdataset->type == dns_rdatatype_soa)
RD_NEXT_RR(rdataset) = LIBRPZ_IDX_BAD;
else
RD_NEXT_RR(rdataset) = rpsdb->result.next_rr;
return (rpsdb_rdataset_next(rdataset));
}
static void
rpsdb_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
rpsdb_t *rpsdb;
librpz_rr_t *rr;
isc_region_t r;
rpsdb = RD_DB(rdataset);
REQUIRE(VALID_RPSDB(rpsdb));
rr = RD_CUR_RR(rdataset);
REQUIRE(rr != NULL);
r.length = ntohs(rr->rdlength);
r.base = rr->rdata;
dns_rdata_fromregion(rdata, ntohs(rr->class), ntohs(rr->type), &r);
}
static void
rpsdb_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
rpsdb_t *rpsdb;
dns_db_t *dbp;
INSIST(!ISC_LINK_LINKED(target, link));
*target = *source;
ISC_LINK_INIT(target, link);
rpsdb = RD_DB(source);
REQUIRE(VALID_RPSDB(rpsdb));
dbp = NULL;
dns_db_attach(&rpsdb->common, &dbp);
RD_DB(target) = dbp;
RD_CUR_RR(target) = NULL;
RD_NEXT_RR(target) = LIBRPZ_IDX_NULL;
}
static unsigned int
rpsdb_rdataset_count(dns_rdataset_t *rdataset) {
rpsdb_t *rpsdb;
rpsdb = RD_DB(rdataset);
REQUIRE(VALID_RPSDB(rpsdb));
return (RD_COUNT(rdataset));
}
static void
rpsdb_rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
rpsdb_t *rpsdb;
dns_rdatasetiter_t *iterator;
isc_mem_t *mctx;
iterator = *iteratorp;
rpsdb = (rpsdb_t *)iterator->db;
REQUIRE(VALID_RPSDB(rpsdb));
mctx = iterator->db->mctx;
dns_db_detachnode(iterator->db, &iterator->node);
isc_mem_put(mctx, iterator, sizeof(rpsdb_rdatasetiter_t));
*iteratorp = NULL;
}
static isc_result_t
rpsdb_rdatasetiter_next(dns_rdatasetiter_t *iter) {
rpsdb_t *rpsdb;
rpsdb_rdatasetiter_t *rpsdb_iter;
dns_rdatatype_t next_type, type;
dns_rdataclass_t next_class, class;
uint32_t ttl;
librpz_emsg_t emsg;
rpsdb = (rpsdb_t *)iter->db;
REQUIRE(VALID_RPSDB(rpsdb));
rpsdb_iter = (rpsdb_rdatasetiter_t *)iter;
/*
* This function is only used after a policy has been chosen,
* and so without caring whether it is after recursion.
*/
if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
return (DNS_R_SERVFAIL);
}
/*
* Find the next class and type after the current class and type
* among the RRs in current result.
* As a side effect, count the number of those RRs.
*/
rpsdb_iter->count = 0;
next_class = dns_rdataclass_reserved0;
next_type = dns_rdatatype_none;
for (;;) {
if (!librpz->rsp_rr(&emsg, &type, &class, &ttl,
NULL, &rpsdb->result, rpsdb->qname->ndata,
rpsdb->qname->length, rpsdb->rsp)) {
librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
return (DNS_R_SERVFAIL);
}
if (type == dns_rdatatype_none) {
if (next_type == dns_rdatatype_none)
return (ISC_R_NOMORE);
rpsdb_iter->type = next_type;
rpsdb_iter->class = next_class;
return (ISC_R_SUCCESS);
}
/*
* Skip RRs with the current class and type or before.
*/
if (rpsdb_iter->class > class ||
(rpsdb_iter->class = class && rpsdb_iter->type >= type))
continue;
if (next_type == dns_rdatatype_none ||
next_class > class ||
(next_class == class && next_type > type)) {
/*
* This is the first of a subsequent class and type.
*/
next_type = type;
next_class = class;
rpsdb_iter->ttl = ttl;
rpsdb_iter->count = 1;
rpsdb_iter->next_rr = rpsdb->result.next_rr;
} else if (next_type == type && next_class == class) {
++rpsdb_iter->count;
}
}
}
static isc_result_t
rpsdb_rdatasetiter_first(dns_rdatasetiter_t *iterator) {
rpsdb_t *rpsdb;
rpsdb_rdatasetiter_t *rpsdb_iter;
rpsdb = (rpsdb_t *)iterator->db;
REQUIRE(VALID_RPSDB(rpsdb));
rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator;
rpsdb_iter->type = dns_rdatatype_none;
rpsdb_iter->class = dns_rdataclass_reserved0;
return (rpsdb_rdatasetiter_next(iterator));
}
static void
rpsdb_rdatasetiter_current(dns_rdatasetiter_t *iterator,
dns_rdataset_t *rdataset)
{
rpsdb_t *rpsdb;
rpsdb_rdatasetiter_t *rpsdb_iter;
rpsdb = (rpsdb_t *)iterator->db;
REQUIRE(VALID_RPSDB(rpsdb));
rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator;
REQUIRE(rpsdb_iter->type != dns_rdatatype_none);
rpsdb_bind_rdataset(rdataset,
rpsdb_iter->count, rpsdb_iter->next_rr,
rpsdb_iter->type, rpsdb_iter->class,
rpsdb_iter->ttl, rpsdb);
}
static dns_dbmethods_t rpsdb_db_methods = {
rpsdb_attach,
rpsdb_detach,
NULL, /* beginload */
NULL, /* endload */
NULL, /* serialize */
NULL, /* dump */
NULL, /* currentversion */
NULL, /* newversion */
NULL, /* attachversion */
NULL, /* closeversion */
rpsdb_findnode,
rpsdb_finddb,
NULL, /* findzonecut*/
rpsdb_attachnode,
rpsdb_detachnode,
NULL, /* expirenode */
NULL, /* printnode */
NULL, /* createiterator */
rpsdb_findrdataset,
rpsdb_allrdatasets,
NULL, /* addrdataset */
NULL, /* subtractrdataset */
NULL, /* deleterdataset */
rpsdb_issecure,
NULL, /* nodecount */
NULL, /* ispersistent */
NULL, /* overmem */
NULL, /* settask */
rpsdb_getoriginnode,
NULL, /* transfernode */
NULL, /* getnsec3parameters */
NULL, /* findnsec3node */
NULL, /* setsigningtime */
NULL, /* getsigningtime */
NULL, /* resigned */
NULL, /* isdnssec */
NULL, /* getrrsetstats */
NULL, /* rpz_attach */
NULL, /* rpz_ready */
NULL, /* findnodeext */
NULL, /* findext */
NULL, /* setcachestats */
NULL, /* hashsize */
NULL, /* nodefullname */
NULL /* getsize */
};
static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
rpsdb_rdataset_disassociate,
rpsdb_rdataset_first,
rpsdb_rdataset_next,
rpsdb_rdataset_current,
rpsdb_rdataset_clone,
rpsdb_rdataset_count,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods = {
rpsdb_rdatasetiter_destroy,
rpsdb_rdatasetiter_first,
rpsdb_rdatasetiter_next,
rpsdb_rdatasetiter_current
};
#endif /* USE_DNSRPS */

View file

@ -14,12 +14,12 @@ HEADERS = acl.h adb.h badcache.h bit.h byaddr.h \
cache.h callbacks.h catz.h cert.h \
client.h clientinfo.h compress.h \
db.h dbiterator.h dbtable.h diff.h dispatch.h \
dlz.h dlz_dlopen.h dns64.h dnssec.h ds.h dsdigest.h \
dlz.h dlz_dlopen.h dns64.h dnsrps.h dnssec.h ds.h dsdigest.h \
dnstap.h dyndb.h ecs.h \
edns.h ecdb.h events.h fixedname.h forward.h geoip.h \
ipkeylist.h iptable.h \
journal.h keydata.h keyflags.h keytable.h keyvalues.h \
lib.h lookup.h log.h master.h masterdump.h message.h \
lib.h librpz.h lookup.h log.h master.h masterdump.h message.h \
name.h ncache.h nsec.h nsec3.h nta.h opcode.h order.h \
peer.h portlist.h private.h \
rbt.h rcode.h rdata.h rdataclass.h rdatalist.h \

View file

@ -0,0 +1,95 @@
#ifndef DNS_DNSRPS_H
#define DNS_DNSRPS_H
#include <isc/lang.h>
#include <dns/types.h>
#include <config.h>
#ifdef USE_DNSRPS
#include <dns/librpz.h>
#include <dns/rpz.h>
/*
* Error message if dlopen(librpz) failed.
*/
extern librpz_emsg_t librpz_lib_open_emsg;
/*
* These shim BIND9 database, node, and rdataset are handles on RRs from librpz.
*
* All of these structures are used by a single thread and so need no locks.
*
* rpsdb_t holds the state for a set of RPZ queries.
*
* rpsnode_t is a link to the rpsdb_t for the set of RPZ queries
* and a flag saying whether it is pretending to be a node with RRs for
* the qname or the node with the SOA for the zone containing the rewritten
* RRs or justifying NXDOMAIN.
*/
typedef struct {
uint8_t unused;
} rpsnode_t;
typedef struct rpsdb {
dns_db_t common;
int ref_cnt;
librpz_result_id_t hit_id;
librpz_result_t result;
librpz_rsp_t* rsp;
librpz_domain_buf_t origin_buf;
const dns_name_t *qname;
rpsnode_t origin_node;
rpsnode_t data_node;
} rpsdb_t;
/*
* Convert a dnsrps policy to a classic BIND9 RPZ policy.
*/
dns_rpz_policy_t dns_dnsrps_2policy(librpz_policy_t rps_policy);
/*
* Convert a dnsrps trigger to a classic BIND9 RPZ rewrite or trigger type.
*/
dns_rpz_type_t dns_dnsrps_trig2type(librpz_trig_t trig);
/*
* Convert a classic BIND9 RPZ rewrite or trigger type to a librpz trigger type.
*/
librpz_trig_t dns_dnsrps_type2trig(dns_rpz_type_t type);
/*
* Start dnsrps for the entire server.
*/
isc_result_t dns_dnsrps_server_create(void);
/*
* Stop dnsrps for the entire server.
*/
void dns_dnsrps_server_destroy(void);
/*
* Ready dnsrps for a view.
*/
isc_result_t dns_dnsrps_view_init(dns_rpz_zones_t *new, char *rps_cstr);
/*
* Connect to and start the dnsrps daemon, dnsrpzd.
*/
isc_result_t dns_dnsrps_connect(dns_rpz_zones_t *rpzs);
/*
* Get ready to try dnsrps rewriting.
*/
isc_result_t dns_dnsrps_rewrite_init(librpz_emsg_t *emsg, dns_rpz_st_t *st,
dns_rpz_zones_t *rpzs,
const dns_name_t *qname, isc_mem_t *mctx,
isc_boolean_t have_rd);
#endif /* USE_DNSRPS */
ISC_LANG_ENDDECLS
#endif /* DNS_DNSRPS_H */

View file

@ -0,0 +1,963 @@
/*
* Copyright (C) 2017 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/.
*/
/*
* Define the interface from a DNS resolver to the Response Policy Zone
* library, librpz.
*
* This file should be included only the interface functions between the
* resolver and librpz to avoid name space pollution.
*
* Copyright (c) 2016-2017 Farsight Security, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* version 1.2.12
*/
#ifndef LIBRPZ_H
#define LIBRPZ_H
#include <arpa/nameser.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
/*
* Allow either ordinary or dlopen() linking.
*/
#ifdef LIBRPZ_INTERNAL
#define LIBDEF(t,s) extern t s;
#define LIBDEF_F(f) LIBDEF(librpz_##f##_t, librpz_##f)
#else
#define LIBDEF(t,s)
#define LIBDEF_F(f)
#endif
/*
* Response Policy Zone triggers.
* Comparisons of trigger precedences require
* LIBRPZ_TRIG_CLIENT_IP < LIBRPZ_TRIG_QNAME < LIBRPZ_TRIG_IP
* < LIBRPZ_TRIG_NSDNAME < LIBRPZ_TRIG_NSIP}
*/
typedef enum {
LIBRPZ_TRIG_BAD =0,
LIBRPZ_TRIG_CLIENT_IP =1,
LIBRPZ_TRIG_QNAME =2,
LIBRPZ_TRIG_IP =3,
LIBRPZ_TRIG_NSDNAME =4,
LIBRPZ_TRIG_NSIP =5
} librpz_trig_t;
#define LIBRPZ_TRIG_SIZE 3 /* sizeof librpz_trig_t in bits */
typedef uint8_t librpz_tbit_t; /* one bit for each of the TRIGS_NUM
* trigger types */
/*
* Response Policy Zone Actions or policies
*/
typedef enum {
LIBRPZ_POLICY_UNDEFINED =0, /* an empty entry or no decision yet */
LIBRPZ_POLICY_DELETED =1, /* placeholder for a deleted policy */
LIBRPZ_POLICY_PASSTHRU =2, /* 'passthru': do not rewrite */
LIBRPZ_POLICY_DROP =3, /* 'drop': do not respond */
LIBRPZ_POLICY_TCP_ONLY =4, /* 'tcp-only': answer UDP with TC=1 */
LIBRPZ_POLICY_NXDOMAIN =5, /* 'nxdomain': answer with NXDOMAIN */
LIBRPZ_POLICY_NODATA =6, /* 'nodata': answer with ANCOUNT=0 */
LIBRPZ_POLICY_RECORD =7, /* rewrite with the policy's RR */
/* only in client configurations to override the zone */
LIBRPZ_POLICY_GIVEN, /* 'given': what policy record says */
LIBRPZ_POLICY_DISABLED, /* at most log */
LIBRPZ_POLICY_CNAME, /* answer with 'cname x' */
} librpz_policy_t;
#define LIBRPZ_POLICY_BITS 4
/*
* Special policies that appear as targets of CNAMEs
* NXDOMAIN is signaled by a CNAME with a "." target.
* NODATA is signaled by a CNAME with a "*." target.
*/
#define LIBRPZ_RPZ_PREFIX "rpz-"
#define LIBRPZ_RPZ_PASSTHRU LIBRPZ_RPZ_PREFIX"passthru"
#define LIBRPZ_RPZ_DROP LIBRPZ_RPZ_PREFIX"drop"
#define LIBRPZ_RPZ_TCP_ONLY LIBRPZ_RPZ_PREFIX"tcp-only"
typedef uint16_t librpz_dznum_t; /* dnsrpzd zone # in [0,DZNUM_MAX] */
typedef uint8_t librpz_cznum_t; /* client zone # in [0,CZNUM_MAX] */
/*
* CIDR block
*/
typedef struct librpz_prefix {
union {
struct in_addr in;
struct in6_addr in6;
} addr;
uint8_t family;
uint8_t len;
} librpz_prefix_t;
/*
* A domain
*/
typedef uint8_t librpz_dsize_t;
typedef struct librpz_domain {
librpz_dsize_t size; /* of only .d */
uint8_t d[0]; /* variable length wire format */
} librpz_domain_t;
/*
* A maximal domain buffer
*/
typedef struct librpz_domain_buf {
librpz_dsize_t size;
uint8_t d[NS_MAXCDNAME];
} librpz_domain_buf_t;
/*
* A resource record without the owner name.
* C compilers say that sizeof(librpz_rr_t)=12 instead of 10.
*/
typedef struct {
uint16_t type; /* network byte order */
uint16_t class; /* network byte order */
uint32_t ttl; /* network byte order */
uint16_t rdlength; /* network byte order */
uint8_t rdata[0]; /* variable length */
} librpz_rr_t;
/*
* The database file might be mapped with different starting addresses
* by concurrent clients (resolvers), and so all pointers are offsets.
*/
typedef uint32_t librpz_idx_t;
#define LIBRPZ_IDX_NULL 0
#define LIBRPZ_IDX_MIN 1
#define LIBRPZ_IDX_BAD ((librpz_idx_t)-1)
/**
* Partial decoded results of a set of RPZ queries for a single DNS response
* or iteration through the mapped file.
*/
typedef int16_t librpz_result_id_t;
typedef struct librpz_result {
librpz_idx_t next_rr;
librpz_result_id_t hit_id; /* trigger ID from resolver */
librpz_policy_t zpolicy; /* policy from zone */
librpz_policy_t policy; /* adjusted by client configuration */
librpz_dznum_t dznum; /* dnsrpzd zone number */
librpz_cznum_t cznum; /* librpz client zone number */
librpz_trig_t trig:LIBRPZ_TRIG_SIZE;
bool log:1; /* log rewrite given librpz_log_level */
} librpz_result_t;
/**
* librpz trace or log levels.
*/
typedef enum {
LIBRPZ_LOG_FATAL =0, /* always print fatal errors */
LIBRPZ_LOG_ERROR =1, /* errors have this level */
LIBRPZ_LOG_TRACE1 =2, /* big events such as dnsrpzd starts */
LIBRPZ_LOG_TRACE2 =3, /* smaller dnsrpzd zone transfers */
LIBRPZ_LOG_TRACE3 =4, /* librpz hits */
LIBRPZ_LOG_TRACE4 =5, /* librpz lookups */
LIBRPZ_LOG_INVALID =999,
} librpz_log_level_t;
typedef librpz_log_level_t (librpz_log_level_val_t)(librpz_log_level_t level);
LIBDEF_F(log_level_val)
/**
* Logging function that can be supplied by the resolver.
* @param level is one of librpz_log_level_t
* @param ctx is for use by the resolver's logging system.
* NULL mean a context-free message.
*/
typedef void(librpz_log_fnc_t)(librpz_log_level_t level, void *ctx,
const char *buf);
/**
* Point librpz logging functions to the resolver's choice.
*/
typedef void (librpz_set_log_t)(librpz_log_fnc_t *new_log, const char *prog_nm);
LIBDEF_F(set_log)
/**
* librpz error messages are put in these buffers.
* Use a structure instead of naked char* to let the compiler check the length.
* A function defined with "foo(char buf[120])" can be called with
* "char sbuf[2]; foo(sbuf)" and suffer a buffer overrun.
*/
typedef struct {
char c[120];
} librpz_emsg_t;
#ifdef LIBRPZ_HAVE_ATTR
#define LIBRPZ_UNUSED __attribute__((unused))
#define LIBRPZ_PF(f,l) __attribute__((format(printf,f,l)))
#define LIBRPZ_NORET __attribute__((__noreturn__))
#else
#define LIBRPZ_UNUSED
#define LIBRPZ_PF(f,l)
#define LIBRPZ_NORET
#endif
#ifdef HAVE_BUILTIN_EXPECT
#define LIBRPZ_LIKELY(c) __builtin_expect(!!(c), 1)
#define LIBRPZ_UNLIKELY(c) __builtin_expect(!!(c), 0)
#else
#define LIBRPZ_LIKELY(c) (c)
#define LIBRPZ_UNLIKELY(c) (c)
#endif
typedef bool (librpz_parse_log_opt_t)(librpz_emsg_t *emsg, const char *arg);
LIBDEF_F(parse_log_opt)
typedef void (librpz_vpemsg_t)(librpz_emsg_t *emsg,
const char *p, va_list args);
LIBDEF_F(vpemsg)
typedef void (librpz_pemsg_t)(librpz_emsg_t *emsg,
const char *p, ...) LIBRPZ_PF(2,3);
LIBDEF_F(pemsg)
typedef void (librpz_vlog_t)(librpz_log_level_t level, void *ctx,
const char *p, va_list args);
LIBDEF_F(vlog)
typedef void (librpz_log_t)(librpz_log_level_t level, void *ctx,
const char *p, ...) LIBRPZ_PF(3,4);
LIBDEF_F(log)
typedef void (librpz_fatal_t)(int ex_code,
const char *p, ...) LIBRPZ_PF(2,3);
extern void librpz_fatal(int ex_code,
const char *p, ...) LIBRPZ_PF(2,3) LIBRPZ_NORET;
typedef void (librpz_rpz_assert_t)(const char *file, unsigned line,
const char *p, ...) LIBRPZ_PF(3,4);
extern void librpz_rpz_assert(const char *file, unsigned line,
const char *p, ...) LIBRPZ_PF(3,4) LIBRPZ_NORET;
typedef void (librpz_rpz_vassert_t)(const char *file, uint line,
const char *p, va_list args);
extern void librpz_rpz_vassert(const char *file, uint line,
const char *p, va_list args) LIBRPZ_NORET;
/*
* As far as clients are concerned, all relative pointers or indexes in a
* version of the mapped file except trie node parent pointers remain valid
* forever. A client must release a version so that it can be garbage
* collected by the file system. When dnsrpzd needs to expand the file,
* it copies the old file to a new, larger file. Clients can continue
* using the old file.
*
* Versions can also appear in a single file. Old nodes and trie values
* within the file are not destroyed until all clients using the version
* that contained the old values release the version.
*
* A client is marked as using version by connecting to the daemon. It is
* marked as using all subsequent versions. A client releases all versions
* by closing the connection or a range of versions by updating is slot
* in the shared memory version table.
*
* As far as clients are concerned, there are the following possible librpz
* failures:
* - malloc() or other fatal internal librpz problems indicated by
* a failing return from a librpz function
* All operations will fail until client handle is destroyed and
* recreated with librpz_client_detach() and librpz_client_create().
* - corrupt database detected by librpz code, corrupt database detected
* by dnsrpzd, or disconnection from the daemon.
* Current operations will fail.
*
* Clients assume that the file has already been unlinked before
* the corrupt flag is set so that they do not race with the server
* over the corruption of a single file. A client that finds the
* corrupt set knows that dnsrpzd has already crashed with
* abort() and is restarting. The client can re-connect to dnsrpzd
* and retransmit its configuration, backing off as usual if anything
* goes wrong.
*
* Searches of the database by a client do not need locks against dnsrpzd or
* other clients, but a lock is used to protect changes to the connection
* by competing threads in the client. The client provides functions
* to serialize the concurrent use of any single client handle.
* Functions that do nothing are appropriate for applications that are
* not "threaded" or that do not share client handles among threads.
* Otherwise, functions must be provided to librpz_clientcreate().
* Something like the following works with pthreads:
*
* static void
* lock(void *mutex) { assert(pthread_mutex_lock(mutex) == 0); }
*
* static void
* unlock(void *mutex) { assert(pthread_mutex_unlock(mutex) == 0); }
*
* static void
* mutex_destroy(void *mutex) { assert(pthread_mutex_destroy(mutex) == 0); }
*
*
*
* At every instant, all of the data and pointers in the mapped file are valid.
* Changes to trie node or other data are always made so that it and
* all pointers in and to it remain valid for a time. Old versions are
* eventually discarded.
*
* Dnsrpzd periodically defines a new version by setting aside all changes
* made since the previous version was defined. Subsequent changes
* made (only!) by dnsrpzd will be part of the next version.
*
* To discard an old version, dnsrpzd must know that all clients have stopped
* using that version. Clients do that by using part of the mapped file
* to tell dnsrpzd the oldest version that each client is using.
* Dnsrpzd assigns each connecting client an entry in the cversions array
* in the mapped file. The client puts version numbers into that entry
* to signal to dnsrpzd which versions that can be discarded.
* Dnsrpzd is free, as far as that client is concerned, to discard all
* numerically smaller versions. A client can disclaim all versions with
* the version number VERSIONS_ALL or 0.
*
* The race between a client changing its entry and dnsrpzd discarding a
* version is resolved by allowing dnsrpzd to discard all versions
* smaller or equal to the client's version number. If dnsrpzd is in
* the midst of discarding or about to discard version N when the
* client asserts N, no harm is done. The client depends only on
* the consistency of version N+1.
*
* This version mechanism depends in part on not being exercised too frequently
* Version numbers are 32 bits long and dnsrpzd creates new versions
* at most once every 30 seconds.
*/
/*
* Lock functions for concurrent use of a single librpz_client_t client handle.
*/
typedef void(librpz_mutex_t)(void *mutex);
/*
* List of connections to dnsrpzd daemons.
*/
typedef struct librpz_clist librpz_clist_t;
/*
* Client's handle on dnsrpzd.
*/
typedef struct librpz_client librpz_client_t;
/**
* Create the list of connections to the dnsrpzd daemon.
* @param[out] emsg: error message
* @param lock: start exclusive access to the client handle
* @param unlock: end exclusive access to the client handle
* @param mutex_destroy: release the lock
* @param mutex: pointer to the lock for the client handle
* @param log_ctx: NULL or resolver's context log messages
*/
typedef librpz_clist_t *(librpz_clist_create_t)(librpz_emsg_t *emsg,
librpz_mutex_t *lock,
librpz_mutex_t *unlock,
librpz_mutex_t *mutex_destroy,
void *mutex, void *log_ctx);
LIBDEF_F(clist_create)
/**
* Release the list of dnsrpzd connections.
*/
typedef void (librpz_clist_detach_t)(librpz_clist_t **clistp);
LIBDEF_F(clist_detach)
/**
* Create a librpz client handle.
* @param[out] emsg: error message
* @param: list of dnsrpzd connections
* @param cstr: string of configuration settings separated by ';' or '\n'
* @param use_expired: true to not ignore expired zones
* @return client handle or NULL if the handle could not be created
*/
typedef librpz_client_t *(librpz_client_create_t)(librpz_emsg_t *emsg,
librpz_clist_t *clist,
const char *cstr,
bool use_expired);
LIBDEF_F(client_create)
/**
* Start (if necessary) dnsrpzd and connect to it.
* @param[out] emsg: error message
* @param client handle
* @param optional: true if it is ok if starting the daemon is not allowed
*/
typedef bool (librpz_connect_t)(librpz_emsg_t *emsg, librpz_client_t *client,
bool optional);
LIBDEF_F(connect)
/**
* Start to destroy a librpz client handle.
* It will not be destroyed until the last set of RPZ queries represented
* by a librpz_rsp_t ends.
* @param client handle to be released
* @return false on error
*/
typedef void (librpz_client_detach_t)(librpz_client_t **clientp);
LIBDEF_F(client_detach)
/**
* State for a set of RPZ queries for a single DNS response
* or for listing the database.
*/
typedef struct librpz_rsp librpz_rsp_t;
/**
* Start a set of RPZ queries for a single DNS response.
* @param[out] emsg: error message for false return or *rspp=NULL
* @param[out] rspp created context or NULL
* @param[out] min_ns_dotsp: NULL or pointer to configured MIN-NS-DOTS value
* @param client state
* @param have_rd: RD=1 in the DNS request
* @param have_do: DO=1 in the DNS request
* @return false on error
*/
typedef bool (librpz_rsp_create_t)(librpz_emsg_t *emsg, librpz_rsp_t **rspp,
int *min_ns_dotsp, librpz_client_t *client,
bool have_rd, bool have_do);
LIBDEF_F(rsp_create)
/**
* Finish RPZ work for a DNS response.
*/
typedef void (librpz_rsp_detach_t)(librpz_rsp_t **rspp);
LIBDEF_F(rsp_detach)
/**
* Get the final, accumulated result of a set of RPZ queries.
* Yield LIBRPZ_POLICY_UNDEFINED if
* - there were no hits,
* - there was a dispositive hit, be we have not recursed and are required
* to recurse so that evil DNS authorities will not know we are using RPZ
* - we have a hit and have recursed, but later data such as NSIP could
* override
* @param[out] emsg
* @param[out] result describes the hit
* or result->policy=LIBRPZ_POLICY_UNDEFINED without a hit
* @param[out] result: current policy rewrite values
* @param recursed: recursion has now been done even if it was not done
* when the hit was found
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_rsp_result_t)(librpz_emsg_t *emsg, librpz_result_t *result,
bool recursed, const librpz_rsp_t *rsp);
LIBDEF_F(rsp_result)
/**
* Might looking for a trigger be worthwhile?
* @param trig: look for this type of trigger
* @param ipv6: true if trig is LIBRPZ_TRIG_CLIENT_IP, LIBRPZ_TRIG_IP,
* or LIBRPZ_TRIG_NSIP and the IP address is IPv6
* @return: true if looking could be worthwhile
*/
typedef bool (librpz_have_trig_t)(librpz_trig_t trig, bool ipv6,
const librpz_rsp_t *rsp);
LIBDEF_F(have_trig)
/**
* Might looking for NSDNAME and NSIP triggers be worthwhile?
* @return: true if looking could be worthwhile
*/
typedef bool (librpz_have_ns_trig_t)(const librpz_rsp_t *rsp);
LIBDEF_F(have_ns_trig)
/**
* Convert the found client IP trie key to a CIDR block
* @param[out] emsg
* @param[out] prefix trigger
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_rsp_clientip_prefix_t)(librpz_emsg_t *emsg,
librpz_prefix_t *prefix,
librpz_rsp_t *rsp);
LIBDEF_F(rsp_clientip_prefix)
/**
* Compute the owner name of the found or result trie key, usually to log it.
* An IP address key might be returned as 8.0.0.0.127.rpz-client-ip.
* example.com. might be a qname trigger. example.com.rpz-nsdname. could
* be an NSDNAME trigger.
* @param[out] emsg
* @param[out] owner domain
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_rsp_domain_t)(librpz_emsg_t *emsg,
librpz_domain_buf_t *owner,
librpz_rsp_t *rsp);
LIBDEF_F(rsp_domain)
/**
* Get the next RR of the LIBRPZ_POLICY_RECORD result after an initial use of
* librpz_rsp_result() or librpz_itr_node() or after a previous use of
* librpz_rsp_rr(). The RR is in uncompressed wire format including type,
* class, ttl and length in network byte order.
* @param[out] emsg
* @param[out] typep: optional host byte order record type or ns_t_invalid (0)
* @param[out] classp: class such as ns_c_in
* @param[out] ttlp: TTL
* @param[out] rrp: optional malloc() buffer containing the next RR or
* NULL after the last RR
* @param[out] result: current policy rewrite values
* @param qname: used construct a wildcard CNAME
* @param qname_size
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_rsp_rr_t)(librpz_emsg_t *emsg, uint16_t *typep,
uint16_t *classp, uint32_t *ttlp,
librpz_rr_t **rrp, librpz_result_t *result,
const uint8_t *qname, size_t qname_size,
librpz_rsp_t *rsp);
LIBDEF_F(rsp_rr)
/**
* Get the next RR of the LIBRPZ_POLICY_RECORD result.
* @param[out] emsg
* @param[out] ttlp: TTL
* @param[out] rrp: malloc() buffer with SOA RR without owner name
* @param[out] result: current policy rewrite values
* @param[out] origin: SOA owner name
* @param[out] origin_size
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_rsp_soa_t)(librpz_emsg_t *emsg, uint32_t *ttlp,
librpz_rr_t **rrp, librpz_domain_buf_t *origin,
librpz_result_t *result, librpz_rsp_t *rsp);
LIBDEF_F(rsp_soa)
/**
* Get the SOA serial number for a policy zone to compare with a known value
* to check whether a zone transfer is complete.
*/
typedef bool (librpz_soa_serial_t)(librpz_emsg_t *emsg, uint32_t *serialp,
const char *domain_nm, librpz_rsp_t *rsp);
LIBDEF_F(soa_serial)
/**
* Save the current policy checking state.
* @param[out] emsg
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_rsp_push_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
LIBDEF_F(rsp_push)
#define LIBRPZ_RSP_STACK_DEPTH 3
/**
* Restore the previous policy checking state.
* @param[out] emsg
* @param[out] result: NULL or restored policy rewrite values
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_rsp_pop_t)(librpz_emsg_t *emsg, librpz_result_t *result,
librpz_rsp_t *rsp);
LIBDEF_F(rsp_pop)
/**
* Discard the most recently save policy checking state.
* @param[out] emsg
* @param[out] result: NULL or restored policy rewrite values
* @return false on error
*/
typedef bool (librpz_rsp_pop_discard_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
LIBDEF_F(rsp_pop_discard)
/**
* Disable a zone.
* @param[out] emsg
* @param znum
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_rsp_forget_zone_t)(librpz_emsg_t *emsg,
librpz_cznum_t znum, librpz_rsp_t *rsp);
LIBDEF_F(rsp_forget_zone)
/**
* Apply RPZ to an IP address.
* @param[out] emsg
* @param addr: address to check
* @param ipv6: true for 16 byte IPv6 instead of 4 byte IPv4
* @param trig LIBRPZ_TRIG_CLIENT_IP, LIBRPZ_TRIG_IP, or LIBRPZ_TRIG_NSIP
* @param hit_id: caller chosen
* @param recursed: recursion has been done
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_ck_ip_t)(librpz_emsg_t *emsg,
const void *addr, uint family,
librpz_trig_t trig, librpz_result_id_t hit_id,
bool recursed, librpz_rsp_t *rsp);
LIBDEF_F(ck_ip)
/**
* Apply RPZ to a wire-format domain.
* @param[out] emsg
* @param domain in wire format
* @param domain_size
* @param trig LIBRPZ_TRIG_QNAME or LIBRPZ_TRIG_NSDNAME
* @param hit_id: caller chosen
* @param recursed: recursion has been done
* @param[in,out] rsp state from librpz_itr_start()
* @return false on error
*/
typedef bool (librpz_ck_domain_t)(librpz_emsg_t *emsg,
const uint8_t *domain, size_t domain_size,
librpz_trig_t trig, librpz_result_id_t hit_id,
bool recursed, librpz_rsp_t *rsp);
LIBDEF_F(ck_domain)
/**
* Ask dnsrpzd to refresh a zone.
* @param[out] emsg error message
* @param librpz_domain_t domain to refresh
* @param client context
* @return false after error
*/
typedef bool (librpz_zone_refresh_t)(librpz_emsg_t *emsg, const char *domain,
librpz_rsp_t *rsp);
LIBDEF_F(zone_refresh)
/**
* Get a string describing the database
* @param license: include the license
* @param cfiles: include the configuration file names
* @param listens: include the local notify IP addresses
* @param[out] emsg error message if the result is null
* @param client context
* @return malloc'ed string or NULL after error
*/
typedef char *(librpz_db_info_t)(librpz_emsg_t *emsg,
bool license, bool cfiles, bool listens,
librpz_rsp_t *rsp);
LIBDEF_F(db_info)
/**
* Start a context for listing the nodes and/or zones in the mapped file
* @param[out] emsg: error message for false return or *rspp=NULL
* @param[out[ rspp created context or NULL
* @param client context
* @return false after error
*/
typedef bool (librpz_itr_start_t)(librpz_emsg_t *emsg, librpz_rsp_t **rspp,
librpz_client_t *client);
LIBDEF_F(itr_start)
/**
* Get mapped file memory allocation statistics.
* @param[out] emsg: error message
* @param rsp state from librpz_itr_start()
* @return malloc'ed string or NULL after error
*/
typedef char *(librpz_mf_stats_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
LIBDEF_F(mf_stats)
/**
* Get versions currently used by clients.
* @param[out] emsg: error message
* @param[in,out] rsp: state from librpz_itr_start()
* @return malloc'ed string or NULL after error
*/
typedef char *(librpz_vers_stats_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
LIBDEF_F(vers_stats)
/**
* Allocate a string describing the next zone or "" after the last zone.
* @param[out] emsg
* @param all_zones to list all instead of only requested zones
* @param[in,out] rsp state from librpz_rsp_start()
* @return malloc'ed string or NULL after error
*/
typedef char *(librpz_itr_zone_t)(librpz_emsg_t *emsg, bool all_zones,
librpz_rsp_t *rsp);
LIBDEF_F(itr_zone)
/**
* Describe the next trie node while dumping the database.
* @param[out] emsg
* @param[out] result describes node
* or result->policy=LIBRPZ_POLICY_UNDEFINED after the last node.
* @param all_zones to list all instead of only requested zones
* @param[in,out] rsp state from librpz_itr_start()
* @return: false on error
*/
typedef bool (librpz_itr_node_t)(librpz_emsg_t *emsg, librpz_result_t *result,
bool all_zones, librpz_rsp_t *rsp);
LIBDEF_F(itr_node)
/**
* RPZ policy to string with a backup buffer of POLICY2STR_SIZE size
*/
typedef const char *(librpz_policy2str_t)(librpz_policy_t policy,
char *buf, size_t buf_size);
#define POLICY2STR_SIZE sizeof("policy xxxxxx")
LIBDEF_F(policy2str)
/**
* Trigger type to string.
*/
typedef const char *(librpz_trig2str_t)(librpz_trig_t trig);
LIBDEF_F(trig2str)
/**
* Convert a number of seconds to a zone file duration string
*/
typedef const char *(librpz_secs2str_t)(time_t secs,
char *buf, size_t buf_size);
#define SECS2STR_SIZE sizeof("1234567w7d24h59m59s")
LIBDEF_F(secs2str)
/**
* Parse a duration with 's', 'm', 'h', 'd', and 'w' units.
*/
typedef bool (librpz_str2secs_t)(librpz_emsg_t *emsg, time_t *val,
const char *str0);
LIBDEF_F(str2secs)
/**
* Translate selected rtypes to strings
*/
typedef const char *(librpz_rtype2str_t)(uint type, char *buf, size_t buf_size);
#define RTYPE2STR_SIZE sizeof("type xxxxx")
LIBDEF_F(rtype2str)
/**
* Local version of ns_name_ntop() for portability.
*/
typedef int (librpz_domain_ntop_t)(const u_char *src, char *dst, size_t dstsiz);
LIBDEF_F(domain_ntop)
/**
* Local version of ns_name_pton().
*/
typedef int (librpz_domain_pton2_t)(const char *src, u_char *dst, size_t dstsiz,
size_t *dstlen, bool lower);
LIBDEF_F(domain_pton2)
typedef union socku socku_t;
typedef socku_t *(librpz_mk_inet_su_t)(socku_t *su, const struct in_addr *addrp,
in_port_t port);
LIBDEF_F(mk_inet_su)
typedef socku_t *(librpz_mk_inet6_su_t)(socku_t *su, const
struct in6_addr *addrp,
uint32_t scope_id, in_port_t port);
LIBDEF_F(mk_inet6_su)
typedef bool (librpz_str2su_t)(socku_t *sup, const char *str);
LIBDEF_F(str2su)
typedef char *(librpz_su2str_t)(char *str, size_t str_len, const socku_t *su);
LIBDEF_F(su2str)
#define SU2STR_SIZE (INET6_ADDRSTRLEN+1+6+1)
/**
* default path to dnsrpzd
*/
const char *librpz_dnsrpzd_path;
#undef LIBDEF
/*
* This is the dlopen() interface to librpz.
*/
typedef const struct {
const char *dnsrpzd_path;
const char *version;
librpz_parse_log_opt_t *parse_log_opt;
librpz_log_level_val_t *log_level_val;
librpz_set_log_t *set_log;
librpz_vpemsg_t *vpemsg;
librpz_pemsg_t *pemsg;
librpz_vlog_t *vlog;
librpz_log_t *log;
librpz_fatal_t *fatal LIBRPZ_NORET;
librpz_rpz_assert_t *rpz_assert LIBRPZ_NORET;
librpz_rpz_vassert_t *rpz_vassert LIBRPZ_NORET;
librpz_clist_create_t *clist_create;
librpz_clist_detach_t *clist_detach;
librpz_client_create_t *client_create;
librpz_connect_t *connect;
librpz_client_detach_t *client_detach;
librpz_rsp_create_t *rsp_create;
librpz_rsp_detach_t *rsp_detach;
librpz_rsp_result_t *rsp_result;
librpz_have_trig_t *have_trig;
librpz_have_ns_trig_t *have_ns_trig;
librpz_rsp_clientip_prefix_t *rsp_clientip_prefix;
librpz_rsp_domain_t *rsp_domain;
librpz_rsp_rr_t *rsp_rr;
librpz_rsp_soa_t *rsp_soa;
librpz_soa_serial_t *soa_serial;
librpz_rsp_push_t *rsp_push;
librpz_rsp_pop_t *rsp_pop;
librpz_rsp_pop_discard_t *rsp_pop_discard;
librpz_rsp_forget_zone_t *rsp_forget_zone;
librpz_ck_ip_t *ck_ip;
librpz_ck_domain_t *ck_domain;
librpz_zone_refresh_t *zone_refresh;
librpz_db_info_t *db_info;
librpz_itr_start_t *itr_start;
librpz_mf_stats_t *mf_stats;
librpz_vers_stats_t *vers_stats;
librpz_itr_zone_t *itr_zone;
librpz_itr_node_t *itr_node;
librpz_policy2str_t *policy2str;
librpz_trig2str_t *trig2str;
librpz_secs2str_t *secs2str;
librpz_str2secs_t *str2secs;
librpz_rtype2str_t *rtype2str;
librpz_domain_ntop_t *domain_ntop;
librpz_domain_pton2_t *domain_pton2;
librpz_mk_inet_su_t *mk_inet_su;
librpz_mk_inet6_su_t *mk_inet6_su;
librpz_str2su_t *str2su;
librpz_su2str_t *su2str;
} librpz_0_t;
extern librpz_0_t librpz_def_0;
/*
* Future versions can be upward compatible by defining LIBRPZ_DEF as
* librpz_X_t.
*/
#define LIBRPZ_DEF librpz_def_0
#define LIBRPZ_DEF_STR "librpz_def_0"
typedef librpz_0_t librpz_t;
extern librpz_t *librpz;
#if LIBRPZ_LIB_OPEN == 2
#include <dlfcn.h>
/**
* link-load librpz
* @param[out] emsg: error message
* @param[in,out] dl_handle: NULL or pointer to new dlopen handle
* @param[in] path: librpz.so path
* @return address of interface structure or NULL on failure
*/
static inline librpz_t *
librpz_lib_open(librpz_emsg_t *emsg, void **dl_handle, const char *path)
{
void *handle;
librpz_t *new_librpz;
emsg->c[0] = '\0';
/*
* Close a previously opened handle on librpz.so.
*/
if (dl_handle != NULL && *dl_handle != NULL) {
if (dlclose(*dl_handle) != 0) {
snprintf(emsg->c, sizeof(librpz_emsg_t),
"dlopen(NULL): %s", dlerror());
return (NULL);
}
*dl_handle = NULL;
}
/*
* First try the main executable of the process in case it was
* linked to librpz.
* Do not worry if we cannot search the main executable of the process.
*/
handle = dlopen(NULL, RTLD_NOW | RTLD_LOCAL);
if (handle != NULL) {
new_librpz = dlsym(handle, LIBRPZ_DEF_STR);
if (new_librpz != NULL) {
if (dl_handle != NULL)
*dl_handle = handle;
return (new_librpz);
}
if (dlclose(handle) != 0) {
snprintf(emsg->c, sizeof(librpz_emsg_t),
"dlsym(NULL, "LIBRPZ_DEF_STR"): %s",
dlerror());
return (NULL);
}
}
if (path == NULL || path[0] == '\0') {
snprintf(emsg->c, sizeof(librpz_emsg_t),
"librpz not linked and no dlopen() path provided");
return (NULL);
}
handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
if (handle == NULL) {
snprintf(emsg->c, sizeof(librpz_emsg_t), "dlopen(%s): %s",
path, dlerror());
return (NULL);
}
new_librpz = dlsym(handle, LIBRPZ_DEF_STR);
if (new_librpz != NULL) {
if (dl_handle != NULL)
*dl_handle = handle;
return (new_librpz);
}
snprintf(emsg->c, sizeof(librpz_emsg_t),
"dlsym(%s, "LIBRPZ_DEF_STR"): %s",
path, dlerror());
dlclose(handle);
return (NULL);
}
#elif defined(LIBRPZ_LIB_OPEN)
/*
* Statically link to the librpz.so DSO on systems without dlopen()
*/
static inline librpz_t *
librpz_lib_open(librpz_emsg_t *emsg, void **dl_handle, const char *path)
{
(void)(path);
if (dl_handle != NULL)
*dl_handle = NULL;
#if LIBRPZ_LIB_OPEN == 1
emsg->c[0] = '\0';
return (&LIBRPZ_DEF);
#else
snprintf(emsg->c, sizeof(librpz_emsg_t),
"librpz not available via ./configure");
return (NULL);
#endif /* LIBRPZ_LIB_OPEN */
}
#endif /* LIBRPZ_LIB_OPEN */
#endif /* LIBRPZ_H */

View file

@ -6,8 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* $Id$ */
#ifndef DNS_RPZ_H
#define DNS_RPZ_H 1
@ -187,6 +185,9 @@ typedef struct dns_rpz_popt dns_rpz_popt_t;
struct dns_rpz_popt {
dns_rpz_zbits_t no_rd_ok;
dns_rpz_zbits_t no_log;
dns_rpz_zbits_t nsip_on;
dns_rpz_zbits_t nsdname_on;
isc_boolean_t dnsrps_enabled;
isc_boolean_t break_dnssec;
isc_boolean_t qname_wait_recurse;
isc_boolean_t nsip_wait_recurse;
@ -203,8 +204,9 @@ struct dns_rpz_zones {
dns_rpz_triggers_t triggers[DNS_RPZ_MAX_ZONES];
/*
* RPZ policy version number (initially 0, increases whenever
* the server is reconfigured with new zones or policy)
* RPZ policy version number.
* It is initially 0 and it increases whenever the server is
* reconfigured with new zones or policy.
*/
int rpz_ver;
@ -250,6 +252,13 @@ struct dns_rpz_zones {
dns_rpz_cidr_node_t *cidr;
dns_rbt_t *rbt;
/*
* DNSRPZ librpz configuration string and handle on librpz connection
*/
char *rps_cstr;
size_t rps_cstr_size;
struct librpz_client *rps_client;
};
@ -319,6 +328,11 @@ typedef struct {
dns_rpz_popt_t popt;
int rpz_ver;
/*
* Shim db between BIND and DNRPS librpz.
*/
dns_db_t *rpsdb;
/*
* p_name: current policy owner name
* r_name: recursing for this name to possible policy triggers
@ -360,7 +374,8 @@ dns_rpz_decode_cname(dns_rpz_zone_t *rpz, dns_rdataset_t *rdataset,
dns_name_t *selfname);
isc_result_t
dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, isc_mem_t *mctx,
dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, char *rps_cstr,
size_t rps_cstr_size, isc_mem_t *mctx,
isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr);
isc_result_t

View file

@ -23,6 +23,7 @@
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/dnsrps.h>
#include <dns/events.h>
#include <dns/fixedname.h>
#include <dns/log.h>
@ -397,11 +398,10 @@ fix_qname_skip_recurse(dns_rpz_zones_t *rpzs) {
* qname_wait_recurse and qname_skip_recurse are used to
* implement the "qname-wait-recurse" config option.
*
* By default, "qname-wait-recurse" is yes, so no
* processing happens without recursion. In this case,
* qname_wait_recurse is true, and qname_skip_recurse
* (a bit field indicating which policy zones can be
* processed without recursion) is set to all 0's by
* When "qname-wait-recurse" is yes, no processing happens without
* recursion. In this case, qname_wait_recurse is true, and
* qname_skip_recurse (a bit field indicating which policy zones
* can be processed without recursion) is set to all 0's by
* fix_qname_skip_recurse().
*
* When "qname-wait-recurse" is no, qname_skip_recurse may be
@ -681,6 +681,12 @@ badname(int level, const dns_name_t *name, const char *str1, const char *str2) {
* Convert an IP address from radix tree binary (host byte order) to
* to its canonical response policy domain name without the origin of the
* policy zone.
*
* Generate a name for an IPv6 address that fits RFC 5952, except that our
* reversed format requires that when the length of the consecutive 16-bit
* 0 fields are equal (e.g., 1.0.0.1.0.0.db8.2001 corresponding to
* 2001:db8:0:0:1:0:0:1), we shorted the last instead of the first
* (e.g., 1.0.0.1.zz.db8.2001 corresponding to 2001:db8::1:0:0:1).
*/
static isc_result_t
ip2name(const dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t tgt_prefix,
@ -693,7 +699,7 @@ ip2name(const dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t tgt_prefix,
char str[1+8+1+INET6_ADDRSTRLEN+1];
isc_buffer_t buffer;
isc_result_t result;
isc_boolean_t zeros;
int best_first, best_len, cur_first, cur_len;
int i, n, len;
if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) {
@ -703,43 +709,53 @@ ip2name(const dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t tgt_prefix,
(tgt_ip->w[3]>>8) & 0xff,
(tgt_ip->w[3]>>16) & 0xff,
(tgt_ip->w[3]>>24) & 0xff);
if (len < 0 || len > (int)sizeof(str))
if (len < 0 || len > (int)sizeof(str)) {
return (ISC_R_FAILURE);
}
} else {
len = snprintf(str, sizeof(str), "%d", tgt_prefix);
if (len == -1) {
return (ISC_R_FAILURE);
}
for (i = 0; i < DNS_RPZ_CIDR_WORDS; i++) {
w[i*2+1] = ((tgt_ip->w[DNS_RPZ_CIDR_WORDS-1-i] >> 16)
& 0xffff);
w[i*2] = tgt_ip->w[DNS_RPZ_CIDR_WORDS-1-i] & 0xffff;
}
zeros = ISC_FALSE;
len = snprintf(str, sizeof(str), "%d", tgt_prefix);
if (len == -1)
return (ISC_R_FAILURE);
i = 0;
while (i < DNS_RPZ_CIDR_WORDS * 2) {
if (w[i] != 0 || zeros ||
i >= DNS_RPZ_CIDR_WORDS * 2 - 1 ||
w[i+1] != 0) {
INSIST((size_t)len <= sizeof(str));
n = snprintf(&str[len], sizeof(str) - len,
".%x", w[i++]);
if (n < 0)
return (ISC_R_FAILURE);
len += n;
/*
* Find the start and length of the first longest sequence
* of zeros in the address.
*/
best_first = -1;
best_len = 0;
cur_first = -1;
cur_len = 0;
for (n = 0; n <=7; ++n) {
if (w[n] != 0) {
cur_len = 0;
cur_first = -1;
} else {
zeros = ISC_TRUE;
INSIST((size_t)len <= sizeof(str));
n = snprintf(&str[len], sizeof(str) - len,
".zz");
if (n < 0)
return (ISC_R_FAILURE);
len += n;
i += 2;
while (i < DNS_RPZ_CIDR_WORDS * 2 && w[i] == 0)
++i;
++cur_len;
if (cur_first < 0) {
cur_first = n;
} else if (cur_len >= best_len) {
best_first = cur_first;
best_len = cur_len;
}
}
}
for (n = 0; n <= 7; ++n) {
INSIST(len < (int)sizeof(str));
if (n == best_first) {
len += snprintf(str + len, sizeof(str) - len,
".zz");
n += best_len - 1;
} else {
len += snprintf(str + len, sizeof(str) - len,
".%x", w[n]);
}
if (len >= (int)sizeof(str))
return (ISC_R_FAILURE);
}
}
@ -750,26 +766,31 @@ ip2name(const dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t tgt_prefix,
}
/*
* Determine the type a of a name in a response policy zone.
* Determine the type of a name in a response policy zone.
*/
static dns_rpz_type_t
type_from_name(dns_rpz_zone_t *rpz, const dns_name_t *name) {
if (dns_name_issubdomain(name, &rpz->ip))
type_from_name(const dns_rpz_zones_t *rpzs,
dns_rpz_zone_t *rpz, const dns_name_t *name)
{
if (dns_name_issubdomain(name, &rpz->ip)) {
return (DNS_RPZ_TYPE_IP);
}
if (dns_name_issubdomain(name, &rpz->client_ip))
if (dns_name_issubdomain(name, &rpz->client_ip)) {
return (DNS_RPZ_TYPE_CLIENT_IP);
}
#ifdef ENABLE_RPZ_NSIP
if (dns_name_issubdomain(name, &rpz->nsip))
if ((rpzs->p.nsip_on & DNS_RPZ_ZBIT(rpz->num)) != 0 &&
dns_name_issubdomain(name, &rpz->nsip))
{
return (DNS_RPZ_TYPE_NSIP);
#endif
}
#ifdef ENABLE_RPZ_NSDNAME
if (dns_name_issubdomain(name, &rpz->nsdname))
if ((rpzs->p.nsdname_on & DNS_RPZ_ZBIT(rpz->num)) != 0 &&
dns_name_issubdomain(name, &rpz->nsdname))
{
return (DNS_RPZ_TYPE_NSDNAME);
#endif
}
return (DNS_RPZ_TYPE_QNAME);
}
@ -787,7 +808,7 @@ name2ipkey(int log_level,
dns_rpz_addr_zbits_t *new_set)
{
dns_rpz_zone_t *rpz;
char ip_str[DNS_NAME_FORMATSIZE];
char ip_str[DNS_NAME_FORMATSIZE], ip2_str[DNS_NAME_FORMATSIZE];
dns_offsets_t ip_name_offsets;
dns_fixedname_t ip_name2f;
dns_name_t ip_name, *ip_name2;
@ -830,7 +851,6 @@ name2ipkey(int log_level,
"; invalid leading prefix length", "");
return (ISC_R_FAILURE);
}
*cp2 = '\0';
if (prefix_num < 1U || prefix_num > 128U) {
badname(log_level, src_name,
"; invalid prefix length of ", prefix_str);
@ -926,21 +946,27 @@ name2ipkey(int log_level,
}
/*
* XXXMUKS: Should the following check be enabled in a
* production build? It can be expensive for large IP zones
* from 3rd parties.
* Complain about bad names but be generous and accept them.
*/
/*
* Convert the address back to a canonical domain name
* to ensure that the original name is in canonical form.
*/
dns_fixedname_init(&ip_name2f);
ip_name2 = dns_fixedname_name(&ip_name2f);
result = ip2name(tgt_ip, (dns_rpz_prefix_t)prefix_num, NULL, ip_name2);
if (result != ISC_R_SUCCESS || !dns_name_equal(&ip_name, ip_name2)) {
badname(log_level, src_name, "; not canonical", "");
return (ISC_R_FAILURE);
if (log_level < DNS_RPZ_DEBUG_QUIET &&
isc_log_wouldlog(dns_lctx, log_level)) {
/*
* Convert the address back to a canonical domain name
* to ensure that the original name is in canonical form.
*/
dns_fixedname_init(&ip_name2f);
ip_name2 = dns_fixedname_name(&ip_name2f);
result = ip2name(tgt_ip, (dns_rpz_prefix_t)prefix_num,
NULL, ip_name2);
if (result != ISC_R_SUCCESS ||
!dns_name_equal(&ip_name, ip_name2)) {
dns_name_format(ip_name2, ip2_str, sizeof(ip2_str));
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, log_level,
"rpz IP address \"%s\""
" is not the canonical \"%s\"",
ip_str, ip2_str);
}
}
return (ISC_R_SUCCESS);
@ -1396,10 +1422,11 @@ rpz_node_deleter(void *nm_data, void *mctx) {
}
/*
* Get ready for a new set of policy zones.
* Get ready for a new set of policy zones for a view.
*/
isc_result_t
dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, isc_mem_t *mctx,
dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, char *rps_cstr,
size_t rps_cstr_size, isc_mem_t *mctx,
isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr)
{
dns_rpz_zones_t *zones;
@ -1424,7 +1451,20 @@ dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, isc_mem_t *mctx,
if (result != ISC_R_SUCCESS)
goto cleanup_refcount;
result = dns_rbt_create(mctx, rpz_node_deleter, mctx, &zones->rbt);
zones->rps_cstr = rps_cstr;
zones->rps_cstr_size = rps_cstr_size;
#ifdef USE_DNSRPS
if (rps_cstr != NULL) {
result = dns_dnsrps_view_init(zones, rps_cstr);
}
#else
INSIST(!zones->p.dnsrps_enabled);
#endif
if (result == ISC_R_SUCCESS && !zones->p.dnsrps_enabled) {
result = dns_rbt_create(mctx, rpz_node_deleter,
mctx, &zones->rbt);
}
if (result != ISC_R_SUCCESS)
goto cleanup_rbt;
@ -2074,26 +2114,38 @@ dns_rpz_detach_rpzs(dns_rpz_zones_t **rpzsp) {
*rpzsp = NULL;
isc_refcount_decrement(&rpzs->refs, &refs);
if (refs != 0) {
return;
}
/*
* Forget the last of view's rpz machinery after the last reference.
*/
if (refs == 0) {
for (rpz_num = 0; rpz_num < DNS_RPZ_MAX_ZONES; ++rpz_num) {
rpz = rpzs->zones[rpz_num];
rpzs->zones[rpz_num] = NULL;
if (rpz != NULL)
rpz_detach(&rpz, rpzs);
for (rpz_num = 0; rpz_num < DNS_RPZ_MAX_ZONES; ++rpz_num) {
rpz = rpzs->zones[rpz_num];
rpzs->zones[rpz_num] = NULL;
if (rpz != NULL) {
rpz_detach(&rpz, rpzs);
}
cidr_free(rpzs);
dns_rbt_destroy(&rpzs->rbt);
DESTROYLOCK(&rpzs->maint_lock);
isc_rwlock_destroy(&rpzs->search_lock);
isc_refcount_destroy(&rpzs->refs);
isc_task_destroy(&rpzs->updater);
isc_mem_putanddetach(&rpzs->mctx, rpzs, sizeof(*rpzs));
}
if (rpzs->rps_cstr_size != 0) {
#ifdef USE_DNSRPS
librpz->client_detach(&rpzs->rps_client);
#endif
isc_mem_put(rpzs->mctx, rpzs->rps_cstr,
rpzs->rps_cstr_size);
}
cidr_free(rpzs);
if (rpzs->rbt != NULL) {
dns_rbt_destroy(&rpzs->rbt);
}
DESTROYLOCK(&rpzs->maint_lock);
isc_rwlock_destroy(&rpzs->search_lock);
isc_refcount_destroy(&rpzs->refs);
isc_task_destroy(&rpzs->updater);
isc_mem_putanddetach(&rpzs->mctx, rpzs, sizeof(*rpzs));
}
/*
@ -2140,7 +2192,7 @@ dns_rpz_add(dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num,
REQUIRE(rpz != NULL);
RWLOCK(&rpzs->search_lock, isc_rwlocktype_write);
rpz_type = type_from_name(rpz, src_name);
rpz_type = type_from_name(rpzs, rpz, src_name);
switch (rpz_type) {
@ -2350,7 +2402,7 @@ dns_rpz_delete(dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num,
RWLOCK(&rpzs->search_lock, isc_rwlocktype_write);
rpz_type = type_from_name(rpz, src_name);
rpz_type = type_from_name(rpzs, rpz, src_name);
switch (rpz_type) {
case DNS_RPZ_TYPE_QNAME:

View file

@ -1419,11 +1419,15 @@ static cfg_type_t cfg_type_dnstapoutput = {
* zone <string> [ policy (given|disabled|passthru|drop|tcp-only|
* nxdomain|nodata|cname <domain> ) ]
* [ recursive-only yes|no ] [ log yes|no ]
* [ max-policy-ttl number ] [ min-update-interval number ] ;
* [ max-policy-ttl number ]
* [ nsip-enable yes|no ] [ nsdname-enable yes|no ];
* } [ recursive-only yes|no ] [ max-policy-ttl number ]
* [ min-update-interval number ]
* [ break-dnssec yes|no ] [ min-ns-dots number ]
* [ qname-wait-recurse yes|no ] ;
* [ qname-wait-recurse yes|no ]
* [ nsip-enable yes|no ] [ nsdname-enable yes|no ]
* [ dnsrps-enable yes|no ]
* [ dnsrps-options { DNSRPS configuration string } ];
*/
static void
@ -1614,6 +1618,8 @@ static cfg_tuplefielddef_t rpz_zone_fields[] = {
{ "min-update-interval", &cfg_type_uint32, 0 },
{ "policy", &cfg_type_rpz_policy, 0 },
{ "recursive-only", &cfg_type_boolean, 0 },
{ "nsip-enable", &cfg_type_boolean, 0 },
{ "nsdname-enable", &cfg_type_boolean, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_rpz_tuple = {
@ -1635,6 +1641,16 @@ static cfg_tuplefielddef_t rpz_fields[] = {
{ "nsip-wait-recurse", &cfg_type_boolean, 0 },
{ "qname-wait-recurse", &cfg_type_boolean, 0 },
{ "recursive-only", &cfg_type_boolean, 0 },
{ "nsip-enable", &cfg_type_boolean, 0 },
{ "nsdname-enable", &cfg_type_boolean, 0 },
#ifdef USE_DNSRPS
{ "dnsrps-enable", &cfg_type_boolean, 0 },
{ "dnsrps-options", &cfg_type_bracketed_text, 0 },
#else
{ "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED },
{ "dnsrps-options", &cfg_type_bracketed_text,
CFG_CLAUSEFLAG_NOTCONFIGURED },
#endif
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_rpz = {
@ -1851,6 +1867,14 @@ view_clauses[] = {
{ "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI },
{ "dns64-contact", &cfg_type_astring, 0 },
{ "dns64-server", &cfg_type_astring, 0 },
#ifdef USE_DNSRPS
{ "dnsrps-enable", &cfg_type_boolean, 0 },
{ "dnsrps-options", &cfg_type_bracketed_text, 0 },
#else
{ "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED },
{ "dnsrps-options", &cfg_type_bracketed_text,
CFG_CLAUSEFLAG_NOTCONFIGURED },
#endif
{ "dnssec-accept-expired", &cfg_type_boolean, 0 },
{ "dnssec-enable", &cfg_type_boolean, 0 },
{ "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI },

View file

@ -29,6 +29,7 @@
#include <dns/db.h>
#include <dns/dlz.h>
#include <dns/dns64.h>
#include <dns/dnsrps.h>
#include <dns/dnssec.h>
#include <dns/events.h>
#include <dns/message.h>
@ -715,6 +716,7 @@ query_reset(ns_client_t *client, isc_boolean_t everything) {
if (client->query.rpz_st != NULL) {
rpz_st_clear(client);
if (everything) {
INSIST(client->query.rpz_st->rpsdb == NULL);
isc_mem_put(client->mctx, client->query.rpz_st,
sizeof(*client->query.rpz_st));
client->query.rpz_st = NULL;
@ -1285,8 +1287,7 @@ rpz_log_fail_helper(ns_client_t *client, int level, dns_name_t *p_name,
{
char qnamebuf[DNS_NAME_FORMATSIZE];
char p_namebuf[DNS_NAME_FORMATSIZE];
const char *failed;
const char *slash;
const char *failed, *via, *slash, *str_blank;
const char *rpztypestr1;
const char *rpztypestr2;
@ -1310,13 +1311,23 @@ rpz_log_fail_helper(ns_client_t *client, int level, dns_name_t *p_name,
rpztypestr2 = "";
}
str_blank = (*str != ' ' && *str != '\0') ? " " : "";
dns_name_format(client->query.qname, qnamebuf, sizeof(qnamebuf));
dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
if (p_name != NULL) {
via = " via ";
dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
} else {
via = "";
p_namebuf[0] = '\0';
}
ns_client_log(client, NS_LOGCATEGORY_QUERY_ERRORS,
NS_LOGMODULE_QUERY, level,
"rpz %s%s%s rewrite %s via %s%s%s%s",
"rpz %s%s%s rewrite %s%s%s%s%s%s : %s",
rpztypestr1, slash, rpztypestr2,
qnamebuf, p_namebuf,
qnamebuf, via, p_namebuf, str_blank,
str, failed, isc_result_totext(result));
}
@ -2512,24 +2523,33 @@ rpz_st_clear(ns_client_t *client) {
CTRACE(ISC_LOG_DEBUG(3), "rpz_st_clear");
if (st->m.rdataset != NULL)
if (st->m.rdataset != NULL) {
query_putrdataset(client, &st->m.rdataset);
}
rpz_match_clear(st);
rpz_clean(NULL, &st->r.db, NULL, NULL);
if (st->r.ns_rdataset != NULL)
if (st->r.ns_rdataset != NULL) {
query_putrdataset(client, &st->r.ns_rdataset);
if (st->r.r_rdataset != NULL)
}
if (st->r.r_rdataset != NULL) {
query_putrdataset(client, &st->r.r_rdataset);
}
rpz_clean(&st->q.zone, &st->q.db, &st->q.node, NULL);
if (st->q.rdataset != NULL)
if (st->q.rdataset != NULL) {
query_putrdataset(client, &st->q.rdataset);
if (st->q.sigrdataset != NULL)
}
if (st->q.sigrdataset != NULL) {
query_putrdataset(client, &st->q.sigrdataset);
}
st->state = 0;
st->m.type = DNS_RPZ_TYPE_BAD;
st->m.policy = DNS_RPZ_POLICY_MISS;
if (st->rpsdb != NULL) {
dns_db_detach(&st->rpsdb);
}
}
static dns_rpz_zbits_t
@ -2544,6 +2564,19 @@ rpz_get_zbits(ns_client_t *client,
st = client->query.rpz_st;
#ifdef USE_DNSRPS
if (st->popt.dnsrps_enabled) {
if (st->rpsdb == NULL ||
librpz->have_trig(dns_dnsrps_type2trig(rpz_type),
ip_type == dns_rdatatype_aaaa,
((rpsdb_t *)st->rpsdb)->rsp))
{
return (DNS_RPZ_ALL_ZBITS);
}
return (0);
}
#endif
switch (rpz_type) {
case DNS_RPZ_TYPE_CLIENT_IP:
zbits = st->have.client_ip;
@ -2733,7 +2766,7 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
rpz_clean(NULL, dbp, &node, rdatasetp);
version = NULL;
dns_db_attach(client->view->cachedb, dbp);
result = dns_db_findext(*dbp, name, version, dns_rdatatype_ns,
result = dns_db_findext(*dbp, name, version, type,
0, client->now, &node, found,
&cm, &ci, *rdatasetp, NULL);
}
@ -2921,8 +2954,7 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
p_name, rpz_type,
" rdatasetiter", result);
CTRACE(ISC_LOG_ERROR,
"rpz_find_p: rdatasetiter_destroy "
"failed");
"rpz_find_p: rdatasetiter failed");
return (DNS_R_SERVFAIL);
}
/*
@ -3017,6 +3049,283 @@ rpz_save_p(dns_rpz_st_t *st, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
SAVE(st->m.version, version);
}
#ifdef USE_DNSRPS
/*
* Check the results of a RPZ service interface lookup.
* Stop after an error (<0) or not a hit on a disabled zone (0).
* Continue after a hit on a disabled zone (>0).
*/
static int
dnsrps_ck(librpz_emsg_t *emsg, ns_client_t *client, rpsdb_t *rpsdb,
isc_boolean_t recursed)
{
isc_region_t region;
librpz_domain_buf_t pname_buf;
if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
return (-1);
}
/*
* Forget the state from before the IP address or domain check
* if the lookup hit nothing.
*/
if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED ||
rpsdb->result.hit_id != rpsdb->hit_id ||
rpsdb->result.policy != LIBRPZ_POLICY_DISABLED)
{
if (!librpz->rsp_pop_discard(emsg, rpsdb->rsp)) {
return (-1);
}
return (0);
}
/*
* Log a hit on a disabled zone.
* Forget the zone to not try it again, and restore the pre-hit state.
*/
if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
return (-1);
}
region.base = pname_buf.d;
region.length = pname_buf.size;
dns_name_fromregion(client->query.rpz_st->p_name, &region);
rpz_log_rewrite(client, ISC_TRUE,
dns_dnsrps_2policy(rpsdb->result.zpolicy),
dns_dnsrps_trig2type(rpsdb->result.trig), NULL,
client->query.rpz_st->p_name, NULL,
rpsdb->result.cznum);
if (!librpz->rsp_forget_zone(emsg, rpsdb->result.cznum, rpsdb->rsp) ||
!librpz->rsp_pop(emsg, &rpsdb->result, rpsdb->rsp))
{
return (-1);
}
return (1);
}
/*
* Ready the shim database and rdataset for a DNSRPS hit.
*/
static isc_boolean_t
dnsrps_set_p(librpz_emsg_t *emsg, ns_client_t *client, dns_rpz_st_t *st,
dns_rdatatype_t qtype, dns_rdataset_t **p_rdatasetp,
isc_boolean_t recursed)
{
rpsdb_t *rpsdb;
librpz_domain_buf_t pname_buf;
isc_region_t region;
dns_zone_t *p_zone;
dns_db_t *p_db;
dns_dbnode_t *p_node;
dns_rpz_policy_t policy;
dns_fixedname_t foundf;
dns_name_t *found;
dns_rdatatype_t foundtype, searchtype;
isc_result_t result;
rpsdb = (rpsdb_t *)st->rpsdb;
if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
return (ISC_FALSE);
}
if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED) {
return (ISC_TRUE);
}
/*
* Give the fake or shim DNSRPS database its new origin.
*/
if (!librpz->rsp_soa(emsg, NULL, NULL, &rpsdb->origin_buf,
&rpsdb->result, rpsdb->rsp))
{
return (ISC_FALSE);
}
region.base = rpsdb->origin_buf.d;
region.length = rpsdb->origin_buf.size;
dns_name_fromregion(&rpsdb->common.origin, &region);
if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
return (ISC_FALSE);
}
region.base = pname_buf.d;
region.length = pname_buf.size;
dns_name_fromregion(st->p_name, &region);
p_zone = NULL;
p_db = NULL;
p_node = NULL;
rpz_ready(client, p_rdatasetp);
dns_db_attach(st->rpsdb, &p_db);
policy = dns_dnsrps_2policy(rpsdb->result.policy);
if (policy != DNS_RPZ_POLICY_RECORD) {
result = ISC_R_SUCCESS;
} else if (qtype == dns_rdatatype_rrsig) {
/*
* dns_find_db() refuses to look for and fail to
* find dns_rdatatype_rrsig.
*/
result = DNS_R_NXRRSET;
policy = DNS_RPZ_POLICY_NODATA;
} else {
/*
* Get the next (and so first) RR from the policy node.
* If it is a CNAME, then look for it regardless of the
* query type.
*/
if (!librpz->rsp_rr(emsg, &foundtype, NULL, NULL, NULL,
&rpsdb->result, rpsdb->qname->ndata,
rpsdb->qname->length, rpsdb->rsp))
{
return (ISC_FALSE);
}
if (foundtype == dns_rdatatype_cname) {
searchtype = dns_rdatatype_cname;
} else {
searchtype = qtype;
}
/*
* Get the DNSPRS imitation rdataset.
*/
dns_fixedname_init(&foundf);
found = dns_fixedname_name(&foundf);
result = dns_db_find(p_db, st->p_name, NULL, searchtype,
0, 0, &p_node, found, *p_rdatasetp, NULL);
if (result == ISC_R_SUCCESS) {
if (searchtype == dns_rdatatype_cname &&
qtype != dns_rdatatype_cname)
{
result = DNS_R_CNAME;
}
} else if (result == DNS_R_NXRRSET) {
policy = DNS_RPZ_POLICY_NODATA;
} else {
snprintf(emsg->c, sizeof(emsg->c), "dns_db_find(): %s",
isc_result_totext(result));
return (ISC_FALSE);
}
}
rpz_save_p(st, client->view->rpzs->zones[rpsdb->result.cznum],
dns_dnsrps_trig2type(rpsdb->result.trig), policy,
st->p_name, 0, result, &p_zone, &p_db, &p_node,
p_rdatasetp, NULL);
rpz_clean(NULL, NULL, NULL, p_rdatasetp);
return (ISC_TRUE);
}
static isc_result_t
dnsrps_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
dns_rpz_type_t rpz_type, dns_rdataset_t **p_rdatasetp)
{
dns_rpz_st_t *st;
rpsdb_t *rpsdb;
librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
isc_boolean_t recursed = ISC_FALSE;
int res;
librpz_emsg_t emsg;
isc_result_t result;
st = client->query.rpz_st;
rpsdb = (rpsdb_t *)st->rpsdb;
result = rpz_ready(client, p_rdatasetp);
if (result != ISC_R_SUCCESS) {
st->m.policy = DNS_RPZ_POLICY_ERROR;
return (result);
}
switch (rpz_type) {
case DNS_RPZ_TYPE_CLIENT_IP:
trig = LIBRPZ_TRIG_CLIENT_IP;
recursed = ISC_FALSE;
break;
case DNS_RPZ_TYPE_IP:
trig = LIBRPZ_TRIG_IP;
recursed = ISC_TRUE;
break;
case DNS_RPZ_TYPE_NSIP:
trig = LIBRPZ_TRIG_NSIP;
recursed = ISC_TRUE;
break;
default:
INSIST(0);
}
do {
if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
!librpz->ck_ip(&emsg,
netaddr->family == AF_INET
? (const void *)&netaddr->type.in
: (const void *)&netaddr->type.in6,
netaddr->family, trig, ++rpsdb->hit_id,
recursed, rpsdb->rsp) ||
(res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
{
rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
rpz_type, emsg.c, DNS_R_SERVFAIL);
st->m.policy = DNS_RPZ_POLICY_ERROR;
return (DNS_R_SERVFAIL);
}
} while (res != 0);
return (ISC_R_SUCCESS);
}
static isc_result_t
dnsrps_rewrite_name(ns_client_t *client, dns_name_t *trig_name,
isc_boolean_t recursed, dns_rpz_type_t rpz_type,
dns_rdataset_t **p_rdatasetp)
{
dns_rpz_st_t *st;
rpsdb_t *rpsdb;
librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
isc_region_t r;
int res;
librpz_emsg_t emsg;
isc_result_t result;
st = client->query.rpz_st;
rpsdb = (rpsdb_t *)st->rpsdb;
result = rpz_ready(client, p_rdatasetp);
if (result != ISC_R_SUCCESS) {
st->m.policy = DNS_RPZ_POLICY_ERROR;
return (result);
}
switch (rpz_type) {
case DNS_RPZ_TYPE_QNAME:
trig = LIBRPZ_TRIG_QNAME;
break;
case DNS_RPZ_TYPE_NSDNAME:
trig = LIBRPZ_TRIG_NSDNAME;
break;
default:
INSIST(0);
}
dns_name_toregion(trig_name, &r);
do {
if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
!librpz->ck_domain(&emsg, r.base, r.length,
trig, ++rpsdb->hit_id,
recursed, rpsdb->rsp) ||
(res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
{
rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
rpz_type, emsg.c, DNS_R_SERVFAIL);
st->m.policy = DNS_RPZ_POLICY_ERROR;
return (DNS_R_SERVFAIL);
}
} while (res != 0);
return (ISC_R_SUCCESS);
}
#endif /* USE_DNSRPS */
/*
* Check this address in every eligible policy zone.
*/
@ -3041,6 +3350,15 @@ rpz_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip");
rpzs = client->view->rpzs;
st = client->query.rpz_st;
#ifdef USE_DNSRPS
if (st->popt.dnsrps_enabled) {
return (dnsrps_rewrite_ip(client, netaddr, rpz_type,
p_rdatasetp));
}
#endif
dns_fixedname_init(&ip_namef);
ip_name = dns_fixedname_name(&ip_namef);
@ -3048,8 +3366,6 @@ rpz_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
p_db = NULL;
p_node = NULL;
rpzs = client->view->rpzs;
st = client->query.rpz_st;
while (zbits != 0) {
rpz_num = dns_rpz_find_ip(rpzs, rpz_type, zbits, netaddr,
ip_name, &prefix);
@ -3319,7 +3635,8 @@ rpz_rewrite_ip_rrsets(ns_client_t *client, dns_name_t *name,
static isc_result_t
rpz_rewrite_name(ns_client_t *client, dns_name_t *trig_name,
dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
dns_rpz_zbits_t allowed_zbits, dns_rdataset_t **rdatasetp)
dns_rpz_zbits_t allowed_zbits, isc_boolean_t recursed,
dns_rdataset_t **rdatasetp)
{
dns_rpz_zones_t *rpzs;
dns_rpz_zone_t *rpz;
@ -3335,15 +3652,27 @@ rpz_rewrite_name(ns_client_t *client, dns_name_t *trig_name,
dns_rpz_policy_t policy;
isc_result_t result;
#ifndef USE_DNSRPS
UNUSED(recursed);
#endif
CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_name");
rpzs = client->view->rpzs;
st = client->query.rpz_st;
#ifdef USE_DNSRPS
if (st->popt.dnsrps_enabled) {
return (dnsrps_rewrite_name(client, trig_name, recursed,
rpz_type, rdatasetp));
}
#endif
zbits = rpz_get_zbits(client, qtype, rpz_type);
zbits &= allowed_zbits;
if (zbits == 0)
return (ISC_R_SUCCESS);
rpzs = client->view->rpzs;
/*
* Use the summary database to find the bit mask of policy zones
* with policies for this trigger name. We do this even if there
@ -3361,8 +3690,6 @@ rpz_rewrite_name(ns_client_t *client, dns_name_t *trig_name,
p_db = NULL;
p_node = NULL;
st = client->query.rpz_st;
/*
* Check the trigger name in every policy zone that the summary data
* says has a hit for the trigger name.
@ -3513,6 +3840,15 @@ rpz_rewrite_ns_skip(ns_client_t *client, dns_name_t *nsname,
st->r.label--;
}
/*
* RPZ query result types
*/
typedef enum {
qresult_type_done = 0,
qresult_type_restart = 1,
qresult_type_recurse = 2
} qresult_type_t;
/*
* Look for response policy zone QNAME, NSIP, and NSDNAME rewriting.
*/
@ -3526,12 +3862,15 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
dns_rdataset_t *rdataset;
dns_fixedname_t nsnamef;
dns_name_t *nsname;
int qresult_type;
qresult_type_t qresult_type;
dns_rpz_zbits_t zbits;
isc_result_t result = ISC_R_SUCCESS;
dns_rpz_have_t have;
dns_rpz_popt_t popt;
int rpz_ver;
#ifdef USE_DNSRPS
librpz_emsg_t emsg;
#endif
CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite");
@ -3543,7 +3882,7 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
return (DNS_R_DISALLOWED);
RWLOCK(&rpzs->search_lock, isc_rwlocktype_read);
if (rpzs->p.num_zones == 0 ||
if ((rpzs->p.num_zones == 0 && !rpzs->p.dnsrps_enabled) ||
(!RECURSIONOK(client) && rpzs->p.no_rd_ok == 0) ||
!rpz_ck_dnssec(client, qresult, ordataset, osigset))
{
@ -3560,6 +3899,7 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
if (st == NULL)
return (ISC_R_NOMEMORY);
st->state = 0;
st->rpsdb = NULL;
}
if (st->state == 0) {
st->state |= DNS_RPZ_ACTIVE;
@ -3579,6 +3919,26 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
st->popt = popt;
st->rpz_ver = rpz_ver;
client->query.rpz_st = st;
if (popt.dnsrps_enabled) {
#ifdef USE_DNSRPS
if (st->rpsdb != NULL) {
dns_db_detach(&st->rpsdb);
}
result = dns_dnsrps_rewrite_init(&emsg, st, rpzs,
client->query.qname,
client->mctx,
RECURSIONOK(client));
if (result != ISC_R_SUCCESS) {
rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
NULL, DNS_RPZ_TYPE_QNAME,
emsg.c, result);
st->m.policy = DNS_RPZ_POLICY_ERROR;
return (ISC_R_SUCCESS);
}
#else
INSIST(0);
#endif
}
}
/*
@ -3588,7 +3948,7 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
case ISC_R_SUCCESS:
case DNS_R_GLUE:
case DNS_R_ZONECUT:
qresult_type = 0;
qresult_type = qresult_type_done;
break;
case DNS_R_EMPTYNAME:
case DNS_R_NXRRSET:
@ -3598,7 +3958,7 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
case DNS_R_NCACHENXRRSET:
case DNS_R_CNAME:
case DNS_R_DNAME:
qresult_type = 1;
qresult_type = qresult_type_restart;
break;
case DNS_R_DELEGATION:
case ISC_R_NOTFOUND:
@ -3608,19 +3968,19 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
* can rewrite.
*/
if (RECURSIONOK(client))
qresult_type = 2;
qresult_type = qresult_type_recurse;
else
qresult_type = 1;
qresult_type = qresult_type_restart;
break;
case ISC_R_FAILURE:
case ISC_R_TIMEDOUT:
case DNS_R_BROKENCHAIN:
rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL3, client->query.qname,
rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL3, NULL,
DNS_RPZ_TYPE_QNAME,
" stop on qresult in rpz_rewrite()", qresult);
return (ISC_R_SUCCESS);
default:
rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, client->query.qname,
rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, NULL,
DNS_RPZ_TYPE_QNAME,
" stop on unrecognized qresult in rpz_rewrite()",
qresult);
@ -3630,19 +3990,23 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
rdataset = NULL;
if ((st->state & (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME)) !=
(DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME)) {
(DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME))
{
isc_netaddr_t netaddr;
dns_rpz_zbits_t allowed;
if (qresult_type == 2) {
if (!st->popt.dnsrps_enabled &&
qresult_type == qresult_type_recurse)
{
/*
* This request needs recursion that has not been done.
* Get bits for the policy zones that do not need
* to wait for the results of recursion.
*/
allowed = st->have.qname_skip_recurse;
if (allowed == 0)
if (allowed == 0) {
return (ISC_R_SUCCESS);
}
} else {
allowed = DNS_RPZ_ALL_ZBITS;
}
@ -3671,9 +4035,12 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
* There is a first time for each name in a CNAME chain
*/
if ((st->state & DNS_RPZ_DONE_QNAME) == 0) {
isc_boolean_t norec =
ISC_TF(qresult_type != qresult_type_recurse);
result = rpz_rewrite_name(client, client->query.qname,
qtype, DNS_RPZ_TYPE_QNAME,
allowed, &rdataset);
allowed, norec,
&rdataset);
if (result != ISC_R_SUCCESS)
goto cleanup;
@ -3699,7 +4066,7 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
* Do not bother saving the work from this attempt,
* because recusion is so slow.
*/
if (qresult_type == 2)
if (qresult_type == qresult_type_recurse)
goto cleanup;
/*
@ -3710,13 +4077,14 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
}
/*
* Check known IP addresses for the query name if the database
* lookup resulted in some addresses (qresult_type == 0)
* Check known IP addresses for the query name if the database lookup
* resulted in some addresses (qresult_type == qresult_type_done)
* and if we have not already checked them.
* Any recursion required for the query has already happened.
* Do not check addresses that will not be in the ANSWER section.
*/
if ((st->state & DNS_RPZ_DONE_QNAME_IP) == 0 && qresult_type == 0 &&
if ((st->state & DNS_RPZ_DONE_QNAME_IP) == 0 &&
qresult_type == qresult_type_done &&
rpz_get_zbits(client, qtype, DNS_RPZ_TYPE_IP) != 0) {
result = rpz_rewrite_ip_rrsets(client,
client->query.qname, qtype,
@ -3799,13 +4167,13 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
case ISC_R_FAILURE:
rpz_rewrite_ns_skip(client, nsname, result,
DNS_RPZ_DEBUG_LEVEL3,
" NS rpz_rrset_find() ");
" NS rpz_rrset_find()");
continue;
default:
rpz_rewrite_ns_skip(client, nsname, result,
DNS_RPZ_INFO_LEVEL,
" unrecognized NS"
" rpz_rrset_find() ");
" rpz_rrset_find()");
continue;
}
}
@ -3843,6 +4211,7 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
qtype,
DNS_RPZ_TYPE_NSDNAME,
DNS_RPZ_ALL_ZBITS,
ISC_TRUE,
&rdataset);
if (result != ISC_R_SUCCESS) {
dns_rdata_freestruct(&ns);
@ -3879,6 +4248,17 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
result = ISC_R_SUCCESS;
cleanup:
#ifdef USE_DNSRPS
if (st->popt.dnsrps_enabled &&
st->m.policy != DNS_RPZ_POLICY_ERROR &&
!dnsrps_set_p(&emsg, client, st, qtype, &rdataset,
ISC_TF(qresult_type != qresult_type_recurse)))
{
rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
DNS_RPZ_TYPE_BAD, emsg.c, DNS_R_SERVFAIL);
st->m.policy = DNS_RPZ_POLICY_ERROR;
}
#endif
if (st->m.policy != DNS_RPZ_POLICY_MISS &&
st->m.policy != DNS_RPZ_POLICY_ERROR &&
st->m.rpz->policy != DNS_RPZ_POLICY_GIVEN)
@ -5427,7 +5807,8 @@ query_resume(query_ctx_t *qctx) {
if (qctx->rpz_st->rpz_ver != qctx->client->view->rpzs->rpz_ver)
{
ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_QUERY, ISC_LOG_INFO,
NS_LOGMODULE_QUERY,
DNS_RPZ_INFO_LEVEL,
"query_resume: RPZ settings "
"out of date "
"(rpz_ver %d, expected %d)",
@ -5789,6 +6170,17 @@ query_checkrpz(query_ctx_t *qctx, isc_result_t result) {
RESTORE(qctx->version, qctx->rpz_st->m.version);
RESTORE(qctx->zone, qctx->rpz_st->m.zone);
/*
* Add SOA record to additional section
*/
rresult = query_addsoa(qctx,
dns_rdataset_isassociated(qctx->rdataset),
DNS_SECTION_ADDITIONAL);
if (rresult != ISC_R_SUCCESS) {
QUERY_ERROR(qctx, result);
return (ISC_R_COMPLETE);
}
switch (qctx->rpz_st->m.policy) {
case DNS_RPZ_POLICY_TCP_ONLY:
qctx->client->message->flags |= DNS_MESSAGEFLAG_TC;
@ -7584,7 +7976,6 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) {
*/
isc_result_t
query_sign_nodata(query_ctx_t *qctx) {
dns_section_t section;
isc_result_t result;
/*
* Look for a NSEC3 record if we don't have a NSEC record.
@ -7688,16 +8079,16 @@ query_sign_nodata(query_ctx_t *qctx) {
}
/*
* Add SOA to the additional section if generated by a RPZ
* rewrite.
* The RPZ SOA has already been added to the additional section
* if this was an RPZ rewrite, but if it wasn't, add it now.
*/
section = qctx->nxrewrite ? DNS_SECTION_ADDITIONAL
: DNS_SECTION_AUTHORITY;
result = query_addsoa(qctx, ISC_UINT32_MAX, section);
if (result != ISC_R_SUCCESS) {
QUERY_ERROR(qctx, result);
return (query_done(qctx));
if (!qctx->nxrewrite) {
result = query_addsoa(qctx, ISC_UINT32_MAX,
DNS_SECTION_AUTHORITY);
if (result != ISC_R_SUCCESS) {
QUERY_ERROR(qctx, result);
return (query_done(qctx));
}
}
/*