--enable-developer
--enable-option-checking=fatal
--enable-dnstap
- --enable-dnsrps
--with-cmocka
--with-libxml2
--with-json-c
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -DDEBUG"
- # NOTE: Testing DNSRPS-enabled builds currently requires an
- # operating system with glibc 2.34+. This requirement will go away
- # once the DNSRPS dynamic loading code gets reworked to use libuv's
- # dlopen() API.
- #
- # NOTE: This does *not* enable testing of the DNSRPS feature itself.
- # Doing that requires a DNSRPS provider library to be present on the
- # test host.
- EXTRA_CONFIGURE: "--enable-dnsrps --enable-dnsrps-dl --with-libidn2 ${WITH_READLINE_READLINE}"
+ EXTRA_CONFIGURE: "--with-libidn2 ${WITH_READLINE_READLINE}"
<<: *tumbleweed_latest_amd64_image
<<: *build_job
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -Og -fsanitize=address,undefined"
LDFLAGS: "-fsanitize=address,undefined"
- EXTRA_CONFIGURE: "--disable-dnsrps --without-jemalloc"
+ EXTRA_CONFIGURE: "--without-jemalloc"
MAX_DISAGREEMENTS_PERCENTAGE: "0.5"
script:
- bash respdiff.sh -s named -q "${PWD}/100k_mixed.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}" "/usr/local/respdiff-reference-bind/sbin/named"
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -Og -fsanitize=thread"
LDFLAGS: "-fsanitize=thread"
- EXTRA_CONFIGURE: "--disable-dnsrps --enable-pthread-rwlock --without-jemalloc PKG_CONFIG_PATH=/opt/tsan/lib/pkgconfig"
+ EXTRA_CONFIGURE: "--enable-pthread-rwlock --without-jemalloc PKG_CONFIG_PATH=/opt/tsan/lib/pkgconfig"
MAX_DISAGREEMENTS_PERCENTAGE: "0.5"
TSAN_OPTIONS: "${TSAN_OPTIONS_DEBIAN}"
script:
clients-per-query 10;\n\
dnssec-accept-expired no;\n\
dnssec-validation " VALIDATION_DEFAULT "; \n"
-#ifdef USE_DNSRPS
- " dnsrps-library \"" DNSRPS_LIBRPZ_PATH "\";\n"
-#endif /* ifdef USE_DNSRPS */
#ifdef HAVE_DNSTAP
" dnstap-identity hostname;\n"
#endif /* ifdef HAVE_DNSTAP */
char *version; /*%< User-specified version */
bool hostname_set; /*%< User has set hostname */
char *hostname; /*%< User-specified hostname */
-#ifdef USE_DNSRPS
- char *dnsrpslib;
-#endif /* ifdef USE_DNSRPS */
/* Server data structures. */
dns_loadmgr_t *loadmgr;
#include <dns/dispatch.h>
#include <dns/dlz.h>
#include <dns/dns64.h>
-#include <dns/dnsrps.h>
#include <dns/dnssec.h>
#include <dns/dyndb.h>
#include <dns/fixedname.h>
return (result);
}
-#ifdef USE_DNSRPS
-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 bool
-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);
- 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 (true);
- }
-
- new_cstr_size = ((cur_len + new_len) / 256 + 1) * 256;
- new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
-
- 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 (true);
-}
-
-/*
- * Get a DNSRPS configuration value using the global and view options
- * for the default. Return false upon failure.
- */
-static bool
-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 (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 (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, 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, ISC_LOG_ERROR,
- "\"%s\" without \"dnsrps-enable yes\"", name);
- return;
- }
-
- if (cfg_obj_isduration(sub_obj)) {
- conf_dnsrps_sadd(ctx, " %s %d", name,
- cfg_obj_asduration(sub_obj));
- } else {
- 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, bool nsip_enabled,
- bool 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;
- bool 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);
-}
-#endif /* ifdef USE_DNSRPS */
-
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) {
"invalid zone name '%s'", str);
return (DNS_R_EMPTYLABEL);
}
- if (!view->rpzs->p.dnsrps_enabled) {
- for (rpz_num = 0; rpz_num < view->rpzs->p.num_zones - 1;
- ++rpz_num)
+ 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))
{
- if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
- &zone->origin))
- {
- cfg_obj_log(rpz_obj, DNS_RPZ_ERROR_LEVEL,
- "duplicate '%s'", str);
- result = DNS_R_DUPLICATE;
- return (result);
- }
+ cfg_obj_log(rpz_obj, DNS_RPZ_ERROR_LEVEL,
+ "duplicate '%s'", str);
+ result = DNS_R_DUPLICATE;
+ return (result);
}
}
if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin)) {
}
static isc_result_t
-configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps,
- const cfg_obj_t *rpz_obj, bool *old_rpz_okp) {
- bool dnsrps_enabled;
+configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t *rpz_obj,
+ bool *old_rpz_okp) {
const cfg_listelt_t *zone_element;
- char *rps_cstr;
- size_t rps_cstr_size;
const cfg_obj_t *sub_obj;
bool recursive_only_default, add_soa_default;
bool nsip_enabled, nsdname_enabled;
}
nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
- /*
- * "dnsrps-enable yes|no" can be either a global or response-policy
- * clause.
- */
- dnsrps_enabled = 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);
- }
-#ifndef USE_DNSRPS
- if (dnsrps_enabled) {
- cfg_obj_log(rpz_obj, DNS_RPZ_ERROR_LEVEL,
- "\"dnsrps-enable yes\" but"
- " without `./configure --enable-dnsrps`");
- return (ISC_R_FAILURE);
- }
-#else /* ifndef USE_DNSRPS */
- if (dnsrps_enabled) {
- if (librpz == NULL) {
- cfg_obj_log(rpz_obj, DNS_RPZ_ERROR_LEVEL,
- "\"dnsrps-enable yes\" but %s",
- librpz_lib_open_emsg.c);
- return (ISC_R_FAILURE);
- }
-
- /*
- * 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);
- }
- }
-#endif /* ifndef USE_DNSRPS */
-
- result = dns_rpz_new_zones(view, named_g_loopmgr, rps_cstr,
- rps_cstr_size, &view->rpzs);
+ result = dns_rpz_new_zones(view, named_g_loopmgr, &view->rpzs);
if (result != ISC_R_SUCCESS) {
return (result);
}
* zones are unchanged, then use the same policy data.
* Data for individual zones that must be reloaded will be merged.
*/
- if (*old_rpz_okp) {
- if (old != NULL &&
- memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
- {
- *old_rpz_okp = false;
- } else if ((old == NULL || old->rps_cstr == NULL) !=
- (zones->rps_cstr == NULL))
- {
- *old_rpz_okp = false;
- } else if (old != NULL && zones->rps_cstr != NULL &&
- strcmp(old->rps_cstr, zones->rps_cstr) != 0)
- {
- *old_rpz_okp = false;
- }
+ if (old != NULL && memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0) {
+ *old_rpz_okp = false;
}
if (*old_rpz_okp) {
if (view->rdclass == dns_rdataclass_in && need_hints &&
named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS)
{
- CHECK(configure_rpz(view, NULL, maps, obj, &old_rpz_ok));
+ CHECK(configure_rpz(view, NULL, obj, &old_rpz_ok));
rpz_configured = true;
}
* zone named in the response policy statement, unless we are
* using RPZ service interface.
*/
- if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
+ if (view->rpzs != NULL) {
dns_rpz_num_t n;
for (n = 0; n < view->rpzs->p.num_zones; ++n) {
* because we are reverting the same operation
* done previously in the "correct" order.
*/
- result2 = configure_rpz(pview, view, maps, obj,
+ result2 = configure_rpz(pview, view, obj,
&old_rpz_ok);
if (result2 != ISC_R_SUCCESS) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
* 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 ||
- view->rpzs->p.dnsrps_enabled)
- {
+ if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones) {
rpz_num = DNS_RPZ_INVALID_NUM;
break;
}
server->kasplist = kasplist;
kasplist = tmpkasplist;
-#ifdef USE_DNSRPS
- /*
- * Find the path to the DNSRPS implementation library.
- */
- obj = NULL;
- if (named_config_get(maps, "dnsrps-library", &obj) == ISC_R_SUCCESS) {
- if (server->dnsrpslib != NULL) {
- dns_dnsrps_server_destroy();
- isc_mem_free(server->mctx, server->dnsrpslib);
- server->dnsrpslib = NULL;
- }
- setstring(server, &server->dnsrpslib, cfg_obj_asstring(obj));
- result = dns_dnsrps_server_create(server->dnsrpslib);
- isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
- ISC_LOG_DEBUG(1),
- "initializing DNSRPS RPZ provider '%s': %s",
- server->dnsrpslib, isc_result_totext(result));
- /*
- * It's okay if librpz isn't available. We'll complain
- * later if it turns out to be needed for a view with
- * "dnsrps-enable yes".
- */
- if (result == ISC_R_FILENOTFOUND) {
- result = ISC_R_SUCCESS;
- }
- CHECKFATAL(result, "initializing RPZ service interface");
- }
-#endif /* ifdef USE_DNSRPS */
-
/*
* Configure the views.
*/
(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 (dns_view_t *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_altsecrets;
- }
- }
-#endif /* ifdef USE_DNSRPS */
-
/*
* Record the time of most recent configuration
*/
}
#endif /* HAVE_DNSTAP */
-#ifdef USE_DNSRPS
- dns_dnsrps_server_destroy();
- isc_mem_free(server->mctx, server->dnsrpslib);
-#endif /* ifdef USE_DNSRPS */
-
named_controls_destroy(&server->controls);
isc_stats_detach(&server->zonestats);
SUBDIRS = dyndb/driver dlzexternal/driver hooks/driver
-if DNSRPS
-SUBDIRS += rpz/testlib
-endif
-
AM_CPPFLAGS += \
$(LIBISC_CFLAGS) \
$(LIBDNS_CFLAGS)
feature-test \
makejournal \
pipelined/pipequeries \
- rndc/gencheck \
- rpz/dnsrps
+ rndc/gencheck
feature_test_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(LDADD) \
$(LIBDNS_LIBS)
-rpz_dnsrps_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- $(LIBDNS_CFLAGS) \
- -DLIBRPZ_LIB_OPEN=\"$(abs_builddir)/rpz/testlib/.libs/libdummyrpz.so\"
-
-rpz_dnsrps_LDADD = \
- $(LDADD) \
- $(LIBUV_LIBS) \
- $(LIBDNS_LIBS)
-
# Longer running tests are listed (and executed) first to take the most
# advantage of parallel execution.
TESTS = \
fprintf(stderr, "usage: feature-test <arg>\n");
fprintf(stderr, "args:\n");
fprintf(stderr, "\t--edns-version\n");
- fprintf(stderr, "\t--enable-dnsrps\n");
fprintf(stderr, "\t--enable-dnstap\n");
fprintf(stderr, "\t--enable-querytrace\n");
fprintf(stderr, "\t--fips-provider\n");
return (0);
}
- if (strcmp(argv[1], "--enable-dnsrps") == 0) {
-#ifdef USE_DNSRPS
- return (0);
-#else /* ifdef USE_DNSRPS */
- return (1);
-#endif /* ifdef USE_DNSRPS */
- }
-
if (strcmp(argv[1], "--enable-dnstap") == 0) {
#ifdef HAVE_DNSTAP
return (0);
# information regarding copyright ownership.
import os
-from pathlib import Path
import subprocess
import pytest
return True
-DNSRPS_BIN = Path(os.environ["TOP_BUILDDIR"]) / "bin/tests/system/rpz/dnsrps"
-
-
-def is_dnsrps_available():
- if not feature_test("--enable-dnsrps"):
- return False
- try:
- subprocess.run([DNSRPS_BIN, "-a"], check=True)
- except subprocess.CalledProcessError:
- return False
- return True
-
-
def with_tsan(*args): # pylint: disable=unused-argument
return feature_test("--tsan")
not feature_test("--have-json-c"), reason="json-c support disabled in the build"
)
-dnsrps_enabled = pytest.mark.skipif(
- not is_dnsrps_available(), reason="dnsrps disabled in the build"
-)
-
try:
import flaky as flaky_pkg # type: ignore
rm -f ns8/manual-update-rpz.db
rm -f */policy2.db
rm -f */*.jnl
-rm -f dnsrps.cache dnsrps.conf
rm -f proto.* dsset-* trusted.conf dig.out* nsupdate.tmp ns*/*tmp
rm -f ns5/requests ns5/*.perf
rm -f */named.memstats */*.run */*.run.prev */named.stats */session.key
rm -f ns*/named.lock
rm -f ns*/named.conf
rm -f ns*/*switch
-rm -f dnsrps.zones
rm -f ns*/managed-keys.bind*
rm -f tmp
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * 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 https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*
- * -a exit(EXIT_SUCCESS) if dnsrps is available or dlopen() msg if not
- * -n domain print the serial number of a domain to check if a new
- * version of a policy zone is ready.
- * Exit(1) if dnsrps is not available
- * -w sec.ond wait for seconds, because `sleep 0.1` is not portable
- */
-
-#include <errno.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <isc/util.h>
-
-#ifdef USE_DNSRPS
-#include <dns/librpz.h>
-#else /* ifdef USE_DNSRPS */
-typedef struct {
- char c[120];
-} librpz_emsg_t;
-#endif /* ifdef USE_DNSRPS */
-
-static bool
-link_dnsrps(librpz_emsg_t *emsg);
-
-#define USAGE "usage: [-a] [-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 = NULL;
- librpz_client_t *client = NULL;
- librpz_rsp_t *rsp = NULL;
- uint32_t serial;
-#endif /* ifdef USE_DNSRPS */
- double seconds;
- librpz_emsg_t emsg;
- char *p;
- int i;
-
- while ((i = getopt(argc, argv, "an:w:")) != -1) {
- switch (i) {
- case 'a':
- if (!link_dnsrps(&emsg)) {
- printf("I:%s\n", emsg.c);
- return (1);
- }
- return (0);
-
- 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.
- */
- 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;", optarg);
- client = librpz->client_create(&emsg, clist, cstr,
- true);
- if (client == NULL) {
- fprintf(stderr, "## %s\n", emsg.c);
- librpz->clist_detach(&clist);
- 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);
- librpz->clist_detach(&clist);
- return (1);
- }
-
- if (!librpz->soa_serial(&emsg, &serial, optarg, rsp)) {
- fprintf(stderr, "## %s\n", emsg.c);
- librpz->rsp_detach(&rsp);
- librpz->client_detach(&client);
- librpz->clist_detach(&clist);
- return (1);
- }
- librpz->rsp_detach(&rsp);
- librpz->client_detach(&client);
- librpz->clist_detach(&clist);
- printf("%u\n", serial);
-#else /* ifdef USE_DNSRPS */
- UNREACHABLE();
-#endif /* ifdef USE_DNSRPS */
- return (0);
-
- case 'w':
- seconds = strtod(optarg, &p);
- if (seconds <= 0 || *p != '\0') {
- fprintf(stderr, USAGE);
- return (1);
- }
- usleep((int)(seconds * 1000.0 * 1000.0));
- return (0);
-
- default:
- fprintf(stderr, USAGE);
- return (1);
- }
- }
- fprintf(stderr, USAGE);
- return (1);
-}
-
-static bool
-link_dnsrps(librpz_emsg_t *emsg) {
-#ifdef USE_DNSRPS
- librpz = librpz_lib_open(emsg, NULL, LIBRPZ_LIB_OPEN);
- if (librpz == NULL) {
- return (false);
- }
-
- return (true);
-#else /* ifdef USE_DNSRPS */
- snprintf(emsg->c, sizeof(emsg->c), "DNSRPS not configured");
- return (false);
-#endif /* ifdef USE_DNSRPS */
-}
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * 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 https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-# dnsrpzd configuration.
-
-pid-file ../dnsrpzd.pid
-
-# configure NOTIFY and zone transfers
-port @EXTRAPORT1@;
-listen-on port @EXTRAPORT1@ { 10.53.0.3; };
-allow-notify { 10.53.0.0/24; };
-
-zone "bl0" {type primary; file "../ns5/bl.db"; };
-zone "bl1" {type primary; file "../ns5/bl.db"; };
-zone "bl2" {type primary; file "../ns5/bl.db"; };
-zone "bl3" {type primary; file "../ns5/bl.db"; };
-zone "bl4" {type primary; file "../ns5/bl.db"; };
-zone "bl5" {type primary; file "../ns5/bl.db"; };
-zone "bl6" {type primary; file "../ns5/bl.db"; };
-zone "bl7" {type primary; file "../ns5/bl.db"; };
-zone "bl8" {type primary; file "../ns5/bl.db"; };
-zone "bl9" {type primary; file "../ns5/bl.db"; };
-zone "bl10" {type primary; file "../ns5/bl.db"; };
-zone "bl11" {type primary; file "../ns5/bl.db"; };
-zone "bl12" {type primary; file "../ns5/bl.db"; };
-zone "bl13" {type primary; file "../ns5/bl.db"; };
-zone "bl14" {type primary; file "../ns5/bl.db"; };
-zone "bl15" {type primary; file "../ns5/bl.db"; };
-zone "bl16" {type primary; file "../ns5/bl.db"; };
-zone "bl17" {type primary; file "../ns5/bl.db"; };
-zone "bl18" {type primary; file "../ns5/bl.db"; };
-zone "bl19" {type primary; file "../ns5/bl.db"; };
-
-zone "bl" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-2" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-given" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-passthru" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-no-op" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-disabled" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-nodata" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-nxdomain" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-cname" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-wildcname" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-garden" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-drop" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl-tcp-only" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-zone "bl.tld2" {type secondary; primaries port @PORT@ { 10.53.0.3; }; };
-
-zone "policy1" {type secondary; primaries port @PORT@ { 10.53.0.6; }; };
-zone "policy2" {type secondary; primaries port @PORT@ { 10.53.0.7; }; };
nsip-enable yes
;
- include "../dnsrps.conf";
also-notify { 10.53.0.3 port @EXTRAPORT1@; };
notify-delay 0;
};
# turn rpz on or off
include "rpz-switch";
-
- include "../dnsrps.conf";
};
key rndc_key {
// add-soa yes # leave add-soa as default for unset test
nsip-enable yes
nsdname-enable yes;
-
- include "../dnsrps.conf";
};
logging { category rpz { default_debug; }; };
nsip-enable yes
nsdname-enable yes
min-update-interval 0;
-
- include "../dnsrps.conf";
};
logging { category rpz { default_debug; }; };
nsip-enable yes
;
- include "../dnsrps.conf";
also-notify { 10.53.0.8 port @EXTRAPORT1@; };
notify-delay 0;
};
}
qname-wait-recurse no ;
- include "../dnsrps.conf";
notify-delay 0;
};
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
-# touch dnsrps-off to not test with DNSRPS
-
set -e
. ../conf.sh
copy_setports ns9/named.conf.in ns9/named.conf
copy_setports ns10/named.conf.in ns10/named.conf
-copy_setports dnsrps.zones.in dnsrps.zones
-
-touch dnsrps.conf
-touch dnsrps.cache
-
# set up test policy zones.
# bl is the main test zone
# bl-2 is used to check competing zones.
+++ /dev/null
-include $(top_srcdir)/Makefile.top
-
-AM_CPPFLAGS += \
- $(LIBISC_CFLAGS) \
- $(LIBDNS_CFLAGS)
-
-AM_CFLAGS += -Wall -pedantic -Wno-zero-length-array
-
-noinst_LTLIBRARIES = libdummyrpz.la
-libdummyrpz_la_SOURCES= dummylib.c test-data.c trpz.h test-data.h
-libdummyrpz_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -rpath $(abs_builddir)
-LDADD += -lpthread
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * 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 https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*
- * Limited implementation of the DNSRPS API for testing purposes.
- *
- * 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.
- */
-
-#include <arpa/inet.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <time.h>
-#include <unistd.h>
-
-#ifdef HAVE_ARPA_NAMESER_COMPAT_H
-#include <arpa/nameser_compat.h>
-#endif /* HAVE_ARPA_NAMESER_COMPAT_H */
-
-#include <isc/endian.h>
-#include <isc/util.h>
-
-#include <dns/librpz.h>
-
-#include "test-data.h"
-#include "trpz.h"
-
-librpz_log_fnc_t *g_log_fnc = NULL;
-const char *g_prog_nm = NULL;
-bool g_scan_data_file_for_errors = true;
-
-typedef struct {
- void *mutex_ctx;
- void *log_ctx;
- librpz_mutex_t *mutex_lock_fn;
- librpz_mutex_t *mutex_unlock_fn;
- librpz_mutex_t *mutex_destroy_fn;
-} trpz_clist_t;
-
-typedef struct {
- char *cstr;
- bool uses_expired;
- trpz_clist_t *pclist;
-} trpz_client_t;
-
-typedef struct {
- size_t idx; /* value only used for node iteration */
- trpz_client_t *client;
- bool have_rd;
- char zone[256];
- char domain[256];
- size_t zidx;
- trpz_result_t rstack[LIBRPZ_RSP_STACK_DEPTH];
- size_t stack_idx;
- trpz_zone_t *all_zones;
- trpz_result_t *all_nodes;
- size_t num_zones, num_nodes;
- ssize_t last_zone;
- ssize_t *base_zones;
- size_t nbase_zones;
-} trpz_rsp_t;
-
-librpz_log_level_t g_log_level = LIBRPZ_LOG_TRACE2;
-FILE *g_log_outf = NULL;
-
-static int
-apply_all_updates(trpz_rsp_t *trsp);
-static void
-clear_all_updates(trpz_rsp_t *trsp);
-
-static bool
-domain_ntop(const u_char *src, char *dst, size_t dstsiz);
-static bool
-domain_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen,
- bool lower);
-
-void
-trpz_set_log(librpz_log_fnc_t *new_log, const char *prog_nm);
-void
-trpz_vlog(librpz_log_level_t level, void *ctx, const char *p, va_list args)
- LIBRPZ_PF(3, 0);
-void
-trpz_log(librpz_log_level_t level, void *ctx, const char *p, ...)
- LIBRPZ_PF(3, 4);
-librpz_log_level_t
-trpz_log_level_val(librpz_log_level_t level);
-void
-trpz_vpemsg(librpz_emsg_t *emsg, const char *p, va_list args) LIBRPZ_PF(2, 0);
-void
-trpz_pemsg(librpz_emsg_t *emsg, const char *fmt, ...) LIBRPZ_PF(2, 3);
-librpz_clist_t *
-trpz_clist_create(librpz_emsg_t *emsg, librpz_mutex_t *lock,
- librpz_mutex_t *unlock, librpz_mutex_t *mutex_destroy,
- void *mutex_ctx, void *log_ctx);
-void
-trpz_clist_detach(librpz_clist_t **clistp);
-bool
-trpz_connect(librpz_emsg_t *emsg, librpz_client_t *client, bool optional);
-librpz_client_t *
-trpz_client_create(librpz_emsg_t *emsg, librpz_clist_t *clist, const char *cstr,
- bool use_expired);
-void
-trpz_client_detach(librpz_client_t **clientp);
-bool
-trpz_rsp_create(librpz_emsg_t *emsg, librpz_rsp_t **rspp, int *min_ns_dotsp,
- librpz_client_t *client, bool have_rd, bool have_do);
-void
-trpz_rsp_detach(librpz_rsp_t **rspp);
-bool
-trpz_rsp_push(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
-bool
-trpz_rsp_pop(librpz_emsg_t *emsg, librpz_result_t *result, librpz_rsp_t *rsp);
-bool
-trpz_rsp_pop_discard(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
-bool
-trpz_rsp_domain(librpz_emsg_t *emsg, librpz_domain_buf_t *owner,
- librpz_rsp_t *rsp);
-bool
-trpz_rsp_result(librpz_emsg_t *emsg, librpz_result_t *result, bool recursed,
- const librpz_rsp_t *rsp);
-bool
-trpz_rsp_soa(librpz_emsg_t *emsg, uint32_t *ttlp, librpz_rr_t **rrp,
- librpz_domain_buf_t *origin, librpz_result_t *result,
- librpz_rsp_t *rsp);
-bool
-trpz_rsp_rr(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);
-bool
-trpz_ck_domain(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);
-bool
-trpz_ck_ip(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);
-bool
-trpz_rsp_clientip_prefix(librpz_emsg_t *emsg, librpz_prefix_t *prefix,
- librpz_rsp_t *rsp);
-bool
-trpz_have_trig(librpz_trig_t trig, bool ipv6, const librpz_rsp_t *rsp);
-bool
-trpz_rsp_forget_zone(librpz_emsg_t *emsg, librpz_cznum_t znum,
- librpz_rsp_t *rsp);
-char *
-trpz_vers_stats(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
-bool
-trpz_soa_serial(librpz_emsg_t *emsg, uint32_t *serialp, const char *domain_nm,
- librpz_rsp_t *rsp);
-const char *
-trpz_policy2str(librpz_policy_t policy, char *buf, size_t buf_size);
-
-#define BASE_ZONE_ANY -1
-#define BASE_ZONE_INVALID -2
-
-librpz_0_t LIBRPZ_DEF = {
- .dnsrpzd_path = "test-only",
- .version = "0.0",
- .log_level_val = trpz_log_level_val,
- .set_log = trpz_set_log,
- .vpemsg = trpz_vpemsg,
- .pemsg = trpz_pemsg,
- .vlog = trpz_vlog,
- .log = trpz_log,
- .clist_create = trpz_clist_create,
- .clist_detach = trpz_clist_detach,
- .client_create = trpz_client_create,
- .connect = trpz_connect,
- .client_detach = trpz_client_detach,
- .rsp_create = trpz_rsp_create,
- .rsp_detach = trpz_rsp_detach,
- .rsp_result = trpz_rsp_result,
- .have_trig = trpz_have_trig,
- .rsp_domain = trpz_rsp_domain,
- .rsp_rr = trpz_rsp_rr,
- .rsp_soa = trpz_rsp_soa,
- .soa_serial = trpz_soa_serial,
- .rsp_push = trpz_rsp_push,
- .rsp_pop = trpz_rsp_pop,
- .rsp_pop_discard = trpz_rsp_pop_discard,
- .rsp_forget_zone = trpz_rsp_forget_zone,
- .ck_ip = trpz_ck_ip,
- .ck_domain = trpz_ck_domain,
- .policy2str = trpz_policy2str,
-};
-
-/*
- * Returns whether or not searching in the specified zone, by index, is
- * permitted. A client/RSP state can support a variable number of configured
- * zones.
- */
-static bool
-has_base_zone(trpz_rsp_t *trsp, ssize_t zone) {
- size_t n;
-
- if (trsp == NULL || trsp->base_zones == NULL || trsp->nbase_zones == 0)
- {
- return (false);
- }
-
- for (n = 0; n < trsp->nbase_zones; n++) {
- if (trsp->base_zones[n] == BASE_ZONE_ANY ||
- trsp->base_zones[n] == zone)
- {
- return (true);
- }
- }
-
- return (false);
-}
-
-static bool
-pack_soa_record(unsigned char *rdatap, size_t rbufsz, size_t *rdlenp,
- const rpz_soa_t *psoa) {
- size_t needed = (sizeof(uint32_t) * 5) + strlen(psoa->mname) + 2 +
- strlen(psoa->rname) + 2;
- size_t mlen = 0, rlen = 0, used = 0;
-
- if (needed > rbufsz) {
- return (false);
- }
-
- if (!domain_pton2(psoa->mname, rdatap, rbufsz, &rlen, true)) {
- return (false);
- }
-
- if (!domain_pton2(psoa->rname, rdatap + rlen, rbufsz - rlen, &mlen,
- true))
- {
- return (false);
- }
-
- used = rlen + mlen;
-
- rdatap += rlen + mlen;
- ISC_U32TO8_BE(rdatap, psoa->serial);
- rdatap += 4;
- ISC_U32TO8_BE(rdatap, psoa->refresh);
- rdatap += 4;
- ISC_U32TO8_BE(rdatap, psoa->retry);
- rdatap += 4;
- ISC_U32TO8_BE(rdatap, psoa->expire);
- rdatap += 4;
- ISC_U32TO8_BE(rdatap, psoa->minimum);
- used += (4 * 5);
-
- SET_IF_NOT_NULL(rdlenp, used);
-
- return (true);
-}
-
-static void
-do_log(librpz_log_level_t level, void *ctx, const char *fmt, va_list args)
- LIBRPZ_PF(3, 0);
-static void
-do_log(librpz_log_level_t level, void *ctx, const char *fmt, va_list args) {
- if (level > g_log_level) {
- return;
- }
-
- if (g_log_fnc != NULL) {
- char lbuf[8192] = { 0 };
-
- vsnprintf(lbuf, sizeof(lbuf) - 1, fmt, args);
- g_log_fnc(level, ctx, lbuf);
- return;
- }
-
- if (g_log_outf == NULL) {
- return;
- }
-
- vfprintf(g_log_outf, fmt, args);
- fprintf(g_log_outf, "\n");
- return;
-}
-
-void
-trpz_vlog(librpz_log_level_t level, void *ctx, const char *p, va_list args) {
- do_log(level, ctx, p, args);
- return;
-}
-
-void
-trpz_log(librpz_log_level_t level, void *ctx, const char *p, ...) {
- va_list ap;
-
- va_start(ap, p);
- trpz_vlog(level, ctx, p, ap);
- va_end(ap);
-
- return;
-}
-
-void
-trpz_set_log(librpz_log_fnc_t *new_log, const char *prog_nm) {
- assert(new_log != NULL || prog_nm != NULL);
-
- if (new_log != NULL) {
- g_log_fnc = new_log;
- }
-
- if (prog_nm != NULL) {
- g_prog_nm = prog_nm;
- }
-}
-
-librpz_log_level_t
-trpz_log_level_val(librpz_log_level_t level) {
- if (level >= LIBRPZ_LOG_INVALID) {
- return (g_log_level);
- }
-
- g_log_level = (level < LIBRPZ_LOG_FATAL) ? LIBRPZ_LOG_FATAL : level;
-
- return (g_log_level);
-}
-
-void
-trpz_vpemsg(librpz_emsg_t *emsg, const char *p, va_list args) {
- if (emsg == NULL) {
- return;
- }
-
- vsnprintf(emsg->c, sizeof(emsg->c), p, args);
- emsg->c[sizeof(emsg->c) - 1] = 0;
- return;
-}
-
-void
-trpz_pemsg(librpz_emsg_t *emsg, const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- trpz_vpemsg(emsg, fmt, ap);
- va_end(ap);
-
- return;
-}
-
-/*
- * Scan the data file for errors and log anything found that's critically
- * wrong.
- */
-static void
-scan_data_file_for_errors(void *lctx) {
- char *updfile = NULL, *fname = NULL, *last = NULL;
- char *tmp = NULL;
-
- updfile = getenv("DNSRPS_TEST_UPDATE_FILE");
- if (updfile == NULL) {
- return;
- }
-
- tmp = strdup(updfile);
- if (tmp == NULL) {
- return;
- }
-
- fname = strtok_r(tmp, ":", &last);
-
- while (fname) {
- char *errp = NULL;
- int ret;
-
- ret = sanity_check_data_file(fname, &errp);
-
- if ((ret < 0) && errp) {
- trpz_log(LIBRPZ_LOG_ERROR, lctx, "%s", errp);
- free(errp);
- }
-
- fname = strtok_r(NULL, ":", &last);
- }
- free(tmp);
-
- return;
-}
-
-librpz_clist_t *
-trpz_clist_create(librpz_emsg_t *emsg, librpz_mutex_t *lock,
- librpz_mutex_t *unlock, librpz_mutex_t *mutex_destroy,
- void *mutex_ctx, void *log_ctx) {
- trpz_clist_t *result = NULL;
-
- result = calloc(1, sizeof(*result));
- if (result == NULL) {
- trpz_pemsg(emsg, "calloc: %s", strerror(errno));
- return (NULL);
- }
-
- result->mutex_ctx = mutex_ctx;
- result->log_ctx = log_ctx;
- result->mutex_lock_fn = lock;
- result->mutex_unlock_fn = unlock;
- result->mutex_destroy_fn = mutex_destroy;
-
- if (g_scan_data_file_for_errors) {
- scan_data_file_for_errors(log_ctx);
- }
-
- return ((librpz_clist_t *)result);
-}
-
-void
-trpz_clist_detach(librpz_clist_t **clistp) {
- if (clistp != NULL && *clistp != NULL) {
- librpz_clist_t *clist = *clistp;
- *clistp = NULL;
- free(clist);
- }
-
- return;
-}
-
-bool
-trpz_connect(librpz_emsg_t *emsg, librpz_client_t *client, bool optional) {
- UNUSED(optional);
-
- if (client == NULL) {
- trpz_pemsg(emsg, "Can't connect to null client");
- return (false);
- }
-
- return (true);
-}
-
-const char *
-trpz_policy2str(librpz_policy_t policy, char *buf, size_t buf_size) {
- const char *pname = NULL;
-
- if (buf == NULL || buf_size == 0) {
- return (NULL);
- }
-
- switch (policy) {
- case LIBRPZ_POLICY_UNDEFINED:
- pname = "UNDEFINED";
- break;
- case LIBRPZ_POLICY_DELETED:
- pname = "DELETED";
- break;
- case LIBRPZ_POLICY_PASSTHRU:
- pname = "PASSTHRU";
- break;
- case LIBRPZ_POLICY_DROP:
- pname = "DROP";
- break;
- case LIBRPZ_POLICY_TCP_ONLY:
- pname = "TCP-ONLY";
- break;
- case LIBRPZ_POLICY_NXDOMAIN:
- pname = "NXDOMAIN";
- break;
- case LIBRPZ_POLICY_NODATA:
- pname = "NODATA";
- break;
- case LIBRPZ_POLICY_RECORD:
- pname = "RECORD";
- break;
- case LIBRPZ_POLICY_GIVEN:
- pname = "GIVEN";
- break;
- case LIBRPZ_POLICY_DISABLED:
- pname = "DISABLED";
- break;
- case LIBRPZ_POLICY_CNAME:
- pname = "CNAME";
- break;
- default:
- pname = "UNKNOWN";
- break;
- }
-
- strncpy(buf, pname, buf_size);
- buf[buf_size - 1] = 0;
- return (buf);
-}
-
-/*
- * Get the entire set of zones configured by the config string,
- * and bind then to the specified RSP state.
- *
- * The array of active zone indices is returned by the function on success,
- * or NULL on failure. The total number of zones is stored in pnzones.
- */
-static ssize_t *
-get_cstr_zones(const char *cstr, trpz_rsp_t *trsp, size_t *pnzones) {
- char tmpc[8192] = { 0 };
- char *tptr = tmpc, *tok = NULL;
- size_t nzones = 0, cur_idx = 0;
- ssize_t *result = NULL;
- unsigned long zflags = 0;
-
- result = calloc(trsp->num_zones + 1, sizeof(*result));
- if (result == NULL) {
- perror("calloc");
- exit(EXIT_FAILURE);
- }
-
- if (cstr == NULL) {
- result[0] = BASE_ZONE_ANY;
- *pnzones = 1;
- return (result);
- }
-
- strncpy(tmpc, cstr, sizeof(tmpc) - 1);
- *pnzones = 0;
-
- while (tptr != NULL && *tptr != '\0') {
- tok = strsep(&tptr, ";\n");
-
- while (isspace((unsigned char)*tok)) {
- tok++;
- }
-
- if (strncasecmp(tok, "zone ", 5) == 0) {
- char zcmd[1024] = { 0 };
- char *qend = NULL;
- size_t zind = 0, old_zct = trsp->num_zones;
- unsigned long zopts = 0;
-
- tok += 5;
-
- while (isspace((unsigned char)*tok)) {
- tok++;
- }
-
- if (*tok == '"') {
- qend = strchr(++tok, '"');
- if (qend == NULL) {
- fprintf(stderr, "Error parsing cstr "
- "contents!\n");
- free(result);
- return (NULL);
- }
-
- *qend++ = 0;
-
- if (tok[strlen(tok) - 1] == '.') {
- tok[strlen(tok) - 1] = 0;
- }
-
- } else {
- qend = tok;
- }
-
- while (*qend != '\0' && !isspace((unsigned char)*qend))
- {
- qend++;
- }
-
- if (*qend != '\0') {
- *qend++ = '\0';
- zopts = parse_zone_options(qend);
- }
-
- snprintf(zcmd, sizeof(zcmd) - 1, "zone %s 1", tok);
-
- if (apply_update(zcmd, &(trsp->all_nodes),
- &(trsp->num_nodes), &(trsp->all_zones),
- &(trsp->num_zones), 0, zopts,
- NULL) < 0)
- {
- fprintf(stderr, "Internal error {%s}!\n", zcmd);
- free(result);
- return (NULL);
- }
-
- if (trsp->num_zones > old_zct) {
- result = realloc(result,
- ((trsp->num_zones + 1) *
- sizeof(*result)));
- if (result == NULL) {
- perror("realloc");
- exit(EXIT_FAILURE);
- }
- }
-
- for (zind = 0; zind < trsp->num_zones; zind++) {
- if (!strcmp(trsp->all_zones[zind].name, tok)) {
- break;
- }
- }
-
- if (zind == trsp->num_zones) {
- free(result);
- return (NULL);
- }
-
- result[cur_idx++] = zind;
- *pnzones = cur_idx;
- nzones++;
- } else {
- unsigned long flags;
-
- flags = parse_zone_options(tok);
- zflags |= (flags & (ZOPT_QNAME_AS_NS | ZOPT_IP_AS_NS |
- ZOPT_RECURSIVE_ONLY |
- ZOPT_NOT_RECURSIVE_ONLY |
- ZOPT_NO_QNAME_WAIT_RECURSE |
- ZOPT_NO_NSIP_WAIT_RECURSE));
- }
-
- tok = NULL;
- }
-
- if (nzones == 0) {
- free(result);
- return (NULL);
- }
-
- if (zflags != 0) {
- size_t n;
-
- for (n = 0; n < trsp->num_zones; n++) {
- if (zflags & ZOPT_QNAME_AS_NS) {
- trsp->all_zones[n].qname_as_ns = true;
- }
-
- if (zflags & ZOPT_IP_AS_NS) {
- trsp->all_zones[n].ip_as_ns = true;
- }
-
- if (zflags & ZOPT_RECURSIVE_ONLY) {
- trsp->all_zones[n].not_recursive_only = false;
- } else if (zflags & ZOPT_NOT_RECURSIVE_ONLY) {
- trsp->all_zones[n].not_recursive_only = true;
- }
-
- if (zflags & ZOPT_NO_QNAME_WAIT_RECURSE) {
- trsp->all_zones[n].no_qname_wait_recurse = true;
- }
-
- if (zflags & ZOPT_NO_NSIP_WAIT_RECURSE) {
- trsp->all_zones[n].no_nsip_wait_recurse = true;
- }
- }
- }
-
- return (result);
-}
-
-librpz_client_t *
-trpz_client_create(librpz_emsg_t *emsg, librpz_clist_t *clist, const char *cstr,
- bool use_expired) {
- trpz_client_t *result = NULL;
-
- if (clist == NULL) {
- trpz_pemsg(emsg, "clist was NULL\n");
- return (NULL);
- }
-
- result = calloc(1, sizeof(*result));
- if (result == NULL) {
- trpz_pemsg(emsg, "calloc: %s", strerror(errno));
- return (NULL);
- }
-
- result->cstr = strdup(cstr);
- if (result->cstr == NULL) {
- trpz_pemsg(emsg, "strdup: %s", strerror(errno));
- free(result);
- return (NULL);
- }
-
- result->uses_expired = use_expired;
- result->pclist = (trpz_clist_t *)clist;
-
- return ((librpz_client_t *)result);
-}
-
-void
-trpz_client_detach(librpz_client_t **clientp) {
- if (clientp != NULL && *clientp != NULL) {
- trpz_client_t *client = (trpz_client_t *)(*clientp);
- if (client->cstr != NULL) {
- free(client->cstr);
- }
- free(client);
- }
-
- return;
-}
-
-/*
- * If the DNSRPS_TEST_UPDATE_FILE env variable is set,
- * load the current list of test nodes from the specified data file.
- *
- * Any existing nodes are first destroyed.
- */
-static int
-apply_all_updates(trpz_rsp_t *trsp) {
- char *updfile = NULL, *fname = NULL, *last = NULL;
- char *tmp = NULL;
-
- updfile = getenv("DNSRPS_TEST_UPDATE_FILE");
- if (updfile == NULL) {
- return (0);
- }
-
- tmp = strdup(updfile);
- if (tmp == NULL) {
- return (-1);
- }
-
- fname = strtok_r(updfile, ":", &last);
- while (fname != NULL) {
- char *errp = NULL;
- int ret;
-
- ret = load_all_updates(fname, &trsp->all_nodes,
- &trsp->num_nodes, &trsp->all_zones,
- &trsp->num_zones, &errp);
-
- if (errp != NULL) {
- fprintf(stderr, "Error loading updates: %s\n", errp);
- free(errp);
- }
-
- if (ret < 0) {
- free(tmp);
- return (-1);
- }
-
- fname = strtok_r(NULL, ":", &last);
- }
- free(tmp);
-
- return (0);
-}
-
-static void
-clear_all_updates(trpz_rsp_t *trsp) {
- if (trsp == NULL) {
- return;
- }
-
- if (trsp->all_zones != NULL) {
- free(trsp->all_zones);
- }
-
- trsp->all_zones = NULL;
- trsp->num_zones = 0;
-
- if (trsp->all_nodes != NULL) {
- size_t n;
-
- for (n = 0; n < trsp->num_nodes; n++) {
- if (trsp->all_nodes[n].canonical != NULL) {
- free(trsp->all_nodes[n].canonical);
- }
- if (trsp->all_nodes[n].dname != NULL) {
- free(trsp->all_nodes[n].dname);
- }
- if (trsp->all_nodes[n].rrs) {
- size_t m;
-
- for (m = 0; m < trsp->all_nodes[n].nrrs; m++) {
- if (trsp->all_nodes[n].rrs[m].rdata) {
- free(trsp->all_nodes[n]
- .rrs[m]
- .rdata);
- }
- }
-
- free(trsp->all_nodes[n].rrs);
- }
- }
-
- free(trsp->all_nodes);
- }
-
- trsp->all_nodes = NULL;
- trsp->num_nodes = 0;
-
- return;
-}
-
-/*
- * Start a set of RPZ queries for a single DNS response.
- */
-bool
-trpz_rsp_create(librpz_emsg_t *emsg, librpz_rsp_t **rspp, int *min_ns_dotsp,
- librpz_client_t *client, bool have_rd, bool have_do) {
- trpz_client_t *cli = (trpz_client_t *)client;
- trpz_rsp_t *result = NULL;
-
- UNUSED(min_ns_dotsp);
- UNUSED(have_do);
-
- if (client == NULL) {
- trpz_pemsg(emsg, "client was NULL");
- return (false);
- } else if (rspp == NULL) {
- trpz_pemsg(emsg, "rspp was NULL");
- return (false);
- } else if (cli->cstr == NULL) {
- trpz_pemsg(emsg, "no valid policy zone specified");
- return (false);
- }
-
- result = calloc(1, sizeof(*result));
- if (result == NULL) {
- trpz_pemsg(emsg, "calloc: %s", strerror(errno));
- return (false);
- }
-
- result->idx = 0;
- result->client = cli;
- result->have_rd = have_rd;
- result->stack_idx = 1;
- result->last_zone = -1;
-
- assert(*rspp == NULL);
-
- clear_all_updates(result);
- result->base_zones = get_cstr_zones(cli->cstr, result,
- &(result->nbase_zones));
-
- if (result->base_zones == NULL) {
- trpz_pemsg(emsg, "no valid policy zone specified");
- clear_all_updates(result);
- free(result);
- return (false);
- }
-
- if (apply_all_updates(result) < 0) {
- trpz_pemsg(emsg, "internal error loading test data 1");
- clear_all_updates(result);
- free(result->base_zones);
- free(result);
- return (false);
- }
-
- *rspp = (librpz_rsp_t *)result;
-
- return (true);
-}
-
-bool
-trpz_rsp_push(librpz_emsg_t *emsg, librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
-
- UNUSED(emsg);
-
- if (trsp->stack_idx == 0) {
- memset(&(trsp->rstack[0]), 0, sizeof(trsp->rstack[0]) * 2);
- trsp->stack_idx++;
- return (true);
- } else if (trsp->stack_idx >= LIBRPZ_RSP_STACK_DEPTH) {
- return (false);
- }
-
- memmove(&(trsp->rstack[1]), &(trsp->rstack[0]),
- (trsp->stack_idx * sizeof(trsp->rstack[0])));
- trsp->stack_idx++;
-
- return (true);
-}
-
-bool
-trpz_rsp_pop(librpz_emsg_t *emsg, librpz_result_t *result, librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
-
- UNUSED(emsg);
-
- if (trsp->stack_idx <= 1) {
- return (false);
- }
-
- memmove(&(trsp->rstack[0]), &(trsp->rstack[1]),
- ((trsp->stack_idx - 1) * sizeof(trsp->rstack[0])));
- memmove(result, &(trsp->rstack[0].result), sizeof(*result));
- trsp->stack_idx--;
-
- return (true);
-}
-
-bool
-trpz_rsp_pop_discard(librpz_emsg_t *emsg, librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
-
- UNUSED(emsg);
-
- if (trsp->stack_idx == 0) {
- return (false);
- } else if (trsp->stack_idx == 1) {
- return (true);
- }
-
- if (trsp->stack_idx > 1) {
- memmove(&(trsp->rstack[1]), &(trsp->rstack[2]),
- ((trsp->stack_idx - 2) * sizeof(trsp->rstack[0])));
- }
-
- trsp->stack_idx--;
-
- return (true);
-}
-
-void
-trpz_rsp_detach(librpz_rsp_t **rspp) {
- if (rspp != NULL && *rspp != NULL) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)*rspp;
- *rspp = NULL;
- clear_all_updates(trsp);
- if (trsp->base_zones != NULL) {
- free(trsp->base_zones);
- }
- free(trsp);
- }
-
- return;
-}
-
-bool
-trpz_rsp_domain(librpz_emsg_t *emsg, librpz_domain_buf_t *owner,
- librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
- const char *tstr = "";
- char tmpname[256] = { 0 };
- size_t osz = 0;
- uint32_t n;
-
- if (rsp == NULL) {
- trpz_pemsg(emsg, "rsp was NULL");
- return (false);
- } else if (trsp->stack_idx == 0) {
- trpz_pemsg(emsg, "domain not found [1]");
- return (false);
- } else if (trsp->rstack[0].result.policy == LIBRPZ_POLICY_UNDEFINED) {
- trpz_pemsg(emsg, "domain not found [2]");
- return (false);
- }
-
- if (trsp->all_zones[trsp->rstack[0].result.dznum].forgotten) {
- trpz_pemsg(emsg, "domain not found [3]");
- memset(owner, 0, sizeof(*owner));
- return (true);
- }
-
- switch (trsp->rstack[0].result.trig) {
- case LIBRPZ_TRIG_CLIENT_IP:
- tstr = "rpz-client-ip.";
- break;
- case LIBRPZ_TRIG_IP:
- tstr = "rpz-ip.";
- break;
- case LIBRPZ_TRIG_NSDNAME:
- tstr = "rpz-nsdname.";
- break;
- case LIBRPZ_TRIG_NSIP:
- tstr = "rpz-nsip.";
- break;
- default:
- break;
- }
-
- n = snprintf(tmpname, sizeof(tmpname), "%s.%s%s", trsp->rstack[0].dname,
- tstr, trsp->all_zones[trsp->rstack[0].result.dznum].name);
- if (n > sizeof(tmpname)) {
- trpz_pemsg(emsg, "%s truncated", tmpname);
- return (false);
- }
-
- if (!domain_pton2(tmpname, owner->d, sizeof(owner->d), &osz, true)) {
- trpz_pemsg(emsg, "unable to read hostname from rsp!");
- return (false);
- }
-
- owner->size = osz;
- return (true);
-}
-
-bool
-trpz_rsp_result(librpz_emsg_t *emsg, librpz_result_t *result, bool recursed,
- const librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
-
- UNUSED(recursed);
-
- if (rsp == NULL) {
- trpz_pemsg(emsg, "rsp was NULL!");
- return (false);
- } else if (result == NULL) {
- trpz_pemsg(emsg, "result was NULL");
- return (false);
- }
-
- if (trsp->stack_idx == 0) {
- memset(result, 0, sizeof(*result));
- result->policy = LIBRPZ_POLICY_UNDEFINED;
- } else {
- if (trsp->rstack[0].result.policy && trsp->rstack[0].nrrs &&
- (trsp->rstack[0].result.policy != LIBRPZ_POLICY_DISABLED))
- {
- trsp->rstack[0].result.next_rr =
- trsp->rstack[0].rrs[0].rrn;
- }
-
- trsp->rstack[0].rridx = 0;
-
- memmove(result, &(trsp->rstack[0].result), sizeof(*result));
-
- if (result->policy && trsp->rstack[0].poverride) {
- result->policy = trsp->rstack[0].poverride;
- }
- }
-
- return (true);
-}
-
-bool
-trpz_rsp_soa(librpz_emsg_t *emsg, uint32_t *ttlp, librpz_rr_t **rrp,
- librpz_domain_buf_t *origin, librpz_result_t *result,
- librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
- librpz_rr_t *rres = NULL;
- rpz_soa_t tmpsoa;
- unsigned char *rdbuf = NULL;
- char tmp_rname[1024] = { 0 };
- size_t rdlen = 0;
-
- UNUSED(ttlp);
-
- if (result == NULL) {
- trpz_pemsg(emsg, "result was NULL!");
- return (false);
- } else if (rsp == NULL) {
- trpz_pemsg(emsg, "rsp was NULL!");
- return (false);
- }
-
- if (trsp->zidx >= trsp->num_zones) {
- trpz_pemsg(emsg, "bad zone");
- return (false);
- }
-
- rdbuf = calloc(1024, 1);
- if (rdbuf == NULL) {
- trpz_pemsg(emsg, "calloc: %s", strerror(errno));
- return (false);
- }
-
- rres = (librpz_rr_t *)rdbuf;
-
- rres->type = htons(6);
- rres->class = htons(1);
- rres->ttl = htonl(60);
-
- memmove(&tmpsoa, &g_soa_record, sizeof(tmpsoa));
- tmpsoa.serial = trsp->all_zones[result->dznum].serial;
- tmpsoa.mname = trsp->all_zones[result->dznum].name;
-
- snprintf(tmp_rname, sizeof(tmp_rname) - 1, "hostmaster.ns.%s",
- tmpsoa.mname);
- tmpsoa.rname = tmp_rname;
-
- if (tmpsoa.serial == 0) {
- tmpsoa.serial = time(NULL);
- }
-
- if (!pack_soa_record(rres->rdata, 1024 - sizeof(*rres), &rdlen,
- &tmpsoa))
- {
- trpz_pemsg(emsg, "Error packing SOA reply");
- free(rdbuf);
- return (false);
- }
-
- rres->rdlength = htons(rdlen);
-
- if (origin != NULL) {
- uint8_t *buf = NULL;
- int nbytes;
-
- if ((nbytes = wdns_str_to_name(tmpsoa.mname, &buf, 1)) < 0) {
- trpz_pemsg(emsg, "Error packing domain");
- free(rdbuf);
- return (false);
- }
-
- memset(origin, 0, sizeof(*origin));
- memmove(origin->d, buf, nbytes);
- origin->size = nbytes;
- free(buf);
- }
-
- if (rrp != NULL) {
- *rrp = rres;
- } else {
- free(rdbuf);
- }
-
- return (true);
-}
-
-/*
- * Compare a query domain against a record, allowing for the possibility of
- * a wildcard match.
- */
-static int
-domain_cmp(const char *query, const char *record, bool *wildp) {
- const char *end = NULL;
- size_t cmplen;
-
- end = record + strlen(record);
-
- cmplen = end - record;
-
- *wildp = false;
-
- if (record != NULL && *record == '*' && record[1] == '.') {
- const char *rptr = record + 2;
-
- if ((cmplen - 2) < strlen(query)) {
- const char *qptr = NULL;
-
- qptr = query + strlen(query) - (cmplen - 2);
-
- if (strncmp(qptr, rptr, (cmplen - 2)) == 0) {
- *wildp = true;
- return (0);
- }
- }
- }
-
- if (strlen(query) > cmplen) {
- return (1);
- } else if (strlen(query) < cmplen) {
- return (-1);
- }
-
- return ((strncmp(record, query, cmplen)));
-}
-
-/*
- * Count the number of labels in the given domain name.
- */
-static size_t
-count_labels(const char *domain) {
- const char *dptr = NULL;
- size_t result = 1;
-
- if (domain == NULL || *domain == '\0') {
- return (0);
- }
-
- dptr = domain + strlen(domain);
-
- while (1) {
- while ((dptr >= domain) && (*dptr != '.')) {
- dptr--;
- }
-
- if (dptr <= domain) {
- break;
- }
-
- result++;
- dptr--;
- }
-
- return (result);
-}
-
-/*
- * Does the newly found result supercede the old result in precedence?
- * This function is used to determine whether a match on the result stack
- * should be overwritten by another match of higher precedence - or whether
- * the old match should remain, as-is.
- *
- * 1. "CNAME or DNAME Chain Position" Precedence Rule
- * 2. "RPZ Ordering" Precedence Rule [zone order]
- * 3. "Domain Name Matching" Precedence Rule [QNAME/NSDNAME - label count]
- * 4. "Trigger Type" Precedence Rule
- * 5. "Name Order" Precedence Rule [NSDNAME]
- * 6. "Prefix Length" Precedence Rule
- * 7. "IP Address Order" Precedence Rule
- */
-static bool
-result_supercedes(const trpz_result_t *new, const trpz_result_t *old) {
- size_t nsz, osz;
-
- if (old == NULL || old->result.policy == 0 || old->dname == NULL ||
- old->dname[0] == '\0')
- {
- return (true);
- }
-
- if (new->result.dznum < old->result.dznum) {
- return (true);
- } else if (new->result.dznum > old->result.dznum) {
- return (false);
- }
-
- nsz = count_labels(new->dname);
- osz = count_labels(old->dname);
-
- /* More matching labels is better. */
- if (nsz > osz) {
- return (true);
- } else if (nsz < osz) {
- return (false);
- }
-
- if (new->result.trig < old->result.trig) {
- return (true);
- } else if (new->result.trig > old->result.trig) {
- return (false);
- }
-
- return (true);
-}
-
-static bool
-result_supercedes_address(const trpz_result_t *new, const trpz_result_t *old) {
- if (old == NULL || old->result.policy == 0 || old->dname == NULL ||
- old->dname[0] == '\0')
- {
- return (true);
- }
-
- if (new->result.dznum < old->result.dznum) {
- return (true);
- } else if (new->result.dznum > old->result.dznum) {
- return (false);
- }
-
- if (new->result.trig < old->result.trig) {
- return (true);
- } else if (new->result.trig > old->result.trig) {
- return (false);
- }
-
- if ((new->flags &NODE_FLAG_IPV6_ADDRESS) &&
- !(old->flags & NODE_FLAG_IPV6_ADDRESS))
- {
- return (true);
- }
-
- /*
- * XXX: this is broken. Needs proper address comparison. For
- * example, by most specific prefix match.
- */
- if (strcmp(old->dname, new->dname) < 0) {
- return (false);
- }
-
- return (true);
-}
-
-bool
-trpz_ck_domain(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) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
- char dname[256] = { 0 };
- librpz_trig_t toverride = LIBRPZ_TRIG_BAD;
- ssize_t fidx = -1, nfidx = -1;
- bool wild;
- size_t n;
-
- if (rsp == NULL) {
- trpz_pemsg(emsg, "rsp was NULL!");
- return (false);
- } else if (domain == NULL || domain_size == 0) {
- trpz_pemsg(emsg, "domain was empty");
- return (false);
- } else if (trig != LIBRPZ_TRIG_QNAME && trig != LIBRPZ_TRIG_NSDNAME) {
- trpz_pemsg(emsg, "invalid trigger type");
- return (false);
- } else if (!domain_ntop(domain, dname, sizeof(dname))) {
- trpz_pemsg(emsg, "domain was invalid");
- return (false);
- }
-
- if (trsp->stack_idx == 0) {
- trsp->stack_idx = 1;
- }
-
- for (n = 0; n < trsp->num_nodes; n++) {
- int pos = 0;
-
- if (!trsp->have_rd &&
- !trsp->all_zones[trsp->all_nodes[n].result.dznum]
- .not_recursive_only)
- {
- continue;
- }
-
- if (pos ||
- ((trig == trsp->all_nodes[n].result.trig) &&
- (!domain_cmp(dname, trsp->all_nodes[n].dname, &wild))))
- {
- if ((trsp->all_zones[trsp->all_nodes[n].result.dznum]
- .no_qname_wait_recurse ||
- trsp->all_zones[trsp->all_nodes[n].result.dznum]
- .not_recursive_only ||
- recursed) &&
- has_base_zone(trsp,
- trsp->all_nodes[n].result.dznum) &&
- !trsp->all_zones[trsp->all_nodes[n].result.dznum]
- .forgotten)
- {
- if (fidx < 0) {
- fidx = n;
- toverride = LIBRPZ_TRIG_BAD;
- }
- }
- if (!wild) {
- break;
- }
-
- /*
- * Some inelegant special handling for qname_as_ns
- * feature.
- */
- } else if (trsp->all_zones[trsp->all_nodes[n].result.dznum]
- .qname_as_ns &&
- (((trig == LIBRPZ_TRIG_QNAME) &&
- (trsp->all_nodes[n].result.trig ==
- LIBRPZ_TRIG_NSDNAME)) ||
- ((trig == LIBRPZ_TRIG_NSDNAME) &&
- (trsp->all_nodes[n].result.trig ==
- LIBRPZ_TRIG_QNAME))))
- {
- if (!domain_cmp(dname, trsp->all_nodes[n].dname, &wild))
- {
- if (recursed &&
- has_base_zone(
- trsp,
- trsp->all_nodes[n].result.dznum) &&
- !trsp->all_zones[trsp->all_nodes[n]
- .result.dznum]
- .forgotten)
- {
- if (fidx < 0) {
- fidx = n;
- toverride = trig;
- }
- }
- if (!wild) {
- break;
- }
- }
- }
- }
-
- if (!trsp->have_rd && (fidx < 0) && (nfidx < 0)) {
- goto out;
- }
-
- if (recursed && (fidx < 0) && trsp->rstack[0].hidden_policy) {
- if (trsp->rstack[0].result.trig <= trig) {
- trsp->rstack[0].result.policy =
- trsp->rstack[0].hidden_policy;
- trsp->rstack[0].result.zpolicy =
- trsp->rstack[0].hidden_policy;
- trsp->rstack[0].hidden_policy = LIBRPZ_POLICY_UNDEFINED;
- return (true);
- }
- }
-
- if (fidx >= 0) {
- bool disabled = false;
-
- if (!result_supercedes(&(trsp->all_nodes[fidx]),
- &(trsp->rstack[0])))
- {
- return (true);
- }
-
- strncpy(trsp->domain, dname, sizeof(trsp->domain));
- memmove(&(trsp->rstack[0]), &(trsp->all_nodes[fidx]),
- sizeof(trsp->rstack[0]));
- trsp->rstack[0].result.hit_id = hit_id;
- trsp->last_zone = trsp->rstack[0].result.dznum;
-
- if (trsp->all_zones[trsp->rstack[0].result.dznum].flags) {
- unsigned long flags =
- trsp->all_zones[trsp->rstack[0].result.dznum]
- .flags;
- librpz_policy_t force_policy = 0;
-
- if (flags & ZOPT_POLICY_NODATA) {
- force_policy = LIBRPZ_POLICY_NODATA;
- } else if (flags & ZOPT_POLICY_PASSTHRU) {
- force_policy = LIBRPZ_POLICY_PASSTHRU;
- } else if (flags & ZOPT_POLICY_NXDOMAIN) {
- force_policy = LIBRPZ_POLICY_NXDOMAIN;
- } else if (flags & ZOPT_POLICY_DROP) {
- force_policy = LIBRPZ_POLICY_DROP;
- } else if (flags & ZOPT_POLICY_TCP_ONLY) {
- force_policy = LIBRPZ_POLICY_TCP_ONLY;
- } else if (flags & ZOPT_POLICY_DISABLED) {
- disabled = true;
- }
-
- if (force_policy) {
- trsp->rstack[0].result.policy = force_policy;
- trsp->rstack[0].result.zpolicy = force_policy;
- trsp->rstack[0].poverride = force_policy;
- }
- }
-
- if (toverride) {
- trsp->rstack[0].result.trig = toverride;
- }
-
- if (disabled) {
- trsp->rstack[0].poverride = LIBRPZ_POLICY_DISABLED;
- } else if (!recursed) {
- ssize_t m;
-
- /*
- * If recursed is not set, then an earlier zone of
- * higher precedence may not contain a rule of
- * trigger types rpz-ip, rpz-nsip, or rpz-nsdname -
- * which are by nature post-recursion rules.
- */
- for (m = trsp->all_nodes[fidx].result.dznum - 1; m >= 0;
- m--)
- {
- if (trsp->all_zones[m]
- .has_triggers[0][LIBRPZ_TRIG_IP] ||
- trsp->all_zones[m]
- .has_triggers[1][LIBRPZ_TRIG_IP] ||
- trsp->all_zones[m]
- .has_triggers[0][LIBRPZ_TRIG_NSIP] ||
- trsp->all_zones[m]
- .has_triggers[1][LIBRPZ_TRIG_NSIP] ||
- trsp->all_zones[m]
- .has_triggers[0]
- [LIBRPZ_TRIG_NSDNAME])
- {
- trsp->rstack[0].result.policy =
- LIBRPZ_POLICY_UNDEFINED;
- break;
- }
- }
- }
-
- return (true);
- } else if (nfidx >= 0) {
- strncpy(trsp->domain, dname, sizeof(trsp->domain));
- memmove(&(trsp->rstack[0]), &(trsp->all_nodes[nfidx]),
- sizeof(trsp->rstack[0]));
- trsp->last_zone = trsp->all_nodes[nfidx].result.dznum;
- trsp->rstack[0].hidden_policy = trsp->rstack[0].result.policy;
- trsp->rstack[0].result.hit_id = hit_id;
- trsp->rstack[0].result.policy = LIBRPZ_POLICY_UNDEFINED;
- trsp->rstack[0].result.zpolicy = LIBRPZ_POLICY_UNDEFINED;
- return (true);
- }
-
-out:
- if (trsp->rstack[0].result.policy == LIBRPZ_POLICY_UNDEFINED) {
- memset(&(trsp->rstack[0]), 0, sizeof(trsp->rstack[0]));
- }
-
- return (true);
-}
-
-static void
-rpzify_ipv6_str(char *buf) {
- char tmpb[512] = { 0 }, *tptr = NULL;
-
- strncpy(tmpb, buf, sizeof(tmpb) - 1);
- memset(buf, 0, strlen(buf));
- tptr = tmpb + strlen(tmpb);
-
- strcat(buf, "128.");
-
- while (tptr > tmpb) {
- if (*tptr == ':') {
- strcat(buf, tptr + 1);
- strcat(buf, ".");
- }
-
- tptr--;
-
- if ((*tptr == ':') && (tptr[0] == tptr[1])) {
- strcat(buf, "zz");
- }
-
- if (tptr[1] == ':') {
- tptr[1] = 0;
- }
- }
-
- strcat(buf, tptr);
-
- return;
-}
-
-static uint32_t
-get_mask(unsigned char prefix) {
- uint32_t result = 0;
- unsigned char n;
-
- if (prefix == 0) {
- return (0);
- } else if (prefix >= 32) {
- return (~(0));
- }
-
- for (n = 1; n < prefix; n++) {
- result |= (1 << n);
- }
-
- return (result);
-}
-
-/* XXX: this is broken for handling subnet masks in IPv6. */
-static int
-address_cmp(const char *addrstr, const void *addr, uint family,
- unsigned int *pmask) {
- char abuf[256] = { 0 };
- int ipstr[8] = { 0 };
- unsigned int nmask = 32;
-
- if (family == AF_INET6) {
- if (inet_ntop(AF_INET6, addr, abuf, sizeof(abuf)) == 0) {
- return (-1);
- }
-
- rpzify_ipv6_str(abuf);
- } else if (family == AF_INET) {
- char newstr[32] = { 0 };
- in_addr_t a1, a2;
-
- if (sscanf(addrstr, "%d.%d.%d.%d.%d", &ipstr[0], &ipstr[1],
- &ipstr[2], &ipstr[3], &ipstr[4]) == 5)
- {
- nmask = ipstr[0];
- if (nmask > 32) {
- return (-1);
- }
- } else if (sscanf(addrstr, "%d.%d.%d.%d", &ipstr[1], &ipstr[2],
- &ipstr[3], &ipstr[4]) != 4)
- {
- perror("bad address format");
- return (-1);
- }
-
- if (ipstr[1] > 255 || ipstr[2] > 255 || ipstr[3] > 255 ||
- ipstr[4] > 255 || ipstr[1] < 0 || ipstr[2] < 0 ||
- ipstr[3] < 0 || ipstr[4] < 0)
- {
- perror("bad address format");
- return (-1);
- }
-
- sprintf(newstr, "%u.%u.%u.%u", ipstr[4], ipstr[3], ipstr[2],
- ipstr[1]);
-
- a1 = inet_addr(newstr);
- if (a1 == INADDR_NONE) {
- perror("inet_addr");
- return (-1);
- } else {
- uint32_t m;
-
- memmove(&a2, addr, sizeof(uint32_t));
- m = get_mask(nmask);
-
- if (pmask != NULL) {
- *pmask = nmask;
- }
-
- return (((a1 & m) == (a2 & m)) ? 0 : 1);
- }
-
- } else {
- return (-1);
- }
-
- if (strcmp(addrstr, abuf) == 0) {
- if (pmask != NULL) {
- *pmask = nmask;
- }
-
- return (0);
- }
-
- return (1);
-}
-
-bool
-trpz_ck_ip(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) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
- size_t n, last_mask = 0;
- ssize_t fidx = -1, nfidx = -1;
-
- if (rsp == NULL) {
- trpz_pemsg(emsg, "rsp was NULL!");
- return (false);
- } else if (addr == NULL) {
- trpz_pemsg(emsg, "addr was empty");
- return (false);
- } else if (trig != LIBRPZ_TRIG_IP && trig != LIBRPZ_TRIG_CLIENT_IP &&
- trig != LIBRPZ_TRIG_NSIP)
- {
- trpz_pemsg(emsg, "trigger type not supported for IP");
- return (false);
- }
-
- if (trsp->stack_idx == 0) {
- trsp->stack_idx = 1;
- }
-
- /* The final match is the most specifically-matching netmask. */
- for (n = 0; n < trsp->num_nodes; n++) {
- unsigned int mask = 0;
- bool amatch = false;
-
- if (!trsp->have_rd &&
- !trsp->all_zones[trsp->all_nodes[n].result.dznum]
- .not_recursive_only)
- {
- continue;
- }
-
- if (trsp->all_zones[trsp->all_nodes[n].result.dznum].ip_as_ns &&
- (((trig == LIBRPZ_TRIG_IP) &&
- (trsp->all_nodes[n].result.trig == LIBRPZ_TRIG_NSIP)) ||
- ((trig == LIBRPZ_TRIG_NSIP) &&
- (trsp->all_nodes[n].result.trig == LIBRPZ_TRIG_IP))) &&
- !address_cmp(trsp->all_nodes[n].dname, addr, family, &mask))
- {
- amatch = true;
- } else if (trsp->all_nodes[n].match_trig != trig) {
- continue;
- }
-
- if (amatch ||
- !address_cmp(trsp->all_nodes[n].dname, addr, family, &mask))
- {
- if ((trsp->all_zones[trsp->all_nodes[n].result.dznum]
- .no_qname_wait_recurse ||
- trsp->all_zones[trsp->all_nodes[n].result.dznum]
- .not_recursive_only ||
- recursed) &&
- has_base_zone(trsp,
- trsp->all_nodes[n].result.dznum) &&
- !trsp->all_zones[trsp->all_nodes[n].result.dznum]
- .forgotten)
- {
- if (mask > last_mask) {
- last_mask = mask;
- fidx = n;
- }
-
- } else if ((nfidx < 0) && !recursed &&
- has_base_zone(
- trsp,
- trsp->all_nodes[n].result.dznum) &&
- !trsp->all_zones[trsp->all_nodes[n]
- .result.dznum]
- .forgotten)
- {
- nfidx = n;
- }
- }
- }
-
- if (!trsp->have_rd && (fidx < 0) && (nfidx < 0)) {
- goto out;
- }
-
- if (recursed && (fidx < 0) && trsp->rstack[0].hidden_policy) {
- if (trsp->rstack[0].result.trig <= trig) {
- trsp->rstack[0].result.policy =
- trsp->rstack[0].hidden_policy;
- trsp->rstack[0].result.zpolicy =
- trsp->rstack[0].hidden_policy;
- trsp->rstack[0].hidden_policy = LIBRPZ_POLICY_UNDEFINED;
- return (true);
- }
- }
-
- if (fidx >= 0) {
- bool disabled = false;
-
- if (!result_supercedes_address(&(trsp->all_nodes[fidx]),
- &(trsp->rstack[0])))
- {
- return (true);
- }
-
- memmove(&(trsp->rstack[0]), &(trsp->all_nodes[fidx]),
- sizeof(trsp->rstack[0]));
- trsp->rstack[0].result.hit_id = hit_id;
- trsp->last_zone = trsp->rstack[0].result.dznum;
-
- if (trsp->all_zones[trsp->rstack[0].result.dznum].flags) {
- unsigned long flags =
- trsp->all_zones[trsp->rstack[0].result.dznum]
- .flags;
- librpz_policy_t force_policy = 0;
-
- if (flags & ZOPT_POLICY_NODATA) {
- force_policy = LIBRPZ_POLICY_NODATA;
- } else if (flags & ZOPT_POLICY_PASSTHRU) {
- force_policy = LIBRPZ_POLICY_PASSTHRU;
- } else if (flags & ZOPT_POLICY_NXDOMAIN) {
- force_policy = LIBRPZ_POLICY_NXDOMAIN;
- } else if (flags & ZOPT_POLICY_DROP) {
- force_policy = LIBRPZ_POLICY_DROP;
- } else if (flags & ZOPT_POLICY_TCP_ONLY) {
- force_policy = LIBRPZ_POLICY_TCP_ONLY;
- } else if (flags & ZOPT_POLICY_DISABLED) {
- disabled = true;
- }
-
- if (force_policy) {
- trsp->rstack[0].result.policy = force_policy;
- trsp->rstack[0].result.zpolicy = force_policy;
- trsp->rstack[0].poverride = force_policy;
- }
- }
-
- if (disabled) {
- trsp->rstack[0].poverride = LIBRPZ_POLICY_DISABLED;
- }
-
- return (true);
- } else if (nfidx >= 0) {
- memmove(&(trsp->rstack[0]), &(trsp->all_nodes[nfidx]),
- sizeof(trsp->rstack[0]));
- trsp->last_zone = trsp->rstack[0].result.dznum;
- trsp->rstack[0].result.hit_id = hit_id;
- trsp->rstack[0].hidden_policy = trsp->rstack[0].result.policy;
- trsp->rstack[0].result.policy = LIBRPZ_POLICY_UNDEFINED;
- trsp->rstack[0].result.zpolicy = LIBRPZ_POLICY_UNDEFINED;
- return (true);
- }
-
-out:
- if (trig == LIBRPZ_TRIG_NSIP) {
- bool needs_wait = false;
-
- for (n = 0; n < trsp->num_zones; n++) {
- if (trsp->all_zones[n].no_nsip_wait_recurse) {
- needs_wait = true;
- break;
- }
- }
-
- if (!needs_wait) {
- usleep(100);
- }
- }
-
- if (trsp->rstack[0].result.policy == LIBRPZ_POLICY_UNDEFINED) {
- memset(&(trsp->rstack[0]), 0, sizeof(trsp->rstack[0]));
- trsp->rstack[0].result.trig = trig;
- }
-
- return (true);
-}
-
-bool
-trpz_soa_serial(librpz_emsg_t *emsg, uint32_t *serialp, const char *domain_nm,
- librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
- size_t n, dlen;
-
- if (rsp == NULL) {
- trpz_pemsg(emsg, "rsp was NULL");
- return (false);
- } else if (domain_nm == NULL) {
- trpz_pemsg(emsg, "domain_nm was NULL");
- return (false);
- } else if (serialp == NULL) {
- trpz_pemsg(emsg, "serialp was NULL");
- return (false);
- }
-
- dlen = strlen(domain_nm);
-
- if (dlen > 0U && domain_nm[dlen - 1] == '.') {
- dlen--;
- }
-
- for (n = 0; n < trsp->num_zones; n++) {
- if (dlen != strlen(trsp->all_zones[n].name)) {
- continue;
- } else if (!has_base_zone(trsp, n)) {
- continue;
- }
-
- if ((strlen(trsp->all_zones[n].name) == dlen) &&
- (!strncmp(trsp->all_zones[n].name, domain_nm, dlen)))
- {
- if (!trsp->all_zones[n].serial) {
- trsp->all_zones[n].serial = time(NULL);
- }
-
- *serialp = trsp->all_zones[n].serial;
- return (true);
- }
- }
-
- trpz_pemsg(emsg, "zone not found");
- return (false);
-}
-
-static bool
-domain_ntop(const u_char *src, char *dst, size_t dstsiz) {
- const unsigned char *sptr = src;
- char *dptr = dst, *dend = dst + dstsiz;
-
- if (dst == NULL || dstsiz == 0) {
- return (false);
- }
-
- memset(dst, 0, dstsiz);
-
- while (*sptr) {
- if (((dptr + *sptr) > dend)) {
- return (false);
- }
-
- if (sptr != src) {
- *dptr++ = '.';
- }
-
- memmove(dptr, sptr + 1, *sptr);
- dptr += *sptr;
- sptr += *sptr;
- sptr++;
- }
-
- return (true);
-}
-
-static bool
-domain_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen,
- bool lower) {
- unsigned char *dptr = dst;
- const unsigned char *dend = dst + dstsiz;
- char *tmps = NULL, *tok = NULL, *tptr = NULL;
-
- UNUSED(lower);
-
- if (src == NULL || dst == NULL || dstsiz == 0) {
- return (false);
- }
-
- memset(dst, 0, dstsiz);
-
- tmps = strdup(src);
- if (tmps == NULL) {
- perror("strdup");
- return (false);
- }
-
- tptr = tmps;
-
- SET_IF_NOT_NULL(dstlen, 0);
-
- while (tptr && *tptr) {
- tok = strsep(&tptr, ".");
-
- if (((dptr + strlen(tok) + 1) > dend)) {
- free(tmps);
- return (false);
- }
-
- *dptr++ = strlen(tok);
- memmove(dptr, tok, strlen(tok));
- dptr += strlen(tok);
-
- if (dstlen != NULL) {
- (*dstlen) += (1 + strlen(tok));
- }
- }
-
- if (dptr >= dend) {
- free(tmps);
- return (false);
- }
-
- *dptr = 0;
-
- if (dstlen != NULL) {
- (*dstlen)++;
- }
-
- free(tmps);
-
- return (true);
-}
-
-/* XXX: needs IPv6 support. */
-bool
-trpz_rsp_clientip_prefix(librpz_emsg_t *emsg, librpz_prefix_t *prefix,
- librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
- unsigned int cbytes[5] = { 0 };
- uint8_t *aptr = NULL;
-
- if (rsp == NULL) {
- trpz_pemsg(emsg, "rsp was NULL");
- return (false);
- } else if (prefix == NULL) {
- trpz_pemsg(emsg, "prefix was NULL");
- return (false);
- }
-
- memset(prefix, 0, sizeof(*prefix));
-
- if (trsp->rstack[0].result.trig != LIBRPZ_TRIG_CLIENT_IP) {
- return (true);
- }
-
- if (sscanf(trsp->rstack[0].dname, "%u.%u.%u.%u.%u", &cbytes[0],
- &cbytes[1], &cbytes[2], &cbytes[3], &cbytes[4]) != 5)
- {
- char abuf[64] = { 0 };
- int family = 0;
-
- if (sscanf(trsp->rstack[0].dname, "%u.", &cbytes[0]) != 1) {
- return (true);
- }
-
- if (get_address_info(trsp->rstack[0].dname, &family, abuf, NULL,
- NULL) < 0)
- {
- return (true);
- } else if (family != AF_INET6) {
- return (true);
- }
-
- aptr = (uint8_t *)&(prefix->addr.in6);
- memset(aptr, 0, sizeof(prefix->addr.in6));
-
- if (inet_pton(AF_INET6, abuf, aptr) != 1) {
- return (true);
- }
-
- prefix->family = AF_INET6;
- prefix->len = cbytes[0];
-
- return (true);
- }
-
- prefix->family = AF_INET;
- prefix->len = cbytes[0];
-
- if (prefix->len <= 24) {
- cbytes[1] = 0;
- }
-
- if (prefix->len <= 16) {
- cbytes[2] = 0;
- }
-
- if (prefix->len == 86) {
- cbytes[3] = 0;
- }
-
- aptr = (uint8_t *)&(prefix->addr.in);
- *aptr++ = cbytes[4];
- *aptr++ = cbytes[3];
- *aptr++ = cbytes[2];
- *aptr++ = cbytes[1];
-
- return (true);
-}
-
-bool
-trpz_have_trig(librpz_trig_t trig, bool ipv6, const librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
- size_t ind = ipv6 ? 1 : 0;
-
- if (rsp == NULL) {
- return (false);
- }
-
- /* No hit, so look in all zones for trigger. */
- if (trsp->stack_idx == 0 || trsp->rstack[0].result.policy == 0) {
- ssize_t max_z = (trsp->last_zone >= 0)
- ? trsp->last_zone
- : (ssize_t)trsp->num_zones - 0;
-
- for (ssize_t n = 0; n < max_z; n++) {
- if (!trsp->have_rd &&
- !trsp->all_zones[n].not_recursive_only)
- {
- continue;
- } else if (trsp->all_zones[n].has_triggers[ind][trig]) {
- return (true);
- } else if (trsp->all_zones[n].ip_as_ns &&
- (((trig == LIBRPZ_TRIG_IP) &&
- trsp->all_zones[n]
- .has_triggers[ind]
- [LIBRPZ_TRIG_NSIP]) ||
- ((trig == LIBRPZ_TRIG_NSIP) &&
- trsp->all_zones[n]
- .has_triggers[ind]
- [LIBRPZ_TRIG_IP])))
- {
- return (true);
- } else if (trsp->all_zones[n].qname_as_ns &&
- (((trig == LIBRPZ_TRIG_QNAME) &&
- trsp->all_zones[n].has_triggers
- [ind][LIBRPZ_TRIG_NSDNAME]) ||
- ((trig == LIBRPZ_TRIG_NSDNAME) &&
- trsp->all_zones[n]
- .has_triggers[ind]
- [LIBRPZ_TRIG_QNAME])))
- {
- return (true);
- }
- }
-
- return (false);
- }
-
- /* Special case of first base zone. */
- if (trsp->rstack[0].result.dznum == 0 &&
- (trig > trsp->rstack[0].result.trig))
- {
- return (false);
- }
-
- /* Otherwise check lower zones (of higher precedence). */
- for (size_t n = 0; n <= (trsp->rstack[0].result.dznum); n++) {
- if (!trsp->have_rd && !trsp->all_zones[n].not_recursive_only) {
- continue;
- } else if (trsp->all_zones[n].has_triggers[ind][trig]) {
- return (true);
- } else if (trsp->all_zones[n].ip_as_ns &&
- (((trig == LIBRPZ_TRIG_IP) &&
- trsp->all_zones[n]
- .has_triggers[ind][LIBRPZ_TRIG_NSIP]) ||
- ((trig == LIBRPZ_TRIG_NSIP) &&
- trsp->all_zones[n]
- .has_triggers[ind][LIBRPZ_TRIG_IP])))
- {
- return (true);
- } else if (trsp->all_zones[n].qname_as_ns &&
- (((trig == LIBRPZ_TRIG_QNAME) &&
- trsp->all_zones[n]
- .has_triggers[ind][LIBRPZ_TRIG_NSDNAME]) ||
- ((trig == LIBRPZ_TRIG_NSDNAME) &&
- trsp->all_zones[n]
- .has_triggers[ind][LIBRPZ_TRIG_QNAME])))
- {
- return (true);
- }
- }
-
- return (false);
-}
-
-bool
-trpz_rsp_rr(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) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
- trpz_result_t *last_result = NULL;
-
- if (result == NULL) {
- trpz_pemsg(emsg, "result was NULL");
- return (false);
- } else if (rsp == NULL) {
- trpz_pemsg(emsg, "rsp was NULL");
- return (false);
- }
-
- last_result = &(trsp->rstack[0]);
-
- if (last_result->rridx < last_result->nrrs) {
- trpz_rr_t *this_rr = &(last_result->rrs[last_result->rridx]);
-
- if (classp != NULL) {
- *classp = this_rr->class;
- }
-
- if (ttlp != NULL) {
- *ttlp = 3600;
- }
-
- SET_IF_NOT_NULL(typep, this_rr->type);
-
- if (rrp != NULL) {
- uint8_t *copy_src = NULL, *nrdata = NULL;
- size_t to_copy, needed;
-
- copy_src = this_rr->rdata;
- to_copy = this_rr->rdlength;
-
- /* If there's CNAME wild card expansion */
- if (qname != NULL && qname_size != 0 &&
- (this_rr->type == T_CNAME) &&
- (this_rr->rdlength > 2))
- {
- if (this_rr->rdata[0] == 1 &&
- this_rr->rdata[1] == '*')
- {
- char tmpexp[256] = { 0 },
- tmpexp2[256] = { 0 }, tmpexp3[256];
-
- wdns_domain_to_str(this_rr->rdata,
- this_rr->rdlength,
- tmpexp);
- wdns_domain_to_str(qname, qname_size,
- tmpexp2);
-
- if (tmpexp2[strlen(tmpexp2) - 1] == '.')
- {
- tmpexp2[strlen(tmpexp2) - 1] =
- 0;
- }
-
- if (strncmp(tmpexp, "*.", 2) == 0) {
- int nrd;
- uint32_t n = snprintf(
- tmpexp3,
- sizeof(tmpexp3),
- "%s.%s", tmpexp2,
- &tmpexp[2]);
- if (n > sizeof(tmpexp3)) {
- trpz_pemsg(
- emsg,
- "%s truncated",
- tmpexp3);
- return (false);
- }
- nrd = wdns_str_to_name(
- tmpexp3, &nrdata, 1);
- if (nrd < 0) {
- trpz_pemsg(
- emsg,
- "Error packing "
- "domain");
- return (false);
- }
- to_copy = nrd;
- copy_src = nrdata;
- }
- }
- }
-
- needed = sizeof(**rrp) + to_copy;
-
- *rrp = calloc(1, needed);
- if (*rrp == NULL) {
- trpz_pemsg(emsg, "calloc: %s", strerror(errno));
- if (nrdata != NULL) {
- free(nrdata);
- }
- return (false);
- }
-
- (*rrp)->type = htons(this_rr->type);
- (*rrp)->class = htons(this_rr->class);
- (*rrp)->ttl = htonl(this_rr->ttl);
- (*rrp)->rdlength = htons(to_copy);
- memmove((*rrp)->rdata, copy_src, to_copy);
- if (nrdata != NULL) {
- free(nrdata);
- }
- }
-
- result->next_rr = this_rr->rrn;
- trsp->rstack[0].result.next_rr = this_rr->rrn;
- last_result->rridx++;
- } else {
- SET_IF_NOT_NULL(typep, 0);
-
- if (rrp != NULL) {
- *rrp = NULL;
- }
-
- result->next_rr = 0;
- trsp->rstack[0].result.next_rr = 0;
- }
-
- return (true);
-}
-
-bool
-trpz_rsp_forget_zone(librpz_emsg_t *emsg, librpz_cznum_t znum,
- librpz_rsp_t *rsp) {
- trpz_rsp_t *trsp = (trpz_rsp_t *)rsp;
-
- if (znum >= trsp->num_zones) {
- trpz_pemsg(emsg, "invalid zone number");
- return (false);
- } else if (trsp->all_zones[znum].forgotten) {
- trpz_pemsg(emsg, "zone already forgotten");
- return (false);
- }
-
- trsp->all_zones[znum].forgotten = true;
-
- return (true);
-}
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * 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 https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*
- * Limited implementation of the DNSRPS API for testing purposes.
- *
- * 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.
- */
-
-#define _GNU_SOURCE 1
-#include <arpa/inet.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#ifdef HAVE_ARPA_NAMESER_COMPAT_H
-#include <arpa/nameser_compat.h>
-#endif /* HAVE_ARPA_NAMESER_COMPAT_H */
-
-#include <isc/atomic.h>
-#include <isc/util.h>
-
-#include "test-data.h"
-
-const rpz_soa_t g_soa_record = { "a.rpz-ns.dns-nod.net",
- "nod-admin.fsi.io",
- 12345,
- 3600,
- 1200,
- 604800,
- 60 };
-
-int
-wdns_str_to_name(const char *str, uint8_t **pbuf, bool downcase);
-
-static char *
-str_printf(const char *fmt, ...) {
- va_list ap;
- char tbuf[8192], *result = NULL;
-
- va_start(ap, fmt);
- vsnprintf(tbuf, sizeof(tbuf) - 1, fmt, ap);
- tbuf[sizeof(tbuf) - 1] = 0;
- va_end(ap);
-
- result = strdup(tbuf);
- if (result == NULL) {
- perror("strdup");
- }
-
- return (result);
-}
-
-/*
- * Given a config-ready RPZ IP address, determine its family and normal
- * canonical representation.
- */
-int
-get_address_info(const char *astr, int *pfamily, char *pbuf,
- const char *optname, char **errp) {
- char tmpc[512] = { 0 };
- char *tok = NULL, *tptr = tmpc, *last_tok = NULL;
- size_t lcount = 0, bcount = 0;
- unsigned int prefix = 0, values[16] = { 0 }, hex_values[16] = { 0 };
- bool is_ipv6 = false;
-
- if (astr == NULL || pfamily == NULL || pbuf == NULL) {
- return (-1);
- }
-
- strncpy(tmpc, astr, sizeof(tmpc) - 1);
-
- while ((tok = strsep(&tptr, "."))) {
- char *eptr = NULL;
- unsigned long val;
-
- lcount++;
- last_tok = tok;
-
- errno = 0;
- val = strtoul(tok, &eptr, 10);
-
- if (errno != 0 || *eptr != '\0') {
- bool bad = false;
-
- bcount++;
- errno = 0;
- eptr = NULL;
- val = strtoul(tok, &eptr, 16);
-
- if (errno || *eptr != '\0') {
- if (strcmp(tok, "zz") == 0) {
- val = ~0;
- is_ipv6 = true;
- } else {
- bad = true;
- }
- }
-
- if (!bad && (lcount > 1)) {
- hex_values[lcount - 2] = val;
- }
- } else {
- if (val > 255) {
- bcount++;
- }
-
- if (lcount == 1) {
- prefix = val;
- } else if (lcount > 1) {
- unsigned int hexval;
- values[lcount - 2] = val;
-
- /*
- * All integer strings are valid hex
- * strings, but decimal values are longer,
- * so we have to check for overflow when
- * reading as hex.
- */
- errno = 0;
- hexval = strtoul(tok, &eptr, 16);
- if (errno != 0) {
- return (-1);
- }
- hex_values[lcount - 2] = hexval;
- }
- }
- }
-
- if (last_tok && (strncmp(last_tok, "rpz-", 4) == 0)) {
- lcount--;
- bcount--;
- }
-
- /* Not acceptable for either address family. */
- if (lcount > 9) {
- return (-1);
- }
-
- *pfamily = (!is_ipv6 && (lcount == 5)) ? AF_INET : AF_INET6;
-
- /*
- * For AF_INET we expect exactly 4 "good" (0<->255) octets and the
- * subnet mask.
- */
- if (*pfamily == AF_INET) {
- if (prefix > 32) {
- if (errp != NULL) {
- *errp = str_printf(
- "invalid rpz IP address \"%s\"; "
- "invalid prefix length of %u",
- (optname ? optname : astr), prefix);
- }
-
- return (-1);
- } else if (bcount > 0) {
- return (-1);
- }
-
- sprintf(pbuf, "%u.%u.%u.%u", values[3], values[2], values[1],
- values[0]);
- } else {
- size_t n;
-
- if (prefix > 128) {
- if (errp != NULL) {
- *errp = str_printf(
- "invalid rpz IP address \"%s\"; "
- "invalid prefix length of %u",
- (optname ? optname : astr), prefix);
- }
-
- return (-1);
- }
-
- *pbuf = 0;
-
- /*
- * Walk the values backward. Account for :: and discard
- * chunks > 2 octets.
- */
- for (n = lcount - 1; n > 0; n--) {
- if (hex_values[n - 1] == ~0U) {
- strcat(pbuf, ":");
- } else {
- if (hex_values[n - 1] > 0xffff) {
- return (-1);
- } else if (n > 1) {
- sprintf(&pbuf[strlen(pbuf)],
- "%x:", hex_values[n - 1]);
- } else {
- sprintf(&pbuf[strlen(pbuf)], "%x",
- hex_values[n - 1]);
- }
- }
- }
- }
-
- return (0);
-}
-
-rpz_soa_t *
-parse_serial(unsigned char *rdata, size_t rdlen) {
- rpz_soa_t *result = NULL;
- char dname[WDNS_PRESLEN_NAME];
- size_t mlen, rlen;
- uint32_t *uptr = NULL;
-
- result = calloc(1, sizeof(*result));
- if (result == NULL) {
- perror("calloc");
- return (NULL);
- }
-
- mlen = wdns_domain_to_str(rdata, rdlen, dname);
- result->mname = strdup(dname);
- rlen = wdns_domain_to_str(rdata + mlen, rdlen - mlen, dname);
- result->rname = strdup(dname);
- uptr = (uint32_t *)(rdata + mlen + rlen);
- result->serial = ntohl(*uptr);
- uptr++;
- result->refresh = ntohl(*uptr);
- uptr++;
- result->retry = ntohl(*uptr);
- uptr++;
- result->expire = ntohl(*uptr);
- uptr++;
- result->minimum = ntohl(*uptr);
-
- return (result);
-}
-
-size_t
-wdns_domain_to_str(const uint8_t *src, size_t src_len, char *dst) {
- size_t bytes_read = 0;
- size_t bytes_remaining = src_len;
- uint8_t oclen;
-
- if (src == NULL) {
- return (0);
- }
-
- oclen = *src;
- while (bytes_remaining > 0 && oclen != 0) {
- src++;
- bytes_remaining--;
-
- bytes_read += oclen + 1 /* length octet */;
-
- while (oclen-- && bytes_remaining > 0) {
- uint8_t c = *src++;
- bytes_remaining--;
-
- if (c == '.' || c == '\\') {
- *dst++ = '\\';
- *dst++ = c;
- } else if (c >= '!' && c <= '~') {
- *dst++ = c;
- } else {
- snprintf(dst, 5, "\\%.3d", c);
- dst += 4;
- }
- }
- *dst++ = '.';
- oclen = *src;
- }
- if (bytes_read == 0) {
- *dst++ = '.';
- }
- bytes_read++;
-
- *dst = '\0';
- return ((bytes_read));
-}
-
-/* Add parsed update specification to maintained list of nodes. */
-static trpz_result_t *
-apply_update_to_set(trpz_result_t **results, size_t *pnresults,
- trpz_zone_t **pzones, const char *node, size_t zidx,
- uint32_t ttl, librpz_trig_t trigger, librpz_policy_t policy,
- int *modified, unsigned long flags, char **errp) {
- size_t n;
- int family = 0;
-
- UNUSED(flags);
-
- *modified = 0;
-
- switch (trigger) {
- case LIBRPZ_TRIG_QNAME:
- case LIBRPZ_TRIG_NSDNAME:
- (*pzones)[zidx].has_triggers[0][trigger] = 1;
- break;
- case LIBRPZ_TRIG_CLIENT_IP:
- case LIBRPZ_TRIG_IP:
- case LIBRPZ_TRIG_NSIP: {
- char abuf[128];
-
- if (get_address_info(node, &family, abuf, NULL, errp) < 0) {
- fprintf(stderr,
- "Error in determining IP address type: %s\n",
- node);
- return (NULL);
- } else if (family == AF_INET) {
- (*pzones)[zidx].has_triggers[0][trigger] = 1;
- } else {
- (*pzones)[zidx].has_triggers[1][trigger] = 1;
- }
-
- } break;
- default:
- break;
- }
-
- for (n = 0; n < *pnresults; n++) {
- trpz_result_t *rptr = &((*results)[n]);
-
- if (rptr->result.cznum != zidx) {
- continue;
- }
-
- if (!strcmp(rptr->dname, node)) {
- if (rptr->result.trig == trigger &&
- rptr->result.policy == policy && rptr->ttl == ttl)
- {
- return (rptr);
- }
-
- rptr->result.trig = trigger;
- rptr->result.policy = policy;
- rptr->result.zpolicy = policy;
- rptr->ttl = ttl;
- *modified = 1;
- return (rptr);
- }
- }
-
- /* No match. Instead, append. */
- (*pnresults)++;
-
- *results = realloc(*results, (*pnresults * sizeof(**results)));
- if (*results == NULL) {
- perror("realloc");
- return (NULL);
- }
-
- memset(&((*results)[*pnresults - 1]), 0, sizeof(**results));
- (*results)[*pnresults - 1].dname = strdup(node);
- (*results)[*pnresults - 1].ttl = ttl;
- (*results)[*pnresults - 1].result.trig = trigger;
- (*results)[*pnresults - 1].result.policy = policy;
- (*results)[*pnresults - 1].result.zpolicy = policy;
- (*results)[*pnresults - 1].result.cznum = zidx;
- (*results)[*pnresults - 1].result.dznum = zidx;
- (*results)[*pnresults - 1].result.log = 1;
- (*results)[*pnresults - 1].poverride = policy;
- (*results)[*pnresults - 1].match_trig = trigger;
-
- if (family == AF_INET6) {
- (*results)[*pnresults - 1].flags |= NODE_FLAG_IPV6_ADDRESS;
- }
-
- *modified = 1;
- return ((&((*results)[*pnresults - 1])));
-}
-
-/*
- * Add a parsed RR value that is maintained in conjunction with record policy
- * items.
- */
-static int
-add_other_rr(trpz_result_t *node, const char *rrtype, const char *val,
- uint32_t ttl, int *modified) {
- trpz_rr_t nrec = { 0 };
- size_t n;
- static atomic_uint_fast32_t rrn = 1;
-
- *modified = 0;
-
- nrec.class = C_IN;
- nrec.ttl = ttl;
- nrec.rrn = atomic_fetch_add_relaxed(&rrn, 1);
-
- if (!strcasecmp(rrtype, "A")) {
- uint32_t addr;
-
- if (inet_pton(AF_INET, val, &addr) != 1) {
- fprintf(stderr,
- "Error determining policy record IPv4 address: "
- "%s\n",
- val);
- return (-1);
- }
-
- nrec.type = T_A;
- nrec.rdlength = sizeof(uint32_t);
-
- nrec.rdata = malloc(nrec.rdlength);
- if (nrec.rdata == NULL) {
- perror("malloc");
- exit(EXIT_FAILURE);
- }
-
- memmove(nrec.rdata, &addr, nrec.rdlength);
- } else if (!strcasecmp(rrtype, "AAAA")) {
- char addr[16] = { 0 };
-
- if (inet_pton(AF_INET6, val, addr) != 1) {
- fprintf(stderr,
- "Error determining policy record IPv6 address: "
- "%s\n",
- val);
- return (-1);
- }
-
- nrec.type = T_AAAA;
- nrec.rdlength = sizeof(addr);
-
- nrec.rdata = malloc(nrec.rdlength);
- if (nrec.rdata == NULL) {
- perror("malloc");
- exit(EXIT_FAILURE);
- }
-
- memmove(nrec.rdata, addr, nrec.rdlength);
- } else if (!strcasecmp(rrtype, "TXT")) {
- nrec.type = T_TXT;
- nrec.rdlength = 1 + strlen(val);
-
- nrec.rdata = calloc(nrec.rdlength, 1);
- if (nrec.rdata == NULL) {
- perror("calloc");
- exit(EXIT_FAILURE);
- }
-
- nrec.rdata[0] = nrec.rdlength - 1;
- memmove(&(nrec.rdata[1]), val, nrec.rdlength - 1);
- } else if (!strcasecmp(rrtype, "CNAME")) {
- int ret;
-
- nrec.type = T_CNAME;
- ret = wdns_str_to_name(val, &(nrec.rdata), 1);
-
- if (ret <= 0) {
- fprintf(stderr,
- "Error processing CNAME policy record data "
- "(%d)!\n",
- ret);
- return (-1);
- }
-
- nrec.rdlength = ret;
- } else if (!strcasecmp(rrtype, "DNAME")) {
- int ret;
-
- nrec.type = T_DNAME;
- ret = wdns_str_to_name(val, &(nrec.rdata), 1);
-
- if (ret <= 0) {
- fprintf(stderr,
- "Error processing DNAME policy record data "
- "(%d)!\n",
- ret);
- return (-1);
- }
-
- nrec.rdlength = ret;
- } else {
- fprintf(stderr,
- "Error: unsupported policy record type: \"%s\"\n",
- rrtype);
- return (-1);
- }
-
- for (n = 0; n < node->nrrs; n++) {
- trpz_rr_t *rptr = &(node->rrs[n]);
-
- /* Same thing. Don't replace. */
- if (rptr->type == nrec.type && rptr->class == nrec.class &&
- rptr->ttl == nrec.ttl && rptr->rdlength == nrec.rdlength &&
- !memcmp(rptr->rdata, nrec.rdata, nrec.rdlength))
- {
- free(nrec.rdata);
- return (n + 1);
- }
- }
-
- node->nrrs++;
-
- node->rrs = realloc(node->rrs, (node->nrrs * sizeof(*(node->rrs))));
- if (node->rrs == NULL) {
- perror("realloc");
- exit(EXIT_FAILURE);
- }
-
- memset(&(node->rrs[node->nrrs - 1]), 0, sizeof(node->rrs[0]));
- node->rrs[node->nrrs - 1] = nrec;
- *modified = 1;
-
- return (node->nrrs);
-}
-
-void
-reverse_labels(const char *str, char *pbuf) {
- const char *sptr = str, *end = NULL;
-
- if (sptr == NULL || *sptr == 0) {
- return;
- }
-
- sptr += (strlen(sptr) - 1);
- end = sptr + 1;
- *pbuf = 0;
-
- if (*sptr == '.') {
- sptr--;
- end--;
- }
-
- while (sptr >= str) {
- if ((*sptr != '.') && (sptr != str)) {
- sptr--;
- continue;
- }
-
- if (sptr == str) {
- strncat(pbuf, sptr, (end - sptr));
- break;
- }
-
- strncat(pbuf, sptr + 1, (end - (sptr + 1)));
- strcat(pbuf, ".");
- end = sptr--;
- }
-
- if (pbuf[strlen(pbuf) - 1] == '.') {
- pbuf[strlen(pbuf) - 1] = 0;
- }
-
- return;
-}
-
-/* Parse trailing zone options as specified in a cstr line */
-unsigned long
-parse_zone_options(const char *str) {
- char tmpstr[8192] = { 0 };
- char *tok = NULL, *sptr = NULL;
- unsigned long result = 0;
-
- if (str == NULL || *str == 0) {
- return (0);
- }
-
- strncpy(tmpstr, str, sizeof(tmpstr) - 1);
-
- tok = strtok_r(tmpstr, " ", &sptr);
-
- while (tok) {
- if (!strcasecmp(tok, "policy")) {
- tok = strtok_r(NULL, " ", &sptr);
- if (tok == NULL) {
- break;
- }
-
- if (!strcasecmp(tok, "passthru")) {
- result |= ZOPT_POLICY_PASSTHRU;
- } else if (!strcasecmp(tok, "drop")) {
- result |= ZOPT_POLICY_DROP;
- } else if (!strcasecmp(tok, "tcp-only")) {
- result |= ZOPT_POLICY_TCP_ONLY;
- } else if (!strcasecmp(tok, "nxdomain")) {
- result |= ZOPT_POLICY_NXDOMAIN;
- } else if (!strcasecmp(tok, "nodata")) {
- result |= ZOPT_POLICY_NODATA;
- } else if (!strcasecmp(tok, "given")) {
- result |= ZOPT_POLICY_GIVEN;
- } else if (!strcasecmp(tok, "disabled")) {
- result |= ZOPT_POLICY_DISABLED;
- } else if (!strcasecmp(tok, "no-op")) {
- ;
- }
- } else {
- if (!strcasecmp(tok, "max-policy-ttl")) {
- tok = strtok_r(NULL, " ", &sptr);
- if (tok == NULL) {
- break;
- }
- } else if (!strcasecmp(tok, "recursive-only")) {
- tok = strtok_r(NULL, " ", &sptr);
- if (tok == NULL) {
- break;
- }
-
- if (!strcasecmp(tok, "yes")) {
- result |= ZOPT_RECURSIVE_ONLY;
- } else if (!strcasecmp(tok, "no")) {
- result |= ZOPT_NOT_RECURSIVE_ONLY;
- }
-
- } else {
- if (!strcasecmp(tok, "qname-as-ns")) {
- tok = strtok_r(NULL, " ", &sptr);
- if (tok == NULL) {
- break;
- }
-
- if (!strcasecmp(tok, "yes")) {
- result |= ZOPT_QNAME_AS_NS;
- }
-
- } else if (!strcasecmp(tok, "ip-as-ns")) {
- tok = strtok_r(NULL, " ", &sptr);
- if (tok == NULL) {
- break;
- }
-
- if (!strcasecmp(tok, "yes")) {
- result |= ZOPT_IP_AS_NS;
- }
-
- } else if (!strcasecmp(tok,
- "qname-wait-recurse"))
- {
- tok = strtok_r(NULL, " ", &sptr);
- if (tok == NULL) {
- break;
- }
-
- if (!strcasecmp(tok, "no")) {
- result |=
- ZOPT_NO_QNAME_WAIT_RECURSE;
- }
-
- } else if (!strcasecmp(tok,
- "nsip-wait-recurse"))
- {
- tok = strtok_r(NULL, " ", &sptr);
- if (tok == NULL) {
- break;
- }
-
- if (!strcasecmp(tok, "no")) {
- result |=
- ZOPT_NO_NSIP_WAIT_RECURSE;
- }
- }
- }
- }
-
- tok = strtok_r(NULL, " ", &sptr);
- }
-
- /* LIBRPZ_POLICY_CNAME, */
- return (result);
-}
-
-/*
- * Parse an update string and attempt to add any relevant data to the node
- * and policy RR tables.
- */
-int
-apply_update(const char *updstr, trpz_result_t **presults, size_t *pnresults,
- trpz_zone_t **pzones, size_t *pnzones, int is_static,
- unsigned long flags, char **errp) {
- trpz_result_t *res = NULL;
- char cmdbuf[64] = { 0 }, nodebuf[256] = { 0 }, rrbuf[32] = { 0 },
- databuf[256] = { 0 };
- char *nend = NULL;
- librpz_policy_t policy = LIBRPZ_POLICY_UNDEFINED;
- librpz_trig_t trig = LIBRPZ_TRIG_QNAME;
- unsigned int ttl;
- ssize_t n, zidx = -1;
- size_t ndlen = 0, last_matchlen = 0;
- int nfield, zupd = 0;
-
- nfield = sscanf(updstr, "%63s %255s %u %31s %255s", cmdbuf, nodebuf,
- &ttl, rrbuf, databuf);
- if (nfield < 1) {
- return (-1);
- }
-
- /*
- * Special case for handling zone additions; here the 'ttl' field
- * becomes a serial.
- */
- if (!strcasecmp(cmdbuf, "zone")) {
- trpz_zone_t *zptr = NULL;
- bool qname_as_ns = false, ip_as_ns = false,
- not_recursive_only = false, do_inc = false;
- bool no_qname_as_ns = false, no_ip_as_ns = false,
- recursive_only = false, no_nsip_wait_recurse = false;
-
- if (nfield < 3) {
- return (-1);
- }
-
- if (!strcasecmp(rrbuf, "qname_as_ns")) {
- qname_as_ns = true;
- } else if (!strcasecmp(rrbuf, "ip_as_ns")) {
- ip_as_ns = true;
- } else if (!strcasecmp(rrbuf, "not_recursive_only")) {
- not_recursive_only = true;
- } else if (!strcasecmp(rrbuf, "inc")) {
- do_inc = true;
- } else if (!strcasecmp(rrbuf, "no_qname_as_ns")) {
- no_qname_as_ns = true;
- } else if (!strcasecmp(rrbuf, "no_ip_as_ns")) {
- no_ip_as_ns = true;
- } else if (!strcasecmp(rrbuf, "recursive_only")) {
- recursive_only = true;
- } else if (!strcasecmp(rrbuf, "no_nsip_wait_recurse")) {
- no_nsip_wait_recurse = true;
- }
-
- if (flags & ZOPT_RECURSIVE_ONLY) {
- recursive_only = true;
- not_recursive_only = false;
- } else if (flags & ZOPT_NOT_RECURSIVE_ONLY) {
- recursive_only = false;
- not_recursive_only = true;
- }
-
- if (flags & ZOPT_NO_NSIP_WAIT_RECURSE) {
- no_nsip_wait_recurse = true;
- }
-
- for (n = 0; (size_t)n < *pnzones; n++) {
- if (!strcmp((*pzones)[n].name, nodebuf)) {
- /*
- * Force override of serial. But only if
- * serial is non-zero.
- */
- if (ttl) {
- if (do_inc) {
- (*pzones)[n].serial += ttl;
- } else {
- (*pzones)[n].serial = ttl;
- }
- }
-
- (*pzones)[n].has_update = 0;
-
- if (qname_as_ns) {
- (*pzones)[n].qname_as_ns = true;
- }
-
- if (ip_as_ns) {
- (*pzones)[n].ip_as_ns = true;
- }
-
- if (no_qname_as_ns) {
- (*pzones)[n].qname_as_ns = false;
- }
-
- if (no_ip_as_ns) {
- (*pzones)[n].ip_as_ns = false;
- }
-
- if (not_recursive_only) {
- (*pzones)[n].not_recursive_only = true;
- }
-
- if (recursive_only) {
- (*pzones)[n].not_recursive_only = false;
- }
-
- if (flags & ZOPT_NO_QNAME_WAIT_RECURSE) {
- (*pzones)[n].no_qname_wait_recurse =
- true;
- }
-
- if (no_nsip_wait_recurse) {
- (*pzones)[n].no_nsip_wait_recurse =
- true;
- }
-
- return (0);
- }
- }
-
- (*pnzones)++;
-
- *pzones = realloc(*pzones, (*pnzones * sizeof(**pzones)));
- if (*pzones == NULL) {
- perror("realloc");
- exit(EXIT_FAILURE);
- }
-
- zptr = &(*pzones)[*pnzones - 1];
- *zptr = (trpz_zone_t){
- .serial = ttl,
- .qname_as_ns = qname_as_ns,
- .ip_as_ns = ip_as_ns,
- .flags = flags,
- .not_recursive_only = not_recursive_only,
- };
-
- if (qname_as_ns) {
- (*pzones)[n].qname_as_ns = true;
- }
-
- if (ip_as_ns) {
- (*pzones)[n].ip_as_ns = true;
- }
-
- if (flags & ZOPT_NO_QNAME_WAIT_RECURSE) {
- (*pzones)[n].no_qname_wait_recurse = true;
- }
-
- if (no_nsip_wait_recurse) {
- (*pzones)[n].no_nsip_wait_recurse = true;
- }
-
- strncpy(zptr->name, nodebuf, LIBRPZ_MAXDOMAIN + 1);
- if (zptr->name[strlen(zptr->name) - 1] == '.') {
- zptr->name[strlen(zptr->name) - 1] = 0;
- }
-
- return (0);
- } else if (nfield != 5) {
- return (-1);
- }
-
- if (strcasecmp(cmdbuf, "add")) {
- fprintf(stderr, "Warning: only update add action is currently "
- "supported!\n");
- return (-1);
- }
-
- if (!strcasecmp(rrbuf, "A")) {
- policy = LIBRPZ_POLICY_RECORD;
- } else if (!strcasecmp(rrbuf, "CNAME")) {
- if (!strcmp(databuf, ".")) {
- policy = LIBRPZ_POLICY_NXDOMAIN;
- } else if (!strcmp(databuf, "*.")) {
- policy = LIBRPZ_POLICY_NODATA;
- } else if (!strcasecmp(databuf, "rpz-passthru.")) {
- policy = LIBRPZ_POLICY_PASSTHRU;
- } else if (!strcasecmp(databuf, "rpz-drop.")) {
- policy = LIBRPZ_POLICY_DROP;
- } else if (!strcasecmp(databuf, "rpz-tcp-only.")) {
- policy = LIBRPZ_POLICY_TCP_ONLY;
- } else {
- policy = LIBRPZ_POLICY_RECORD;
- }
-
- } else if (!strcasecmp(rrbuf, "TXT")) {
- char *ftext = NULL;
-
- ftext = strstr(updstr, databuf);
- if (ftext == NULL) {
- fprintf(stderr, "Error parsing TXT record: \"%s\"\n",
- updstr);
- return (-1);
- }
-
- if (*ftext == '"') {
- *ftext++ = 0;
-
- if (ftext[strlen(ftext) - 1] == '"') {
- ftext[strlen(ftext) - 1] = 0;
- }
- }
-
- strncpy(databuf, ftext, sizeof(databuf));
- databuf[sizeof(databuf) - 1] = 0;
- policy = LIBRPZ_POLICY_RECORD;
- } else if (!strcasecmp(rrbuf, "DNAME")) {
- policy = LIBRPZ_POLICY_RECORD;
- } else if (!strcasecmp(rrbuf, "AAAA")) {
- policy = LIBRPZ_POLICY_RECORD;
- } else {
- fprintf(stderr,
- "Warning: target \"%s\" is not currently supported!\n",
- rrbuf);
- return (-1);
- }
-
- if (policy == LIBRPZ_POLICY_UNDEFINED) {
- fprintf(stderr, "Error: could not determine appropriate policy "
- "for update!\n");
- return (-1);
- }
-
- for (n = 0; (size_t)n < *pnzones; n++) {
- const char *zptr = nodebuf;
- size_t cmplen;
-
- zptr += strlen(zptr) - 1;
-
- if (*zptr == '.') {
- zptr--;
- }
-
- cmplen = strlen((*pzones)[n].name);
-
- if ((*pzones)[n].name[cmplen - 1] == '.') {
- cmplen--;
- }
-
- zptr -= (cmplen - 1);
-
- if ((zptr <= nodebuf) || (*(zptr - 1) != '.')) {
- continue;
- }
-
- if (!strncmp((*pzones)[n].name, zptr, cmplen)) {
- /*
- * We don't break immediately after a match because
- * there might be a better one yet.
- */
- if (cmplen > last_matchlen) {
- ndlen = strlen(nodebuf) - cmplen;
-
- if (nodebuf[strlen(nodebuf) - 1] == '.') {
- ndlen--;
- }
-
- /*
- * Account for the period between the node name
- * and zone name.
- */
- ndlen--;
- zidx = n;
- last_matchlen = cmplen;
- }
- }
- }
-
- if (memmem(nodebuf, ndlen, ".rpz-", 5)) {
- char *tptr = nodebuf + ndlen - 1;
- size_t slen;
-
- while (strncmp(tptr, ".rpz-", 5)) {
- tptr--;
- }
-
- slen = nodebuf + ndlen - tptr;
- nend = tptr;
-
- if (slen == 7 && !memcmp(tptr, ".rpz-ip", 7)) {
- trig = LIBRPZ_TRIG_IP;
- } else if (slen == 9 && !memcmp(tptr, ".rpz-nsip", 9)) {
- trig = LIBRPZ_TRIG_NSIP;
- } else if (slen == 14 && !memcmp(tptr, ".rpz-client-ip", 14)) {
- trig = LIBRPZ_TRIG_CLIENT_IP;
- } else if (slen == 12 && !memcmp(tptr, ".rpz-nsdname", 12)) {
- trig = LIBRPZ_TRIG_NSDNAME;
- } else {
- fprintf(stderr, "Warning: unknown suffix \"%s\"\n",
- tptr);
- nend = NULL;
- }
-
- /* We saved the trigger value, so shave that part off. */
- *tptr = 0;
- }
-
- if (zidx == -1) {
- return (0);
- }
-
- nodebuf[ndlen] = 0;
-
- /*
- * The original, deprecated PASSTHRU encoding of a CNAME pointing
- * to the trigger QNAME might still be in use in local, private
- * policy zones, and so it is still recognized by RPZ subscriber
- * implementations as of 2016.
- */
- if ((policy == LIBRPZ_POLICY_RECORD) && !strcasecmp(rrbuf, "cname")) {
- char tmpname[512] = { 0 };
-
- strncpy(tmpname, databuf, sizeof(tmpname) - 1);
-
- if ((nodebuf[strlen(nodebuf) - 1] == '.') &&
- (tmpname[strlen(tmpname) - 1] != '.'))
- {
- size_t tlen = strlen(tmpname);
-
- tmpname[tlen] = '.';
- tmpname[tlen + 1] = 0;
- } else if ((nodebuf[strlen(nodebuf) - 1] != '.') &&
- (tmpname[strlen(tmpname) - 1] == '.'))
- {
- tmpname[strlen(tmpname) - 1] = 0;
- }
-
- /* A special case of PASSTHRU (with trailing characters) */
- if (nend != NULL &&
- (strlen(databuf) == (size_t)(nend - nodebuf)) &&
- !strncmp(databuf, nodebuf, (nend - nodebuf)))
- {
- policy = LIBRPZ_POLICY_PASSTHRU;
- }
-
- if (!strcmp(nodebuf, tmpname)) {
- policy = LIBRPZ_POLICY_PASSTHRU;
- }
- }
-
- res = apply_update_to_set(presults, pnresults, pzones, nodebuf, zidx,
- ttl, trig, policy, &zupd, flags, errp);
-
- if (res) {
- if (zupd && !is_static) {
- (*pzones)[zidx].has_update = 1;
- } else if (is_static) {
- res->flags |= NODE_FLAG_STATIC_DATA;
- }
-
- if (policy == LIBRPZ_POLICY_RECORD) {
- /*
- * Policy/RR change does not seem to prompt zone
- * serial increment. (has_update)
- */
- if (add_other_rr(res, rrbuf, databuf, ttl, &zupd) < 0) {
- fprintf(stderr,
- "Error: could not add policy record %s "
- "/ %s\n",
- rrbuf, databuf);
- return (-1);
- }
- }
- }
-
- return (0);
-}
-
-/*
- * XXX: memory leak. Also, does not properly preserve "static" node entries,
- * as envisioned.
- */
-static void
-free_nodes(trpz_result_t **presults, size_t *pnresults) {
- size_t n, tot;
-
- if (presults == NULL || *presults == NULL) {
- if (pnresults != NULL) {
- *pnresults = 0;
- }
- return;
- }
-
- tot = *pnresults;
-
- for (n = tot; n > 0; n--) {
- trpz_result_t *res = &((*presults)[n - 1]);
- size_t m;
-
- if (res->canonical != NULL) {
- free(res->canonical);
- }
-
- if (res->dname != NULL) {
- free(res->dname);
- }
-
- for (m = 0; m < res->nrrs; m++) {
- if (res->rrs[m].rdata != NULL) {
- free(res->rrs[m].rdata);
- }
- }
-
- if (res->rrs != NULL) {
- free(res->rrs);
- }
- }
-
- free(*presults);
- *presults = NULL;
- *pnresults = 0;
-
- return;
-}
-
-/*
- * Perform only sanity checking on a data file's contents.
- *
- * Note that this function only really exists to facilitate the logging of error
- * messages that may be expected to occur upon encounter with certain invalid
- * node data in unit tests.
- *
- * fname is the pathname of the data file to be checked.
- * errp is a pointer to an error string that may be set if this function fails.
- * It is the responsibility of the caller to free this pointer if it is returned
- * non-NULL.
- *
- * This function returns 0 on success, or -1 on failure, possibly setting *errp
- * on failure.
- */
-int
-sanity_check_data_file(const char *fname, char **errp) {
- FILE *f = NULL;
- int result = -1;
-
- SET_IF_NOT_NULL(errp, NULL);
-
- f = fopen(fname, "r");
- if (f == NULL) {
- fprintf(stderr, "couldn't sanity check %s\n", fname);
- perror("fopen");
- return (-1);
- }
-
- while (!feof(f)) {
- char line[1024] = { 0 }, cmdbuf[64] = { 0 },
- nodebuf[256] = { 0 }, rrbuf[32] = { 0 },
- databuf[256] = { 0 };
- char *lptr = line;
- int nfield;
- unsigned int ttl;
-
- if (!fgets(line, sizeof(line) - 1, f)) {
- break;
- }
-
- if (!line[0]) {
- continue;
- }
-
- if (line[strlen(line) - 1] == '\n') {
- line[strlen(line) - 1] = 0;
- }
-
- if (!line[0] || line[0] == ';') {
- continue;
- }
-
- while (*lptr && !isspace((unsigned char)*lptr)) {
- lptr++;
- }
-
- *lptr++ = 0;
-
- if (!strcasecmp(line, "server") || !strcasecmp(line, "send") ||
- !strcasecmp(line, "wipe") ||
- !strcasecmp(line, "rollback") ||
- !strcasecmp(line, "restart"))
- {
- continue;
- } else if (strcasecmp(line, "static") &&
- strcasecmp(line, "update"))
- {
- if (errp != NULL) {
- *errp = str_printf("Found unknown instruction "
- "directive: \"%s\"\n",
- line);
- }
-
- goto out;
- }
-
- while (isspace((unsigned char)*lptr)) {
- lptr++;
- }
-
- nfield = sscanf(lptr, "%63s %255s %u %31s %255s", cmdbuf,
- nodebuf, &ttl, rrbuf, databuf);
-
- /* We don't care about checking zones - only node entries. */
- if (nfield != 5) {
- continue;
- }
-
- if (strcasecmp(cmdbuf, "add")) {
- continue;
- }
-
- if (strcasecmp(rrbuf, "A") && strcasecmp(rrbuf, "CNAME") &&
- strcasecmp(rrbuf, "TXT") && strcasecmp(rrbuf, "DNAME") &&
- strcasecmp(rrbuf, "AAAA"))
- {
- if (errp != NULL) {
- *errp = str_printf("Target \"%s\" is not "
- "currently supported!\n",
- rrbuf);
- }
-
- goto out;
- }
-
- if (strstr(nodebuf, ".rpz-")) {
- char abuf[64], tmpname[512];
- char *tptr = nodebuf;
- size_t slen;
- int family;
-
- while (strncmp(tptr, ".rpz-", 5)) {
- tptr++;
- }
-
- slen = nodebuf + strlen(nodebuf) - tptr;
-
- if (!(slen >= 8 && !memcmp(tptr, ".rpz-ip.", 8)) &&
- !(slen >= 10 && !memcmp(tptr, ".rpz-nsip.", 10)) &&
- !(slen >= 15 &&
- !memcmp(tptr, ".rpz-client-ip.", 15)) &&
- !(slen >= 13 && !memcmp(tptr, ".rpz-nsdname.", 13)))
- {
- continue;
- }
-
- strncpy(tmpname, nodebuf, sizeof(tmpname) - 1);
- tmpname[sizeof(tmpname) - 1] = 0;
-
- *tptr = 0;
-
- if (get_address_info(nodebuf, &family, abuf, tmpname,
- errp) < 0)
- {
- goto out;
- }
- }
- }
-
- result = 0;
-
-out:
- fclose(f);
-
- return (result);
-}
-
-/* Load a database of nodes from a given filename. */
-int
-load_all_updates(const char *fname, trpz_result_t **presults, size_t *pnresults,
- trpz_zone_t **pzones, size_t *pnzones, char **errp) {
- FILE *f = NULL;
-
- f = fopen(fname, "r");
- if (f == NULL) {
- fprintf(stderr, "couldn't load updates from %s\n", fname);
- perror("fopen");
- return (-1);
- }
-
- while (!feof(f)) {
- char line[1024] = { 0 };
- char *lptr = line;
- int is_static = 0;
-
- if (!fgets(line, sizeof(line) - 1, f)) {
- break;
- }
-
- if (!line[0]) {
- continue;
- }
-
- if (line[strlen(line) - 1] == '\n') {
- line[strlen(line) - 1] = 0;
- }
-
- if (!line[0]) {
- strcpy(line, "send");
- }
-
- if (!line[0] || line[0] == ';') {
- continue;
- }
-
- while (*lptr && !isspace((unsigned char)*lptr)) {
- lptr++;
- }
-
- *lptr++ = 0;
-
- if (!strcasecmp(line, "server")) {
- continue;
- } else if (!strcasecmp(line, "send")) {
- size_t n;
-
- for (n = 0; n < *pnzones; n++) {
- if ((*pzones)[n].has_update) {
- (*pzones)[n].serial += 1;
- (*pzones)[n].rollback += 1;
- (*pzones)[n].has_update = 0;
- }
- }
-
- continue;
- } else if (!strcasecmp(line, "wipe") ||
- !strcasecmp(line, "rollback"))
- {
- size_t n;
- int rollback;
-
- rollback = strcasecmp(line, "rollback") == 0;
-
- free_nodes(presults, pnresults);
-
- /* Now push forward the serial by # rollback */
- for (n = 0; n < *pnzones; n++) {
- if (rollback) {
- (*pzones)[n].serial +=
- (*pzones)[n].rollback;
- (*pzones)[n].rollback = 0;
- }
-
- memset((*pzones)[n].has_triggers, 0,
- sizeof((*pzones)[n].has_triggers));
- }
-
- continue;
- } else if (!strcasecmp(line, "static")) {
- is_static = 1;
- } else if (!strcasecmp(line, "restart")) {
- size_t n;
-
- for (n = 0; n < *pnzones; n++) {
- (*pzones)[n].serial = 1;
- (*pzones)[n].rollback = 0;
- }
-
- continue;
- } else if (strcasecmp(line, "update")) {
- fprintf(stderr,
- "Warning: skipping unknown instruction "
- "directive: \"%s\"\n",
- line);
- continue;
- }
-
- /* Everything here is an update */
- while (isspace((unsigned char)*lptr)) {
- lptr++;
- }
-
- if (apply_update(lptr, presults, pnresults, pzones, pnzones,
- is_static, 0, errp) == -1)
- {
- fprintf(stderr,
- "Error: could not apply update \"%s\"\n", lptr);
- fclose(f);
- return (-1);
- }
- }
-
- fclose(f);
-
- return (0);
-}
-
-#define WDNS_MAXLEN_NAME 255
-int
-wdns_str_to_name(const char *str, uint8_t **pbuf, bool downcase) {
- const char *p = NULL;
- size_t label_len;
- ssize_t slen;
- uint8_t c, *oclen = NULL, *data = NULL;
- int res = -1;
-
- assert(pbuf != NULL);
-
- p = str;
- slen = strlen(str);
-
- if (slen == 1 && *p == '.') {
- *pbuf = malloc(1);
- if (*pbuf == NULL) {
- perror("malloc");
- exit(EXIT_FAILURE);
- }
- *pbuf[0] = 0;
- return (1);
- }
-
- res = 0;
- *pbuf = malloc(WDNS_MAXLEN_NAME);
- if (*pbuf == NULL) {
- perror("malloc");
- exit(EXIT_FAILURE);
- }
-
- data = *pbuf;
- label_len = 0;
- oclen = data++;
- res++;
-
- for (;;) {
- c = *p++;
- label_len++;
-
- /* Will the wire name become too long? */
- if (res >= WDNS_MAXLEN_NAME) {
- goto out;
- }
-
- if (slen == 0) {
- /* end of input */
- *oclen = --label_len;
- *data++ = '\0';
- res++;
- break;
- }
-
- if (c >= 'A' && c <= 'Z') {
- /* an upper case letter; downcase it */
- if (downcase) {
- c |= 0x20;
- }
- *data++ = c;
- res++;
- } else if (c == '\\' && !isdigit((unsigned char)*p)) {
- /* an escaped character */
- if (slen <= 0) {
- goto out;
- }
- *data++ = *p;
- res++;
- p++;
- slen--;
- } else if (c == '\\' && slen >= 3) {
- /* an escaped octet */
- char d[4];
- char *endptr = NULL;
- long int val;
-
- d[0] = *p++;
- d[1] = *p++;
- d[2] = *p++;
- d[3] = '\0';
- slen -= 3;
- if (!isdigit((unsigned char)d[0]) ||
- !isdigit((unsigned char)d[1]) ||
- !isdigit((unsigned char)d[2]))
- {
- goto out;
- }
- val = strtol(d, &endptr, 10);
- if (endptr != NULL && *endptr == '\0' && val >= 0 &&
- val <= 255)
- {
- uint8_t uval;
-
- uval = (uint8_t)val;
- *data++ = uval;
- res++;
- } else {
- goto out;
- }
- } else if (c == '\\') {
- /* should not occur */
- goto out;
- } else if (c == '.') {
- /* end of label */
- *oclen = --label_len;
- if (label_len == 0) {
- goto out;
- }
- oclen = data++;
- if (slen > 1) {
- res++;
- }
- label_len = 0;
- } else if (c != '\0') {
- *data++ = c;
- res++;
- }
-
- slen--;
- }
-
- return (res);
-
-out:
- free(*pbuf);
- *pbuf = NULL;
- return (-1);
-}
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * 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 https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*
- * Limited implementation of the DNSRPS API for testing purposes.
- *
- * 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.
- */
-
-#include <dns/librpz.h>
-
-#include "trpz.h"
-
-#define NODE_FLAG_IPV6_ADDRESS 0x1
-#define NODE_FLAG_STATIC_DATA 0x2
-
-#define ZOPT_POLICY_PASSTHRU 0x0001
-#define ZOPT_POLICY_DROP 0x0002
-#define ZOPT_POLICY_TCP_ONLY 0x0004
-#define ZOPT_POLICY_NXDOMAIN 0x0008
-#define ZOPT_POLICY_NODATA 0x0010
-#define ZOPT_POLICY_GIVEN 0x0020
-#define ZOPT_POLICY_DISABLED 0x0040
-
-#define ZOPT_RECURSIVE_ONLY 0x0100
-#define ZOPT_NOT_RECURSIVE_ONLY 0x0200
-#define ZOPT_QNAME_AS_NS 0x0400
-#define ZOPT_IP_AS_NS 0x0800
-
-#define ZOPT_QNAME_WAIT_RECURSE 0x1000
-#define ZOPT_NO_QNAME_WAIT_RECURSE 0x2000
-#define ZOPT_NO_NSIP_WAIT_RECURSE 0x4000
-
-typedef struct {
- char name[256];
- uint32_t serial;
- int has_update;
- size_t rollback;
- int has_triggers[2][LIBRPZ_TRIG_NSIP + 1];
- bool forgotten;
- bool qname_as_ns, ip_as_ns;
- bool not_recursive_only;
- bool no_qname_wait_recurse, no_nsip_wait_recurse;
- unsigned long flags;
-} trpz_zone_t;
-
-typedef struct {
- uint16_t type;
- uint16_t class;
- uint32_t ttl;
- uint16_t rdlength;
- uint8_t *rdata;
- unsigned int rrn;
-} trpz_rr_t;
-
-typedef struct {
- char *canonical;
- char *dname;
- librpz_result_t result;
- uint32_t ttl;
- trpz_rr_t *rrs;
- size_t nrrs, rridx;
- librpz_policy_t poverride, hidden_policy;
- unsigned long flags;
- librpz_trig_t match_trig;
-} trpz_result_t;
-
-#define DECL_NODE(canon, name, policy, znum, trig) \
- { canon, name, { 0, 0, policy, policy, znum, znum, trig, true } },
-
-#define NUM_ZONES_SNAPSHOT1 20
-
-extern const rpz_soa_t g_soa_record;
-
-#define WDNS_PRESLEN_NAME 1025
-extern size_t
-wdns_domain_to_str(const uint8_t *src, size_t src_len, char *dst);
-extern int
-wdns_str_to_name(const char *str, uint8_t **pbuf, bool downcase);
-
-extern void
-reverse_labels(const char *str, char *pbuf);
-
-extern rpz_soa_t *
-parse_serial(unsigned char *rdata, size_t rdlen);
-
-extern int
-load_all_updates(const char *fname, trpz_result_t **presults, size_t *pnresults,
- trpz_zone_t **pzones, size_t *pnzones, char **errp);
-extern int
-apply_update(const char *updstr, trpz_result_t **presults, size_t *pnresults,
- trpz_zone_t **pzones, size_t *pnzones, int is_static,
- unsigned long flags, char **errp);
-extern int
-sanity_check_data_file(const char *fname, char **errp);
-
-extern unsigned long
-parse_zone_options(const char *str);
-
-extern int
-get_address_info(const char *astr, int *pfamily, char *pbuf,
- const char *optname, char **errp);
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * 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 https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*
- * Limited implementation of the DNSRPS API for testing purposes.
- *
- * 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.
- */
-
-#ifndef TRPZ_H
-#define TRPZ_H
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#define TARGET_ZONE "rpz-test.example.com"
-
-/* This should be in the librpz.h include. */
-union socku {
- struct sockaddr sa;
- struct sockaddr_in ipv4;
- struct sockaddr_in6 ipv6;
- struct sockaddr_un sun;
-};
-
-typedef struct {
- const char *mname;
- const char *rname;
- uint32_t serial;
- uint32_t refresh;
- uint32_t retry;
- uint32_t expire;
- uint32_t minimum;
-} rpz_soa_t;
-
-#endif
# test response policy zones (RPZ)
-# touch dnsrps-off to not test with DNSRPS
-# touch dnsrps-only to not test with classic RPZ
-
. ../conf.sh
ns=10.53.0
status=0
t=0
-export DNSRPS_TEST_UPDATE_FILE=$(pwd)/dnsrps.cache
SAVE_RESULTS=
ARGS=
-if grep 'dnsrps-enable yes;' dnsrps.conf >/dev/null; then
- MODE=dnsrps
-else
- MODE=native
-fi
USAGE="$0: [-S]"
while getopts "S:" c; do
fi
}
-DNSRPSCMD=./dnsrps
RNDCCMD="$RNDC -c ../_common/rndc.conf -p ${CONTROLPORT} -s"
-if test -x "$DNSRPSCMD"; then
- 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
ret=1
status=$((status + 1))
echo_i "$*"
+ echo_i "failed"
}
# set $SN to the SOA serial number of a zone
# $1=domain
# $2=DNS server and client IP address
get_sn() {
- SOA=$($DIG -p ${PORT} +short +norecurse soa "$1" "@$2" "-b$2")
- SN=$(expr "$SOA" : '[^ ]* [^ ]* \([^ ]*\) .*' || true)
- test "$SN" != "" && return
- echo_i "no serial number from \`dig -p ${PORT} soa $1 @$2\` in \"$SOA\""
+ make_dignm
+ $DIG -p "${PORT}" +short +norecurse soa "$1" "@$2" "-b$2" >$DIGNM
+ SN=$(awk '{ print $3 }' <$DIGNM)
+ [ -n "$SN" ] && return
+ echo_i "no serial number from \`dig -p ${PORT} soa $1 @$2\`"
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 dnsrps provider has zones loaded
-# $1=domain
-# $2=DNS server IP address
-FZONES=$(sed -n -e 's/^zone "\(.*\)".*\(10.53.0..\).*/Z=\1;M=\2/p' dnsrps.zones)
-dnsrps_loaded() {
- test "$MODE" = dnsrps || return 0
- 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=$((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
+test_soa() {
+ get_sn "$2" "$3"
+ test "$SN" -eq "$1"
+}
+
ck_soa() {
- n=0
- while true; do
- if test "$MODE" = dnsrps; then
- get_sn_fast "$2"
- test "$RSN" -eq "$1" && return
- else
- get_sn "$2" "$3"
- test "$SN" -eq "$1" && return
- fi
- n=$((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
+ retry_quiet 10 test_soa "$@" && return 0
+ echo_i "got serial number \"$SN\" instead of \"$1\" from $2 @$3"
+ return 1
}
# (re)load the response policy zones with the rules in the file $TEST_FILE
if test -n "$TEST_FILE"; then
copy_setports $TEST_FILE tmp
- for ZONE in bl0 bl1 bl2 bl3 bl4 bl5 bl6 bl7 bl8 bl9 bl10 bl11 bl12 bl13 bl14 bl15 bl16 bl17 bl18 bl19; do
- produce_librpz_rules ns5 $ZONE bl
- done
-
- produce_librpz_rules ns2 bl.tld2 bl.tld2
- cat tmp >>$DNSRPS_TEST_UPDATE_FILE
-
if $NSUPDATE -v tmp; then
:
$RNDCCMD $ns3 sync
fi
start_server --noclean --restart --port ${PORT} ns$1
load_db
- dnsrps_loaded
sleep 1
}
eval "${NSDIR}_CNT=$NEW_CNT"
}
-add_librpz_rule() {
- echo $1 >>$DNSRPS_TEST_UPDATE_FILE
-}
-
-produce_librpz_rules() {
- # echo "Producing rules for $1"
- ZONEFILE=$1/$3.db
- cat $ZONEFILE | grep -E -v '^;' | grep -E '\<(A|CNAME)\>' | awk -v zone=$2 '{ if (NF == 4) {print "static add "$1"."zone" "$2" "$3" "$4} else if (NF == 3) {print "static add "$1"."zone" 300 "$2" "$3}}' >>$DNSRPS_TEST_UPDATE_FILE
-}
-
# $1=message
# $2=optional test file name
start_group() {
else
GROUP_NM=
fi
- dnsrps_loaded
TEST_NUM=0
}
if test -n "$TEST_FILE"; then
# remove the previous set of test rules
copy_setports $TEST_FILE tmp
- add_librpz_rule "rollback"
sed -e 's/[ ]add[ ]/ delete /' tmp | $NSUPDATE
rm -f tmp
TEST_FILE=
fi
ckalive $ns3 "failed; ns3 server crashed and restarted"
- dnsrps_loaded
GROUP_NM=
}
# updating an response zone policy
cp ns2/blv2.tld2.db.in ns2/bl.tld2.db
rndc_reload ns2 $ns2 bl.tld2
-add_librpz_rule "update zone bl.tld2 1 inc"
ck_soa 2 bl.tld2 $ns3
-add_librpz_rule "wipe"
-produce_librpz_rules ns2 bl.tld2 bl.tld2
nochange a7-1.tld2 # 19 PASSTHRU
# ensure that a clock tick has occurred so that named will do the reload
sleep 1
cp ns2/blv3.tld2.db.in ns2/bl.tld2.db
rndc_reload ns2 $ns2 bl.tld2
-# sleep again to let the reload finish
-sleep 1
-add_librpz_rule "update zone bl.tld2 1 inc"
ck_soa 3 bl.tld2 $ns3
-produce_librpz_rules ns2 bl.tld2 bl.tld2
+sleep 1 # there's an delay between "DNS" transfer and RPZ being active
nxdomain a7-1.tld2 # 20 secondary policy zone (RT34450)
end_group
ckstats $ns3 test2 ns3 12
ckstats $ns5 test5 ns5 4
# check that miscellaneous bugs are still absent
-add_librpz_rule "wipe"
start_group "crashes" test6
for Q in RRSIG SIG ANY 'ANY +dnssec'; do
nocrash a3-1.tld2 -t$Q
# restart the main test RPZ server to see if that creates a core file
if test -z "$HAVE_CORE"; then
stop_server --use-rndc --port ${CONTROLPORT} ns3
- add_librpz_rule "restart"
restart 3 "rebuild-bl-rpz"
HAVE_CORE=$(find ns* -name '*core*' -print)
test -z "$HAVE_CORE" || setret "found $HAVE_CORE; memory leak?"
fi
done
-if [ native = "$MODE" ]; then
- # restart the main test RPZ server with a bad zone.
- t=$((t + 1))
- echo_i "checking that ns3 with broken rpz does not crash (${t})"
- stop_server --use-rndc --port ${CONTROLPORT} ns3
- cp ns3/broken.db.in ns3/bl.db
- restart 3 # do not rebuild rpz zones
- nocrash a3-1.tld2 -tA
- stop_server --use-rndc --port ${CONTROLPORT} ns3
- restart 3 "rebuild-bl-rpz"
+# restart the main test RPZ server with a bad zone.
+t=$((t + 1))
+echo_i "checking that ns3 with broken rpz does not crash (${t})"
+stop_server --use-rndc --port ${CONTROLPORT} ns3
+cp ns3/broken.db.in ns3/bl.db
+restart 3 # do not rebuild rpz zones
+nocrash a3-1.tld2 -tA
+stop_server --use-rndc --port ${CONTROLPORT} ns3
+restart 3 "rebuild-bl-rpz"
- t=$((t + 1))
- echo_i "checking if rpz survives a certain class of failed reconfiguration attempts (${t})"
- sed -e "s/^#BAD//" <ns3/named.conf.in >ns3/named.conf.tmp
- copy_setports ns3/named.conf.tmp ns3/named.conf
- rm ns3/named.conf.tmp
- $RNDCCMD $ns3 reconfig >/dev/null 2>&1 && setret "failed"
- sleep 1
- copy_setports ns3/named.conf.in ns3/named.conf
- $RNDCCMD $ns3 reconfig || setret "failed"
+t=$((t + 1))
+echo_i "checking if rpz survives a certain class of failed reconfiguration attempts (${t})"
+sed -e "s/^#BAD//" <ns3/named.conf.in >ns3/named.conf.tmp
+copy_setports ns3/named.conf.tmp ns3/named.conf
+rm ns3/named.conf.tmp
+$RNDCCMD $ns3 reconfig >/dev/null 2>&1 && setret "failed"
+sleep 1
+copy_setports ns3/named.conf.in ns3/named.conf
+$RNDCCMD $ns3 reconfig || setret "failed"
- t=$((t + 1))
- echo_i "checking the configured extended DNS error code (EDE) (${t})"
- $DIG -p ${PORT} @$ns3 walled.tld2 >dig.out.$t || setret "failed"
- grep -F "EDE: 4 (Forged Answer)" dig.out.$t >/dev/null || setret "failed"
+t=$((t + 1))
+echo_i "checking the configured extended DNS error code (EDE) (${t})"
+$DIG -p ${PORT} @$ns3 walled.tld2 >dig.out.$t || setret "failed"
+grep -F "EDE: 4 (Forged Answer)" dig.out.$t >/dev/null || setret "failed"
- # reload a RPZ zone that is now deliberately broken.
- t=$((t + 1))
- echo_i "checking rpz failed update will keep previous rpz rules (${t})"
- $DIG -p ${PORT} @$ns3 walled.tld2 >dig.out.$t.before || setret "failed"
- grep "walled\.tld2\..*IN.*A.*10\.0\.0\.1" dig.out.$t.before >/dev/null || setret "failed"
- cp ns3/broken.db.in ns3/manual-update-rpz.db
- rndc_reload ns3 $ns3 manual-update-rpz
- sleep 1
- # ensure previous RPZ rules still apply.
- $DIG -p ${PORT} @$ns3 walled.tld2 >dig.out.$t.after || setret "failed"
- grep "walled\.tld2\..*IN.*A.*10\.0\.0\.1" dig.out.$t.after >/dev/null || setret "failed"
+# reload a RPZ zone that is now deliberately broken.
+t=$((t + 1))
+echo_i "checking rpz failed update will keep previous rpz rules (${t})"
+$DIG -p ${PORT} @$ns3 walled.tld2 >dig.out.$t.before || setret "failed"
+grep "walled\.tld2\..*IN.*A.*10\.0\.0\.1" dig.out.$t.before >/dev/null || setret "failed"
+cp ns3/broken.db.in ns3/manual-update-rpz.db
+rndc_reload ns3 $ns3 manual-update-rpz
+sleep 1
+# ensure previous RPZ rules still apply.
+$DIG -p ${PORT} @$ns3 walled.tld2 >dig.out.$t.after || setret "failed"
+grep "walled\.tld2\..*IN.*A.*10\.0\.0\.1" dig.out.$t.after >/dev/null || setret "failed"
- t=$((t + 1))
- echo_i "checking the default (unset) extended DNS error code (EDE) (${t})"
- $DIG -p ${PORT} @$ns3 a6-2.tld2. A >dig.out.$t || setret "failed"
- grep -F "EDE: " dig.out.$t >/dev/null && setret "failed"
+t=$((t + 1))
+echo_i "checking the default (unset) extended DNS error code (EDE) (${t})"
+$DIG -p ${PORT} @$ns3 a6-2.tld2. A >dig.out.$t || setret "failed"
+grep -F "EDE: " dig.out.$t >/dev/null && setret "failed"
- t=$((t + 1))
- echo_i "checking reload of a mixed-case RPZ zone (${t})"
- # First, a sanity check: the A6-2.TLD2.mixed-case-rpz RPZ record should
- # cause a6-2.tld2 NOERROR answers to be rewritten to NXDOMAIN answers.
- $DIG -p ${PORT} @$ns3 a6-2.tld2. A >dig.out.$t.before || setret "failed"
- grep "status: NXDOMAIN" dig.out.$t.before >/dev/null || setret "failed"
- # Add a sibling name (a6-1.tld2.mixed-case-rpz, with "tld2" in lowercase
- # rather than uppercase) before A6-2.TLD.mixed-case-rpz.
- nextpart ns3/named.run >/dev/null
- cp ns3/mixed-case-rpz-2.db.in ns3/mixed-case-rpz.db
- rndc_reload ns3 $ns3 mixed-case-rpz
- wait_for_log 20 "rpz: mixed-case-rpz: reload done" ns3/named.run
- # a6-2.tld2 NOERROR answers should still be rewritten to NXDOMAIN answers.
- # (The bug we try to trigger here caused a6-2.tld2.mixed-case-rpz to be
- # erroneously removed from the summary RPZ database after reload.)
- $DIG -p ${PORT} @$ns3 a6-2.tld2. A >dig.out.$t.after || setret "failed"
- grep "status: NXDOMAIN" dig.out.$t.after >/dev/null || setret "failed"
-fi
+t=$((t + 1))
+echo_i "checking reload of a mixed-case RPZ zone (${t})"
+# First, a sanity check: the A6-2.TLD2.mixed-case-rpz RPZ record should
+# cause a6-2.tld2 NOERROR answers to be rewritten to NXDOMAIN answers.
+$DIG -p ${PORT} @$ns3 a6-2.tld2. A >dig.out.$t.before || setret "failed"
+grep "status: NXDOMAIN" dig.out.$t.before >/dev/null || setret "failed"
+# Add a sibling name (a6-1.tld2.mixed-case-rpz, with "tld2" in lowercase
+# rather than uppercase) before A6-2.TLD.mixed-case-rpz.
+nextpart ns3/named.run >/dev/null
+cp ns3/mixed-case-rpz-2.db.in ns3/mixed-case-rpz.db
+rndc_reload ns3 $ns3 mixed-case-rpz
+wait_for_log 20 "rpz: mixed-case-rpz: reload done" ns3/named.run
+# a6-2.tld2 NOERROR answers should still be rewritten to NXDOMAIN answers.
+# (The bug we try to trigger here caused a6-2.tld2.mixed-case-rpz to be
+# erroneously removed from the summary RPZ database after reload.)
+$DIG -p ${PORT} @$ns3 a6-2.tld2. A >dig.out.$t.after || setret "failed"
+grep "status: NXDOMAIN" dig.out.$t.after >/dev/null || setret "failed"
t=$((t + 1))
echo_i "checking that ttl values are not zeroed when qtype is '*' (${t})"
t=$((t + 1))
echo_i "checking that going from an empty policy zone works (${t})"
nsd $ns5 add '*.x.servfail.policy2.' x.servfail.policy2.
-add_librpz_rule "update add *.x.servfail.policy2 300 CNAME ."
sleep 1
rndc_reload ns7 $ns7 policy2
$DIG z.x.servfail -p ${PORT} @$ns7 >dig.out.${t} || setret "failed"
$DIG z.x.servfail -p ${PORT} @$ns7 >dig.out.${t} || setret "failed"
grep "SOA" dig.out.${t} >/dev/null && setret "failed"
-if [ native = "$MODE" ]; then
- t=$((t + 1))
- echo_i "checking that 'add-soa yes' at response-policy level works (${t})"
- $DIG walled.tld2 -p ${PORT} +noall +add @$ns3 >dig.out.${t} || setret "failed"
- grep "^manual-update-rpz\..*60.*SOA" dig.out.${t} >/dev/null || setret "failed"
-fi
+t=$((t + 1))
+echo_i "checking that 'add-soa yes' at response-policy level works (${t})"
+$DIG walled.tld2 -p ${PORT} +noall +add @$ns3 >dig.out.${t} || setret "failed"
+grep "^manual-update-rpz\..*60.*SOA" dig.out.${t} >/dev/null || setret "failed"
-if [ native = "$MODE" ]; then
- t=$((t + 1))
- echo_i "reconfiguring server with 'add-soa no' (${t})"
- cp ns3/named.conf ns3/named.conf.tmp
- sed -e "s/add-soa yes/add-soa no/g" <ns3/named.conf.tmp >ns3/named.conf
- rndc_reconfig ns3 $ns3
- echo_i "checking that 'add-soa no' at response-policy level works (${t})"
- $DIG walled.tld2 -p ${PORT} +noall +add @$ns3 >dig.out.${t} || setret "failed"
- grep "^manual-update-rpz\..*SOA" dig.out.${t} >/dev/null && setret "failed"
-fi
+t=$((t + 1))
+echo_i "reconfiguring server with 'add-soa no' (${t})"
+cp ns3/named.conf ns3/named.conf.tmp
+sed -e "s/add-soa yes/add-soa no/g" <ns3/named.conf.tmp >ns3/named.conf
+rndc_reconfig ns3 $ns3
+echo_i "checking that 'add-soa no' at response-policy level works (${t})"
+$DIG walled.tld2 -p ${PORT} +noall +add @$ns3 >dig.out.${t} || setret "failed"
+grep "^manual-update-rpz\..*SOA" dig.out.${t} >/dev/null && setret "failed"
-if [ native = "$MODE" ]; then
- t=$((t + 1))
- echo_i "checking that 'add-soa unset' works (${t})"
- $DIG walled.tld2 -p ${PORT} +noall +add @$ns8 >dig.out.${t} || setret "failed"
- grep "^manual-update-rpz\..*60.*SOA" dig.out.${t} >/dev/null || setret "failed"
-fi
+t=$((t + 1))
+echo_i "checking that 'add-soa unset' works (${t})"
+$DIG walled.tld2 -p ${PORT} +noall +add @$ns8 >dig.out.${t} || setret "failed"
+grep "^manual-update-rpz\..*60.*SOA" dig.out.${t} >/dev/null || setret "failed"
-# dnsrps does not allow NS RRs in policy zones, so this check
-# with dnsrps results in no rewriting.
-if [ native = "$MODE" ]; then
- t=$((t + 1))
- echo_i "checking rpz with delegation fails correctly (${t})"
- $DIG -p ${PORT} @$ns3 ns example.com >dig.out.$t || setret "failed"
- grep "status: SERVFAIL" dig.out.$t >/dev/null || setret "failed"
+t=$((t + 1))
+echo_i "checking rpz with delegation fails correctly (${t})"
+$DIG -p ${PORT} @$ns3 ns example.com >dig.out.$t || setret "failed"
+grep "status: SERVFAIL" dig.out.$t >/dev/null || setret "failed"
- t=$((t + 1))
- echo_i "checking policies from expired zone are no longer in effect ($t)"
- $DIG -p ${PORT} @$ns3 a expired >dig.out.$t || setret "failed"
- grep "expired.*10.0.0.10" dig.out.$t >/dev/null && setret "failed"
- grep "fast-expire/IN: response-policy zone expired" ns3/named.run >/dev/null || setret "failed"
-fi
+t=$((t + 1))
+echo_i "checking policies from expired zone are no longer in effect ($t)"
+$DIG -p ${PORT} @$ns3 a expired >dig.out.$t || setret "failed"
+grep "expired.*10.0.0.10" dig.out.$t >/dev/null && setret "failed"
+grep "fast-expire/IN: response-policy zone expired" ns3/named.run >/dev/null || setret "failed"
# RPZ 'CNAME *.' (NODATA) trumps DNS64. Test against various DNS64 scenarios.
-produce_librpz_rules ns9 rpz rpz
for label in a-only no-a-no-aaaa a-plus-aaaa; do
for type in AAAA A; do
t=$((t + 1))
done
done
-if [ native = "$MODE" ]; then
- t=$((t + 1))
- echo_i "checking that rewriting CD=1 queries handles pending data correctly (${t})"
- $RNDCCMD $ns3 flush
- $RNDCCMD $ns6 flush
- $DIG a7-2.tld2s -p ${PORT} @$ns6 +cd >dig.out.${t} || setret "failed"
- grep -w "1.1.1.1" dig.out.${t} >/dev/null || setret "failed"
-fi
+t=$((t + 1))
+echo_i "checking that rewriting CD=1 queries handles pending data correctly (${t})"
+$RNDCCMD $ns3 flush
+$RNDCCMD $ns6 flush
+$DIG a7-2.tld2s -p ${PORT} @$ns6 +cd >dig.out.${t} || setret "failed"
+grep -w "1.1.1.1" dig.out.${t} >/dev/null || setret "failed"
[ $status -eq 0 ] || exit 1
+++ /dev/null
-# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
-#
-# SPDX-License-Identifier: MPL-2.0
-#
-# 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 https://mozilla.org/MPL/2.0/.
-#
-# See the COPYRIGHT file distributed with this work for additional
-# information regarding copyright ownership.
-
-import isctest.mark
-
-pytestmark = isctest.mark.dnsrps_enabled
-
-
-def test_rpz_dnsrps(run_tests_sh):
- with open("dnsrps.conf", "w", encoding="utf-8") as conf:
- conf.writelines(
- [
- "dnsrps-options { log-level 3 };"
- "dnsrps-enable yes;"
- 'dnsrps-library "../../rpz/testlib/.libs/libdummyrpz.so";'
- ]
- )
- run_tests_sh()
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
-# touch dnsrps-off to not test with DNSRPS
-
set -e
. ../conf.sh
/ns3/named2.conf
/ns4/named.conf
/ans5/ans.pid
-/dnsrps.conf
-/dnsrpzd.conf
session.key
rm -f ns3/named.conf
rm -f ns3/named.run.prev
-rm -f dnsrps.cache
-rm -f dnsrps*.conf
rm -f ns*/session.key
rm -f ns*/managed-keys.bind* ns*/*.mkeys*
recursion yes;
dnssec-validation yes;
querylog yes;
-
- # let ns3 start dnsrpzd
- include "../dnsrps.conf";
};
trust-anchors { };
controls {
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
-
qname-wait-recurse yes
nsip-enable yes
nsdname-enable yes;
-
- include "../dnsrps.conf";
};
trust-anchors { };
qname-wait-recurse yes
nsip-enable yes
nsdname-enable yes;
-
- include "../dnsrps.conf";
};
trust-anchors { };
dnssec-validation yes;
response-policy { zone "policy"; } nsdname-wait-recurse no
nsdname-enable yes;
-
- include "../dnsrps.conf";
};
trust-anchors { };
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
-# touch dnsrps-off to not test with DNSRPS
-
set -e
. ../conf.sh
copy_setports ns4/named.conf.in ns4/named.conf
-touch dnsrps.conf
-touch dnsrps.cache
-
# setup policy zones for a 64-zone test
i=1
while test $i -le 64; do
set -e
-# touch dnsrps-off to not test with DNSRPS
-# touch dnsrps-only to not test with classic RPZ
-
. ../conf.sh
status=0
t=0
-export DNSRPS_TEST_UPDATE_FILE=$(pwd)/dnsrps.cache
ARGS=
-if grep 'dnsrps-enable yes;' dnsrps.conf >/dev/null; then
- MODE=dnsrps
-else
- MODE=native
-fi
USAGE="$0: [-S]"
while getopts "S:" c; do
# really quit on control-C
trap 'exit 1' 1 2 15
-DNSRPSCMD=../rpz/dnsrps
RNDCCMD="$RNDC -c ../_common/rndc.conf -p ${CONTROLPORT} -s"
# $1 = test name (such as 1a, 1b, etc. for which named.$1.conf exists)
run_server() {
TESTNAME=$1
- start_server_rules $1 $2
echo_i "stopping resolver"
stop_server --use-rndc --port ${CONTROLPORT} ns2
sleep 3
}
-start_server_rules() {
- FCONF=ns2/named.$1.conf
-
- cat /dev/null >$DNSRPS_TEST_UPDATE_FILE
- cat $FCONF | grep 'zone ' | grep ' primary' | while read LINE; do
- ZONE=$(echo $LINE | sed 's/.*zone "//g' | awk -F '"' '{print $1}')
- DBFILE=$(echo $LINE | sed 's/.*file "//g' | awk -F '"' '{print $1}')
- cat ns2/$DBFILE | grep -E -v '^;' | grep -E '\<(A|CNAME)\>' | awk -v zone=$ZONE '{ if (NF == 4) {print "static add "$1"."zone" "$2" "$3" "$4} else if (NF == 3) {print "static add "$1"."zone" 300 "$2" "$3}}' >>$DNSRPS_TEST_UPDATE_FILE
- done
-}
-
-produce_librpz_rules() {
- ZONEFILE=$1/$3.db
- cat $ZONEFILE | grep -E -v '^;' | grep -E '\<(A|CNAME)\>' | awk -v zone=$2 '{ if (NF == 4) {print "static add "$1"."zone" "$2" "$3" "$4} else if (NF == 3) {print "static add "$1"."zone" 300 "$2" "$3}}' >>$DNSRPS_TEST_UPDATE_FILE
-}
-
run_query() {
TESTNAME=$1
LINE=$2
status=1
}
-if [ "$MODE" = "native" ]; then
- # Check for invalid prefix length error
- t=$((t + 1))
- echo_i "testing for invalid prefix length error (${t})"
- add_test_marker 10.53.0.2
- run_server invalidprefixlength
- grep "invalid rpz IP address \"1000.4.0.53.10.rpz-client-ip.invalidprefixlength\"; invalid prefix length of 1000$" ns2/named.run >/dev/null || {
- echo_ic "failed: expected that invalid prefix length error would be logged"
- status=1
- }
-fi
+# Check for invalid prefix length error
+t=$((t + 1))
+echo_i "testing for invalid prefix length error (${t})"
+add_test_marker 10.53.0.2
+run_server invalidprefixlength
+grep "invalid rpz IP address \"1000.4.0.53.10.rpz-client-ip.invalidprefixlength\"; invalid prefix length of 1000$" ns2/named.run >/dev/null || {
+ echo_ic "failed: expected that invalid prefix length error would be logged"
+ status=1
+}
-if [ "$MODE" = "native" ]; then
- t=$((t + 1))
- echo_i "checking 'nsip-wait-recurse no' is faster than 'nsip-wait-recurse yes' ($t)"
- add_test_marker 10.53.0.2 10.53.0.3
- echo_i "timing 'nsip-wait-recurse yes' (default)"
- produce_librpz_rules ns3 policy policy
- ret=0
- t1=$($PERL -e 'print time()."\n";')
- $DIG -p ${PORT} @10.53.0.3 foo.child.example.tld a >dig.out.yes.$t
- t2=$($PERL -e 'print time()."\n";')
- p1=$((t2 - t1))
- echo_i "elapsed time $p1 seconds"
-
- $RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} flush
- copy_setports ns3/named2.conf.in ns3/named.conf
- nextpart ns3/named.run >/dev/null
- $RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} reload >/dev/null
- wait_for_log 20 "rpz: policy: reload done" ns3/named.run || ret=1
-
- echo_i "timing 'nsip-wait-recurse no'"
- echo "update zone policy 0 no_nsip_wait_recurse" >$DNSRPS_TEST_UPDATE_FILE
- t3=$($PERL -e 'print time()."\n";')
- $DIG -p ${PORT} @10.53.0.3 foo.child.example.tld a >dig.out.no.$t
- t4=$($PERL -e 'print time()."\n";')
- p2=$((t4 - t3))
- echo_i "elapsed time $p2 seconds"
-
- if test $p1 -le $p2; then ret=1; fi
- if test $ret != 0; then echo_i "failed"; fi
- status=$((status + ret))
-
- $RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} flush
- # restore original named.conf
- copy_setports ns3/named1.conf.in ns3/named.conf
- nextpart ns3/named.run >/dev/null
- $RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} reload >/dev/null
- wait_for_log 20 "rpz: policy: reload done" ns3/named.run || ret=1
+t=$((t + 1))
+echo_i "checking 'nsip-wait-recurse no' is faster than 'nsip-wait-recurse yes' ($t)"
+add_test_marker 10.53.0.2 10.53.0.3
+echo_i "timing 'nsip-wait-recurse yes' (default)"
+ret=0
+t1=$($PERL -e 'print time()."\n";')
+$DIG -p ${PORT} @10.53.0.3 foo.child.example.tld a >dig.out.yes.$t
+t2=$($PERL -e 'print time()."\n";')
+p1=$((t2 - t1))
+echo_i "elapsed time $p1 seconds"
+
+$RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} flush
+copy_setports ns3/named2.conf.in ns3/named.conf
+nextpart ns3/named.run >/dev/null
+$RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} reload >/dev/null
+wait_for_log 20 "rpz: policy: reload done" ns3/named.run || ret=1
+
+echo_i "timing 'nsip-wait-recurse no'"
+t3=$($PERL -e 'print time()."\n";')
+$DIG -p ${PORT} @10.53.0.3 foo.child.example.tld a >dig.out.no.$t
+t4=$($PERL -e 'print time()."\n";')
+p2=$((t4 - t3))
+echo_i "elapsed time $p2 seconds"
+
+if test $p1 -le $p2; then ret=1; fi
+if test $ret != 0; then echo_i "failed"; fi
+status=$((status + ret))
+
+$RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} flush
+# restore original named.conf
+copy_setports ns3/named1.conf.in ns3/named.conf
+nextpart ns3/named.run >/dev/null
+$RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} reload >/dev/null
+wait_for_log 20 "rpz: policy: reload done" ns3/named.run || ret=1
- t=$((t + 1))
- echo_i "checking 'nsdname-wait-recurse no' is faster than 'nsdname-wait-recurse yes' ($t)"
- add_test_marker 10.53.0.2 10.53.0.3
- echo_i "timing 'nsdname-wait-recurse yes' (default)"
- ret=0
- t1=$($PERL -e 'print time()."\n";')
- $DIG -p ${PORT} @10.53.0.3 foo.child.example.tld a >dig.out.yes.$t
- t2=$($PERL -e 'print time()."\n";')
- p1=$((t2 - t1))
- echo_i "elapsed time $p1 seconds"
-
- $RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} flush
- copy_setports ns3/named3.conf.in ns3/named.conf
- nextpart ns3/named.run >/dev/null
- $RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} reload >/dev/null
- wait_for_log 20 "rpz: policy: reload done" ns3/named.run || ret=1
-
- echo_i "timing 'nsdname-wait-recurse no'"
- t3=$($PERL -e 'print time()."\n";')
- $DIG -p ${PORT} @10.53.0.3 foo.child.example.tld a >dig.out.no.$t
- t4=$($PERL -e 'print time()."\n";')
- p2=$((t4 - t3))
- echo_i "elapsed time $p2 seconds"
-
- if test $p1 -le $p2; then ret=1; fi
- if test $ret != 0; then echo_i "failed"; fi
- status=$((status + ret))
-fi
+t=$((t + 1))
+echo_i "checking 'nsdname-wait-recurse no' is faster than 'nsdname-wait-recurse yes' ($t)"
+add_test_marker 10.53.0.2 10.53.0.3
+echo_i "timing 'nsdname-wait-recurse yes' (default)"
+ret=0
+t1=$($PERL -e 'print time()."\n";')
+$DIG -p ${PORT} @10.53.0.3 foo.child.example.tld a >dig.out.yes.$t
+t2=$($PERL -e 'print time()."\n";')
+p1=$((t2 - t1))
+echo_i "elapsed time $p1 seconds"
+
+$RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} flush
+copy_setports ns3/named3.conf.in ns3/named.conf
+nextpart ns3/named.run >/dev/null
+$RNDC -c ../_common/rndc.conf -s 10.53.0.3 -p ${CONTROLPORT} reload >/dev/null
+wait_for_log 20 "rpz: policy: reload done" ns3/named.run || ret=1
+
+echo_i "timing 'nsdname-wait-recurse no'"
+t3=$($PERL -e 'print time()."\n";')
+$DIG -p ${PORT} @10.53.0.3 foo.child.example.tld a >dig.out.no.$t
+t4=$($PERL -e 'print time()."\n";')
+p2=$((t4 - t3))
+echo_i "elapsed time $p2 seconds"
+
+if test $p1 -le $p2; then ret=1; fi
+if test $ret != 0; then echo_i "failed"; fi
+status=$((status + ret))
[ $status -eq 0 ] || exit 1
+++ /dev/null
-# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
-#
-# SPDX-License-Identifier: MPL-2.0
-#
-# 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 https://mozilla.org/MPL/2.0/.
-#
-# See the COPYRIGHT file distributed with this work for additional
-# information regarding copyright ownership.
-
-import isctest.mark
-
-pytestmark = isctest.mark.dnsrps_enabled
-
-
-def test_rpzrecurse_dnsrps(run_tests_sh):
- with open("dnsrps.conf", "w", encoding="utf-8") as conf:
- conf.writelines(
- [
- "dnsrps-options { log-level 3 };"
- "dnsrps-enable yes;"
- 'dnsrps-library "../../rpz/testlib/.libs/libdummyrpz.so";'
- ]
- )
- run_tests_sh()
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
-# touch dnsrps-off to not test with DNSRPS
-
set -e
. ../conf.sh
#
AC_CHECK_HEADERS([threads.h])
-#
-# Also missing from OpenBSD
-#
-AC_CHECK_HEADERS([arpa/nameser_compat.h])
-
#
# C11 Atomic Operations
#
AS_IF([test "$enable_auto_validation" = "no"],[validation_default=yes])
AC_DEFINE_UNQUOTED([VALIDATION_DEFAULT], ["$validation_default"], [the default value of dnssec-validation option])
-#
-#
-# 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
-
-# [pairwise: --enable-dnsrps --enable-dnsrps-dl, --disable-dnsrps]
-AC_ARG_ENABLE([dnsrps-dl],
- [AS_HELP_STRING([--enable-dnsrps-dl],
- [DNS Response Policy Service delayed link
- [default=yes]])],
- [enable_dnsrps_dl="$enableval"], [enable_dnsrps_dl="yes"])
-
-# [pairwise: skip]
-AC_ARG_WITH([dnsrps-libname],
- [AS_HELP_STRING([--with-dnsrps-libname],
- [DNSRPS provider library name (librpz.so)])],
- [librpz_name="$withval"], [librpz_name="librpz.so"])
-
-# [pairwise: skip]
-AC_ARG_WITH([dnsrps-dir],
- [AS_HELP_STRING([--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])
-AS_IF([test "$enable_dnsrps_dl" = "yes"],
- [
- dnsrps_lib_open=2
- ],[
- 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])
- ])
-AC_DEFINE_UNQUOTED([DNSRPS_LIB_OPEN], [$dnsrps_lib_open],
- [0=no DNSRPS 1=static link 2=dlopen()])
-
-# [pairwise: skip]
-AC_ARG_ENABLE([dnsrps],
- AS_HELP_STRING([--enable-dnsrps],
- [enable DNS Response Policy Service API]),
- [enable_dnsrps=$enableval], [enable_dnsrps=no])
-
-AS_IF([test "$enable_dnsrps" != "no"],[
- AS_IF([test "$dnsrps_lib_open" = "0"],
- [AC_MSG_ERROR([dlopen and librpz.so needed for DNSRPS])])
- AC_DEFINE([USE_DNSRPS], [1], [Enable DNS Response Policy Service API])
- ])
-
-AM_CONDITIONAL([DNSRPS], [test "$enable_dnsrps" != "no"])
-
-AC_CHECK_HEADERS([glob.h])
-
#
# Support for constructor and destructor attributes
#
bin/tests/system/dyndb/driver/Makefile
bin/tests/system/dlzexternal/driver/Makefile
bin/tests/system/hooks/driver/Makefile
- bin/tests/system/rpz/testlib/Makefile
])
AC_CONFIG_FILES([bin/tests/system/ifconfig.sh],
test -z "$LIBIDN2_LIBS" || echo " IDN support (--with-libidn2)"
fi
- test "yes" = "$enable_dnsrps" && \
- echo " DNS Response Policy Service interface (--enable-dnsrps)"
test "yes" = "$enable_fixed_rrset" && \
echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)"
test "yes" = "$enable_fips_mode" && \
test -z "$MAXMINDDB_LIBS" && echo " GeoIP2 access control (--enable-geoip)"
test -z "$GSSAPI_LIBS" && echo " GSS-API (--with-gssapi)"
- test "no" = "$enable_dnsrps" && \
- echo " DNS Response Policy Service interface (--enable-dnsrps)"
-
test "yes" = "$enable_fixed_rrset" || \
echo " Allow 'fixed' rrset-order (--enable-fixed-rrset)"
done to discover problems at the authoritative server.
.. namedconf:statement:: dnsrps-enable
- :tags: server, security
+ :tags: obsolete
:short: Turns on the DNS Response Policy Service (DNSRPS) interface.
- The ``dnsrps-enable yes`` option turns on the DNS Response Policy Service
- (DNSRPS) interface, if it has been compiled in :iscman:`named` using
- ``configure --enable-dnsrps``.
+ This option no longer has any effect.
.. namedconf:statement:: dnsrps-library
- :tags: server, security
+ :tags: obsolete
:short: Turns on the DNS Response Policy Service (DNSRPS) interface.
- This option specifies the path to the DNSRPS provider library. Typically
- this library is detected when building with ``configure --enable-dnsrps``
- and does not need to be specified in ``named.conf``; the option exists
- to override the default library for testing purposes.
+ This option no longer has any effect.
.. namedconf:statement:: dnsrps-options
- :tags: server, security
+ :tags: obsolete
:short: Provides additional RPZ configuration settings, which are passed to the DNS Response Policy Service (DNSRPS) provider library.
- The block provides additional RPZ configuration
- settings, which are passed through to the DNSRPS provider library.
- Multiple DNSRPS settings in an :any:`dnsrps-options` string should be
- separated with semi-colons (;). The DNSRPS provider library is passed a
- configuration string consisting of the :any:`dnsrps-options` text,
- concatenated with settings derived from the :any:`response-policy`
- statement.
-
- Note: the :any:`dnsrps-options` 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
- ``dnsrpzd-conf``, ``dnsrpzd-sock``, and ``dnzrpzd-args`` (for details of
- these options, see the ``librpz`` documentation). Other RPZ
- configuration settings could be included in :any:`dnsrps-options` as well,
- but if :iscman:`named` were switched back to traditional RPZ by setting
- :any:`dnsrps-enable` to "no", those options would be ignored.
+ This option no longer has any effect.
The TTL of a record modified by RPZ policies is set from the TTL of the
relevant record in the policy zone. It is then limited to a maximum value.
dns64-contact <string>;
dns64-server <string>;
dnskey-sig-validity <integer>; // obsolete
- dnsrps-enable <boolean>; // not configured
- dnsrps-library <quoted_string>; // not configured
- dnsrps-options { <unspecified-text> }; // not configured
+ dnsrps-enable <boolean>; // obsolete
+ dnsrps-library <quoted_string>; // obsolete
+ dnsrps-options { <unspecified-text> }; // obsolete
dnssec-accept-expired <boolean>;
dnssec-dnskey-kskonly <boolean>; // obsolete
dnssec-loadkeys-interval <integer>;
dns64-contact <string>;
dns64-server <string>;
dnskey-sig-validity <integer>; // obsolete
- dnsrps-enable <boolean>; // not configured
- dnsrps-options { <unspecified-text> }; // not configured
+ dnsrps-enable <boolean>; // obsolete
+ dnsrps-options { <unspecified-text> }; // obsolete
dnssec-accept-expired <boolean>;
dnssec-dnskey-kskonly <boolean>; // obsolete
dnssec-loadkeys-interval <integer>;
include/dns/dlz.h \
include/dns/dlz_dlopen.h \
include/dns/dns64.h \
- include/dns/dnsrps.h \
include/dns/dnssec.h \
include/dns/ds.h \
include/dns/dsdigest.h \
include/dns/keystore.h \
include/dns/keytable.h \
include/dns/keyvalues.h \
- include/dns/librpz.h \
include/dns/master.h \
include/dns/masterdump.h \
include/dns/message.h \
dispatch.c \
dlz.c \
dns64.c \
- dnsrps.c \
dnssec.c \
ds.c \
dst_api.c \
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * 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 https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*! \file */
-
-#include <inttypes.h>
-#include <stdbool.h>
-
-#ifdef USE_DNSRPS
-
-#include <stdlib.h>
-
-#include <isc/mem.h>
-#include <isc/string.h>
-#include <isc/util.h>
-
-#include <dns/db.h>
-#define LIBRPZ_LIB_OPEN DNSRPS_LIB_OPEN
-#include <isc/result.h>
-
-#include <dns/dnsrps.h>
-#include <dns/rdataset.h>
-#include <dns/rdatasetiter.h>
-#include <dns/rpz.h>
-
-librpz_t *librpz = NULL;
-librpz_emsg_t librpz_lib_open_emsg;
-static uv_lib_t 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)->rps.db)
-#define RD_CUR_RR(r) ((r)->rps.iter_pos)
-#define RD_NEXT_RR(r) ((r)->resign)
-#define RD_COUNT(r) ((r)->rps.iter_count)
-
-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;
-
- isc_mutex_destroy(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_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;
-
- case LIBRPZ_LOG_FATAL:
- case LIBRPZ_LOG_ERROR: /* errors */
- default:
- isc_level = DNS_RPZ_ERROR_LEVEL;
- break;
- }
- isc_log_write(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(const char *librpz_path) {
- librpz_emsg_t emsg;
-
- INSIST(clist == NULL);
- INSIST(librpz == NULL);
-
- /*
- * Notice if librpz is available.
- */
- librpz = librpz_lib_open(&librpz_lib_open_emsg, &librpz_handle,
- librpz_path);
- if (librpz == NULL) {
- return (ISC_R_FILENOTFOUND);
- }
-
- isc_mutex_init(&dnsrps_mutex);
-
- librpz->set_log(dnsrps_log_fnc, NULL);
-
- clist = librpz->clist_create(&emsg, dnsrps_lock, dnsrps_unlock,
- dnsrps_mutex_destroy, &dnsrps_mutex, NULL);
- if (clist == NULL) {
- isc_log_write(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);
- }
-
-#if DNSRPS_LIB_OPEN == 2
- if (librpz != NULL) {
- librpz_lib_close(&librpz, &librpz_handle);
- }
-#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_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
- DNS_RPZ_DEBUG_LEVEL3, "dnsrps configuration \"%s\"",
- rps_cstr);
-
- new->rps_client = librpz->client_create(&emsg, clist, rps_cstr, false);
- if (new->rps_client == NULL) {
- isc_log_write(DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
- DNS_RPZ_ERROR_LEVEL,
- "librpz->client_create(): %s", emsg.c);
- new->p.dnsrps_enabled = false;
- return (ISC_R_FAILURE);
- }
-
- new->p.dnsrps_enabled = 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_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_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
- DNS_RPZ_ERROR_LEVEL, "librpz->connect(): %s",
- emsg.c);
- return (ISC_R_SUCCESS);
- }
-
- isc_log_write(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, bool have_rd) {
- dns_rpsdb_t *rpsdb = NULL;
-
- rpsdb = isc_mem_get(mctx, sizeof(*rpsdb));
- *rpsdb = (dns_rpsdb_t){
- .common = {
- .methods = &rpsdb_db_methods,
- .rdclass = dns_rdataclass_in,
- },
- .qname = qname,
- };
- isc_refcount_init(&rpsdb->common.references, 1);
-
- 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;
- dns_name_init(&rpsdb->common.origin, NULL);
- isc_mem_attach(mctx, &rpsdb->common.mctx);
-
- 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:
- UNREACHABLE();
- }
-}
-
-/*
- * 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_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);
- case LIBRPZ_TRIG_BAD:
- default:
- return (DNS_RPZ_TYPE_BAD);
- }
-}
-
-/*
- * 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_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);
- case DNS_RPZ_TYPE_BAD:
- default:
- return (LIBRPZ_TRIG_BAD);
- }
-}
-
-static void
-rpsdb_destroy(dns_db_t *db) {
- dns_rpsdb_t *rpsdb = (dns_rpsdb_t *)db;
-
- REQUIRE(VALID_RPSDB(rpsdb));
-
- librpz->rsp_detach(&rpsdb->rsp);
- isc_refcount_destroy(&rpsdb->common.references);
- 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 DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = (dns_rpsdb_t *)db;
-
- REQUIRE(VALID_RPSDB(rpsdb));
- REQUIRE(targetp != NULL && *targetp == NULL);
- REQUIRE(source == &rpsdb->origin_node || source == &rpsdb->data_node);
-
- isc_refcount_increment(&rpsdb->common.references);
- *targetp = source;
-}
-
-static void
-rpsdb_detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = (dns_rpsdb_t *)db;
-
- REQUIRE(VALID_RPSDB(rpsdb));
- REQUIRE(*targetp == &rpsdb->origin_node ||
- *targetp == &rpsdb->data_node);
-
- *targetp = NULL;
- dns_db_detach(&db);
-}
-
-static isc_result_t
-rpsdb_findnode(dns_db_t *db, const dns_name_t *name, bool create,
- dns_dbnode_t **nodep DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = (dns_rpsdb_t *)db;
- dns_db_t *dbp = NULL;
-
- 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;
- }
-
- dns_db_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,
- dns_rpsdb_t *rpsdb) {
- dns_db_t *dbp = NULL;
-
- 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) = (dns_rpsdb_t *)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, dns_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 DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = (dns_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_NXDOMAIN:
- return (DNS_R_NXDOMAIN);
-
- case LIBRPZ_POLICY_NODATA:
- return (DNS_R_NXRRSET);
-
- case LIBRPZ_POLICY_RECORD:
- case LIBRPZ_POLICY_CNAME:
- break;
-
- 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);
- }
-
- 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__DB_FLARG) {
- dns_dbnode_t *node = NULL;
-
- UNUSED(version);
- UNUSED(options);
- UNUSED(now);
- UNUSED(sigrdataset);
-
- if (nodep == NULL) {
- node = NULL;
- nodep = &node;
- }
- rpsdb_findnode(db, name, false, nodep DNS__DB_FLARG_PASS);
- dns_name_copy(name, foundname);
- return (rpsdb_findrdataset(db, *nodep, NULL, type, 0, 0, rdataset,
- sigrdataset DNS__DB_FLARG_PASS));
-}
-
-static isc_result_t
-rpsdb_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
- unsigned int options, isc_stdtime_t now,
- dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = (dns_rpsdb_t *)db;
- rpsdb_rdatasetiter_t *rpsdb_iter = NULL;
-
- 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));
- *rpsdb_iter = ( rpsdb_rdatasetiter_t){
-
- .common= {.magic = DNS_RDATASETITER_MAGIC,
- .methods = &rpsdb_rdatasetiter_methods,
- .db = db,
- .options = options,
- },
- };
-
- rpsdb_attachnode(db, node, &rpsdb_iter->common.node DNS__DB_FLARG_PASS);
-
- *iteratorp = &rpsdb_iter->common;
-
- return (ISC_R_SUCCESS);
-}
-
-static bool
-rpsdb_issecure(dns_db_t *db) {
- UNUSED(db);
-
- return (false);
-}
-
-static isc_result_t
-rpsdb_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = (dns_rpsdb_t *)db;
-
- REQUIRE(VALID_RPSDB(rpsdb));
- REQUIRE(nodep != NULL && *nodep == NULL);
-
- rpsdb_attachnode(db, &rpsdb->origin_node, nodep DNS__DB_FLARG_PASS);
- return (ISC_R_SUCCESS);
-}
-
-static void
-rpsdb_rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
- dns_db_t *db = NULL;
-
- /*
- * Detach the last RR delivered.
- */
- if (RD_CUR_RR(rdataset) != NULL) {
- free(RD_CUR_RR(rdataset));
- RD_CUR_RR(rdataset) = NULL;
- }
-
- db = (dns_db_t *)RD_DB(rdataset);
- RD_DB(rdataset) = NULL;
- dns_db_detach(&db);
-}
-
-static isc_result_t
-rpsdb_rdataset_next(dns_rdataset_t *rdataset) {
- dns_rpsdb_t *rpsdb = NULL;
- uint16_t type;
- dns_rdataclass_t class;
- librpz_rr_t *rr = NULL;
- 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) {
- dns_rpsdb_t *rpsdb = NULL;
- 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) {
- dns_rpsdb_t *rpsdb = NULL;
- librpz_rr_t *rr = NULL;
- 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 DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = NULL;
- dns_db_t *dbp = NULL;
-
- 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) = (dns_rpsdb_t *)dbp;
- RD_CUR_RR(target) = NULL;
- RD_NEXT_RR(target) = LIBRPZ_IDX_NULL;
-}
-
-static unsigned int
-rpsdb_rdataset_count(dns_rdataset_t *rdataset) {
- dns_rpsdb_t *rpsdb = NULL;
-
- rpsdb = RD_DB(rdataset);
- REQUIRE(VALID_RPSDB(rpsdb));
-
- return (RD_COUNT(rdataset));
-}
-
-static void
-rpsdb_rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = NULL;
- dns_rdatasetiter_t *iterator = NULL;
- isc_mem_t *mctx = NULL;
-
- iterator = *iteratorp;
- *iteratorp = NULL;
- rpsdb = (dns_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));
-}
-
-static isc_result_t
-rpsdb_rdatasetiter_next(dns_rdatasetiter_t *iter DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = NULL;
- rpsdb_rdatasetiter_t *rpsdb_iter = NULL;
- dns_rdatatype_t next_type, type;
- dns_rdataclass_t next_class, class;
- uint32_t ttl;
- librpz_emsg_t emsg;
-
- rpsdb = (dns_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 DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = NULL;
- rpsdb_rdatasetiter_t *rpsdb_iter = NULL;
-
- rpsdb = (dns_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 DNS__DB_FLARG_PASS));
-}
-
-static void
-rpsdb_rdatasetiter_current(dns_rdatasetiter_t *iterator,
- dns_rdataset_t *rdataset DNS__DB_FLARG) {
- dns_rpsdb_t *rpsdb = NULL;
- rpsdb_rdatasetiter_t *rpsdb_iter = NULL;
-
- rpsdb = (dns_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 = {
- .destroy = rpsdb_destroy,
- .findnode = rpsdb_findnode,
- .find = rpsdb_finddb,
- .attachnode = rpsdb_attachnode,
- .detachnode = rpsdb_detachnode,
- .findrdataset = rpsdb_findrdataset,
- .allrdatasets = rpsdb_allrdatasets,
- .issecure = rpsdb_issecure,
- .getoriginnode = rpsdb_getoriginnode,
-};
-
-static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
- .disassociate = rpsdb_rdataset_disassociate,
- .first = rpsdb_rdataset_first,
- .next = rpsdb_rdataset_next,
- .current = rpsdb_rdataset_current,
- .clone = rpsdb_rdataset_clone,
- .count = rpsdb_rdataset_count,
-};
-
-static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods = {
- rpsdb_rdatasetiter_destroy, rpsdb_rdatasetiter_first,
- rpsdb_rdatasetiter_next, rpsdb_rdatasetiter_current
-};
-
-#endif /* USE_DNSRPS */
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * 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 https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-#pragma once
-
-#include <inttypes.h>
-#include <stdbool.h>
-
-#include <isc/lang.h>
-
-#include <dns/types.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.
- *
- * dns_rpsdb_t holds the state for a set of RPZ queries.
- *
- * rpsnode_t is a link to the dns_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;
-
-struct dns_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;
-};
-
-/*
- * 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(const char *librpz_path);
-
-/*
- * 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, bool have_rd);
-
-#endif /* USE_DNSRPS */
-
-ISC_LANG_ENDDECLS
+++ /dev/null
-/*
- * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
- *
- * SPDX-License-Identifier: MPL-2.0
- *
- * 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 https://mozilla.org/MPL/2.0/.
- *
- * See the COPYRIGHT file distributed with this work for additional
- * information regarding copyright ownership.
- */
-
-/*
- * 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
- */
-
-#pragma once
-
-#include <arpa/nameser.h>
-#include <inttypes.h>
-#include <netinet/in.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <uv.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 /* ifdef LIBRPZ_INTERNAL */
-#define LIBDEF(t, s)
-#define LIBDEF_F(f)
-#endif /* ifdef LIBRPZ_INTERNAL */
-
-#define LIBRPZ_MAXDOMAIN 255
-
-/*
- * 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[]; /* variable length wire format */
-} librpz_domain_t;
-
-/*
- * A maximal domain buffer
- */
-typedef struct librpz_domain_buf {
- librpz_dsize_t size;
- uint8_t d[LIBRPZ_MAXDOMAIN];
-} 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[]; /* 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 at given 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;
-
-#define LIBRPZ_UNUSED __attribute__((__unused__))
-#define LIBRPZ_PF(f, l) __attribute__((__format__(printf, f, l)))
-#define LIBRPZ_NORET __attribute__((__noreturn__))
-
-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)
- LIBRPZ_PF(2, 0);
-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) LIBRPZ_PF(3, 0);
-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 int line,
- const char *p, ...) LIBRPZ_PF(3, 4);
-extern void
-librpz_rpz_assert(const char *file, unsigned int 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 clist: 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
- */
-LIBDEF(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 DNSRPS_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, uv_lib_t *lib, const char *path) {
- librpz_t *new_librpz = NULL;
- int r;
-
- emsg->c[0] = '\0';
-
- if (path == NULL || path[0] == '\0') {
- snprintf(emsg->c, sizeof(librpz_emsg_t),
- "path to librpz not provided");
- return (NULL);
- }
-
- r = uv_dlopen(path, lib);
- if (r != 0) {
- const char *errmsg = uv_dlerror(lib);
- if (errmsg == NULL) {
- errmsg = "unknown error";
- }
- snprintf(emsg->c, sizeof(librpz_emsg_t),
- "uv_dlopen(%s): ", path);
- strlcat(emsg->c, errmsg, sizeof(librpz_emsg_t));
- uv_dlclose(lib);
- return (NULL);
- }
- r = uv_dlsym(lib, LIBRPZ_DEF_STR, (void **)&new_librpz);
- if (r != 0) {
- const char *errmsg = uv_dlerror(lib);
- if (errmsg == NULL) {
- errmsg = "returned function pointer is NULL";
- }
- uv_dlclose(lib);
- snprintf(emsg->c, sizeof(librpz_emsg_t),
- "dlsym(%s, " LIBRPZ_DEF_STR "): ", path);
- strlcat(emsg->c, errmsg, sizeof(librpz_emsg_t));
- return (NULL);
- }
-
- return (new_librpz);
-}
-
-static inline void
-librpz_lib_close(librpz_t **rpz, uv_lib_t *lib) {
- *rpz = NULL;
- uv_dlclose(lib);
-}
-#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 DNSRPS_LIB_OPEN == 1
- emsg->c[0] = '\0';
- return (&LIBRPZ_DEF);
-#else /* if DNSRPS_LIB_OPEN == 1 */
- snprintf(emsg->c, sizeof(librpz_emsg_t),
- "librpz not available via ./configure");
- return (NULL);
-#endif /* DNSRPS_LIB_OPEN */
-}
-#endif /* LIBRPZ_LIB_OPEN */
const struct dns_name *noqname, *closest;
dns_dbnode_t *node;
} rdlist;
-
-#ifdef USE_DNSRPS
- /*
- * DNSRPS rdatasets. dns_rpsdb_t is defined in dnsrps.h.
- */
- struct {
- dns_rpsdb_t *db;
- void *iter_pos;
- unsigned int iter_count;
- } rps;
-#endif /* USE_DNSRPS */
};
};
dns_rpz_zbits_t no_log;
dns_rpz_zbits_t nsip_on;
dns_rpz_zbits_t nsdname_on;
- bool dnsrps_enabled;
bool break_dnssec;
bool qname_wait_recurse;
bool nsip_wait_recurse;
dns_rpz_cidr_node_t *cidr;
dns_qpmulti_t *table;
-
- /*
- * DNSRPZ librpz configuration string and handle on librpz connection
- */
- char *rps_cstr;
- size_t rps_cstr_size;
- struct librpz_client *rps_client;
};
/*
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
dns_name_t *selfname);
isc_result_t
-dns_rpz_new_zones(dns_view_t *view, isc_loopmgr_t *loopmgr, char *rps_cstr,
- size_t rps_cstr_size, dns_rpz_zones_t **rpzsp);
+dns_rpz_new_zones(dns_view_t *view, isc_loopmgr_t *loopmgr,
+ dns_rpz_zones_t **rpzsp);
isc_result_t
dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp);
typedef struct dns_request dns_request_t;
typedef struct dns_requestmgr dns_requestmgr_t;
typedef struct dns_resolver dns_resolver_t;
-typedef struct dns_rpsdb dns_rpsdb_t;
typedef struct dns_qpnode dns_qpnode_t;
typedef uint8_t dns_secalg_t;
typedef uint8_t dns_secproto_t;
#include <dns/db.h>
#include <dns/dbiterator.h>
-#include <dns/dnsrps.h>
#include <dns/fixedname.h>
#include <dns/qp.h>
#include <dns/rdata.h>
* Get ready for a new set of policy zones for a view.
*/
isc_result_t
-dns_rpz_new_zones(dns_view_t *view, isc_loopmgr_t *loopmgr, char *rps_cstr,
- size_t rps_cstr_size, dns_rpz_zones_t **rpzsp) {
+dns_rpz_new_zones(dns_view_t *view, isc_loopmgr_t *loopmgr,
+ dns_rpz_zones_t **rpzsp) {
dns_rpz_zones_t *rpzs = NULL;
isc_mem_t *mctx = NULL;
-#ifdef USE_DNSRPS
- isc_result_t result = ISC_R_SUCCESS;
-#endif
REQUIRE(rpzsp != NULL && *rpzsp == NULL);
REQUIRE(view != NULL);
rpzs = isc_mem_get(mctx, sizeof(*rpzs));
*rpzs = (dns_rpz_zones_t){
- .rps_cstr = rps_cstr,
- .rps_cstr_size = rps_cstr_size,
.loopmgr = loopmgr,
.magic = DNS_RPZ_ZONES_MAGIC,
};
isc_mutex_init(&rpzs->maint_lock);
isc_refcount_init(&rpzs->references, 1);
-#ifdef USE_DNSRPS
- if (rps_cstr != NULL) {
- result = dns_dnsrps_view_init(rpzs, rps_cstr);
- if (result != ISC_R_SUCCESS) {
- goto cleanup;
- }
- }
-#else /* ifdef USE_DNSRPS */
- INSIST(!rpzs->p.dnsrps_enabled);
-#endif /* ifdef USE_DNSRPS */
- if (!rpzs->p.dnsrps_enabled) {
- dns_qpmulti_create(mctx, &qpmethods, view, &rpzs->table);
- }
+ dns_qpmulti_create(mctx, &qpmethods, view, &rpzs->table);
isc_mem_attach(mctx, &rpzs->mctx);
*rpzsp = rpzs;
return (ISC_R_SUCCESS);
-
-#ifdef USE_DNSRPS
- /* Only if DNSRPS is in use can this function fail */
-cleanup:
- isc_refcount_decrementz(&rpzs->references);
- isc_refcount_destroy(&rpzs->references);
- isc_mutex_destroy(&rpzs->maint_lock);
- isc_rwlock_destroy(&rpzs->search_lock);
- isc_mem_put(mctx, rpzs, sizeof(*rpzs));
-
- return (result);
-#endif /* ifdef USE_DNSRPS */
}
isc_result_t
dns_rpz_zone_destroy(&rpzs->zones[rpz_num]);
}
- if (rpzs->rps_cstr_size != 0) {
-#ifdef USE_DNSRPS
- librpz->client_detach(&rpzs->rps_client);
-#endif /* ifdef USE_DNSRPS */
- isc_mem_put(rpzs->mctx, rpzs->rps_cstr, rpzs->rps_cstr_size);
- }
-
cidr_free(rpzs);
if (rpzs->table != NULL) {
dns_qpmulti_destroy(&rpzs->table);
{ "datasize", &cfg_type_size, CFG_CLAUSEFLAG_ANCIENT },
{ "deallocate-on-exit", NULL, CFG_CLAUSEFLAG_ANCIENT },
{ "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
-#ifdef USE_DNSRPS
- { "dnsrps-library", &cfg_type_qstring, 0 },
-#else /* ifdef USE_DNSRPS */
- { "dnsrps-library", &cfg_type_qstring, CFG_CLAUSEFLAG_NOTCONFIGURED },
-#endif /* ifdef USE_DNSRPS */
+ { "dnsrps-library", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
#ifdef HAVE_DNSTAP
{ "dnstap-output", &cfg_type_dnstapoutput, 0 },
{ "dnstap-identity", &cfg_type_serverid, 0 },
* [ break-dnssec yes|no ] [ min-ns-dots number ]
* [ qname-wait-recurse yes|no ]
* [ nsip-enable yes|no ] [ nsdname-enable yes|no ]
- * [ dnsrps-enable yes|no ]
- * [ dnsrps-options { DNSRPS configuration string } ];
*/
static void
{ "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 /* ifdef USE_DNSRPS */
- { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED },
- { "dnsrps-options", &cfg_type_bracketed_text,
- CFG_CLAUSEFLAG_NOTCONFIGURED },
-#endif /* ifdef USE_DNSRPS */
+ { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "dnsrps-options", &cfg_type_bracketed_text, CFG_CLAUSEFLAG_OBSOLETE },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_rpz = { "rpz",
{ "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 /* ifdef USE_DNSRPS */
- { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTCONFIGURED },
- { "dnsrps-options", &cfg_type_bracketed_text,
- CFG_CLAUSEFLAG_NOTCONFIGURED },
-#endif /* ifdef USE_DNSRPS */
+ { "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ { "dnsrps-options", &cfg_type_bracketed_text, CFG_CLAUSEFLAG_OBSOLETE },
{ "dnssec-accept-expired", &cfg_type_boolean, 0 },
{ "dnssec-enable", NULL, CFG_CLAUSEFLAG_ANCIENT },
{ "dnssec-lookaside", NULL,
#include <dns/db.h>
#include <dns/dlz.h>
#include <dns/dns64.h>
-#include <dns/dnsrps.h>
#include <dns/dnssec.h>
#include <dns/keytable.h>
#include <dns/message.h>
if (client->query.rpz_st != NULL) {
rpz_st_clear(client);
if (everything) {
- INSIST(client->query.rpz_st->rpsdb == NULL);
isc_mem_put(client->manager->mctx, client->query.rpz_st,
sizeof(*client->query.rpz_st));
client->query.rpz_st = NULL;
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
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,
- ((dns_rpsdb_t *)st->rpsdb)->rsp))
- {
- return (DNS_RPZ_ALL_ZBITS);
- }
- return (0);
- }
-#endif /* ifdef USE_DNSRPS */
-
switch (rpz_type) {
case DNS_RPZ_TYPE_CLIENT_IP:
zbits = st->have.client_ip;
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, dns_rpsdb_t *rpsdb,
- bool recursed) {
- isc_region_t region;
- librpz_domain_buf_t pname_buf;
-
- CTRACE(ISC_LOG_DEBUG(3), "dnsrps_ck");
-
- 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, ®ion);
- rpz_log_rewrite(client, 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 bool
-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,
- bool recursed) {
- dns_rpsdb_t *rpsdb = NULL;
- librpz_domain_buf_t pname_buf;
- isc_region_t region;
- dns_zone_t *p_zone = NULL;
- dns_db_t *p_db = NULL;
- dns_dbnode_t *p_node = NULL;
- dns_rpz_policy_t policy;
- dns_rdatatype_t foundtype, searchtype;
- isc_result_t result;
-
- CTRACE(ISC_LOG_DEBUG(3), "dnsrps_set_p");
-
- rpsdb = (dns_rpsdb_t *)st->rpsdb;
-
- if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
- return (false);
- }
-
- if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED) {
- return (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 (false);
- }
- region.base = rpsdb->origin_buf.d;
- region.length = rpsdb->origin_buf.size;
- dns_name_fromregion(&rpsdb->common.origin, ®ion);
-
- if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
- return (false);
- }
- region.base = pname_buf.d;
- region.length = pname_buf.size;
- dns_name_fromregion(st->p_name, ®ion);
-
- result = rpz_ready(client, p_rdatasetp);
- if (result != ISC_R_SUCCESS) {
- return (false);
- }
- 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 {
- dns_fixedname_t foundf;
- dns_name_t *found = NULL;
-
- /*
- * 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 (false);
- }
-
- if (foundtype == dns_rdatatype_cname) {
- searchtype = dns_rdatatype_cname;
- } else {
- searchtype = qtype;
- }
- /*
- * Get the DNSPRS imitation rdataset.
- */
- found = dns_fixedname_initname(&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 (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 (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;
- dns_rpsdb_t *rpsdb;
- librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
- bool recursed = false;
- int res;
- librpz_emsg_t emsg;
- isc_result_t result;
-
- CTRACE(ISC_LOG_DEBUG(3), "dnsrps_rewrite_ip");
-
- st = client->query.rpz_st;
- rpsdb = (dns_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 = false;
- break;
- case DNS_RPZ_TYPE_IP:
- trig = LIBRPZ_TRIG_IP;
- recursed = true;
- break;
- case DNS_RPZ_TYPE_NSIP:
- trig = LIBRPZ_TRIG_NSIP;
- recursed = true;
- break;
- default:
- UNREACHABLE();
- }
-
- 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, bool recursed,
- dns_rpz_type_t rpz_type, dns_rdataset_t **p_rdatasetp) {
- dns_rpz_st_t *st;
- dns_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;
-
- CTRACE(ISC_LOG_DEBUG(3), "dnsrps_rewrite_name");
-
- st = client->query.rpz_st;
- rpsdb = (dns_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:
- UNREACHABLE();
- }
-
- 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.
*/
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 /* ifdef USE_DNSRPS */
ip_name = dns_fixedname_initname(&ip_namef);
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, bool recursed,
- dns_rdataset_t **rdatasetp) {
+ dns_rpz_zbits_t allowed_zbits, dns_rdataset_t **rdatasetp) {
dns_rpz_zones_t *rpzs;
dns_rpz_zone_t *rpz;
dns_rpz_st_t *st;
dns_rpz_policy_t policy;
isc_result_t result;
-#ifndef USE_DNSRPS
- UNUSED(recursed);
-#endif /* ifndef USE_DNSRPS */
-
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 /* ifdef USE_DNSRPS */
-
zbits = rpz_get_zbits(client, qtype, rpz_type);
zbits &= allowed_zbits;
if (zbits == 0) {
dns_rpz_popt_t popt;
int rpz_ver;
unsigned int options;
-#ifdef USE_DNSRPS
- librpz_emsg_t emsg;
-#endif /* ifdef USE_DNSRPS */
CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite");
}
RWLOCK(&rpzs->search_lock, isc_rwlocktype_read);
- if ((rpzs->p.num_zones == 0 && !rpzs->p.dnsrps_enabled) ||
+ if ((rpzs->p.num_zones == 0) ||
(!RECURSIONOK(client) && rpzs->p.no_rd_ok == 0) ||
!rpz_ck_dnssec(client, qresult, ordataset, osigset))
{
rpz_ver = rpzs->rpz_ver;
RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
-#ifndef USE_DNSRPS
- INSIST(!popt.dnsrps_enabled);
-#endif /* ifndef USE_DNSRPS */
-
if (st == NULL) {
st = isc_mem_get(client->manager->mctx, sizeof(*st));
st->state = 0;
- st->rpsdb = NULL;
}
if (st->state == 0) {
st->state |= DNS_RPZ_ACTIVE;
st->popt = popt;
st->rpz_ver = rpz_ver;
client->query.rpz_st = st;
-#ifdef USE_DNSRPS
- if (popt.dnsrps_enabled) {
- if (st->rpsdb != NULL) {
- dns_db_detach(&st->rpsdb);
- }
- CTRACE(ISC_LOG_DEBUG(3), "dns_dnsrps_rewrite_init");
- result = dns_dnsrps_rewrite_init(
- &emsg, st, rpzs, client->query.qname,
- client->manager->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);
- }
- }
-#endif /* ifdef USE_DNSRPS */
}
/*
isc_netaddr_t netaddr;
dns_rpz_zbits_t allowed;
- if (!st->popt.dnsrps_enabled &&
- qresult_type == qresult_type_recurse)
- {
+ if (qresult_type == qresult_type_recurse) {
/*
* This request needs recursion that has not been done.
* Get bits for the policy zones that do not need
* There is a first time for each name in a CNAME chain
*/
if ((st->state & DNS_RPZ_DONE_QNAME) == 0) {
- bool norec = (qresult_type != qresult_type_recurse);
result = rpz_rewrite_name(client, client->query.qname,
qtype, DNS_RPZ_TYPE_QNAME,
- allowed, norec, &rdataset);
+ allowed, &rdataset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = rpz_rewrite_name(
client, &ns.name, qtype,
DNS_RPZ_TYPE_NSDNAME, DNS_RPZ_ALL_ZBITS,
- true, &rdataset);
+ &rdataset);
if (result != ISC_R_SUCCESS) {
dns_rdata_freestruct(&ns);
goto cleanup;
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,
- (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 /* ifdef USE_DNSRPS */
if (st->m.policy != DNS_RPZ_POLICY_MISS &&
st->m.policy != DNS_RPZ_POLICY_ERROR &&
st->m.rpz->policy != DNS_RPZ_POLICY_GIVEN)