summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/unbound/ax_pkg_swig.m4139
-rw-r--r--usr.sbin/unbound/services/rpz.c342
-rw-r--r--usr.sbin/unbound/services/rpz.h8
-rw-r--r--usr.sbin/unbound/testcode/checklocks.c24
-rw-r--r--usr.sbin/unbound/testcode/fake_event.c72
-rw-r--r--usr.sbin/unbound/testcode/replay.c14
-rw-r--r--usr.sbin/unbound/testcode/replay.h9
-rw-r--r--usr.sbin/unbound/testcode/testbound.c6
8 files changed, 518 insertions, 96 deletions
diff --git a/usr.sbin/unbound/ax_pkg_swig.m4 b/usr.sbin/unbound/ax_pkg_swig.m4
new file mode 100644
index 00000000000..7a4196ff5df
--- /dev/null
+++ b/usr.sbin/unbound/ax_pkg_swig.m4
@@ -0,0 +1,139 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found])
+#
+# DESCRIPTION
+#
+# This macro searches for a SWIG installation on your system. If found,
+# then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is
+# found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd.
+#
+# You can use the optional first argument to check if the version of the
+# available SWIG is greater than or equal to the value of the argument. It
+# should have the format: N[.N[.N]] (N is a number between 0 and 999. Only
+# the first N is mandatory.) If the version argument is given (e.g.
+# 1.3.17), AX_PKG_SWIG checks that the swig package is this version number
+# or higher.
+#
+# As usual, action-if-found is executed if SWIG is found, otherwise
+# action-if-not-found is executed.
+#
+# In configure.in, use as:
+#
+# AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ])
+# AX_SWIG_ENABLE_CXX
+# AX_SWIG_MULTI_MODULE_SUPPORT
+# AX_SWIG_PYTHON
+#
+# LICENSE
+#
+# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
+# Copyright (c) 2008 Alan W. Irwin
+# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
+# Copyright (c) 2008 Andrew Collier
+# Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
+# Copyright (c) 2018 Reini Urban <rurban@cpan.org>
+# Copyright (c) 2021 Vincent Danjean <Vincent.Danjean@ens-lyon.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 15
+
+AC_DEFUN([AX_PKG_SWIG],[
+ # Find path to the "swig" executable.
+ AC_PATH_PROGS([SWIG],[swig swig3.0 swig2.0])
+ if test -z "$SWIG" ; then
+ m4_ifval([$3],[$3],[:])
+ elif test -z "$1" ; then
+ m4_ifval([$2],[$2],[:])
+ else
+ AC_MSG_CHECKING([SWIG version])
+ [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
+ AC_MSG_RESULT([$swig_version])
+ if test -n "$swig_version" ; then
+ # Calculate the required version number components
+ [required=$1]
+ [required_major=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_major" ; then
+ [required_major=0]
+ fi
+ [required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
+ [required_minor=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_minor" ; then
+ [required_minor=0]
+ fi
+ [required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
+ [required_patch=`echo $required | sed 's/[^0-9].*//'`]
+ if test -z "$required_patch" ; then
+ [required_patch=0]
+ fi
+ # Calculate the available version number components
+ [available=$swig_version]
+ [available_major=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_major" ; then
+ [available_major=0]
+ fi
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+ [available_minor=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_minor" ; then
+ [available_minor=0]
+ fi
+ [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
+ [available_patch=`echo $available | sed 's/[^0-9].*//'`]
+ if test -z "$available_patch" ; then
+ [available_patch=0]
+ fi
+ # Convert the version tuple into a single number for easier comparison.
+ # Using base 100 should be safe since SWIG internally uses BCD values
+ # to encode its version number.
+ required_swig_vernum=`expr $required_major \* 10000 \
+ \+ $required_minor \* 100 \+ $required_patch`
+ available_swig_vernum=`expr $available_major \* 10000 \
+ \+ $available_minor \* 100 \+ $available_patch`
+
+ if test $available_swig_vernum -lt $required_swig_vernum; then
+ AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.])
+ SWIG=''
+ m4_ifval([$3],[$3],[])
+ else
+ AC_MSG_CHECKING([for SWIG library])
+ SWIG_LIB=`$SWIG -swiglib | tr '\r\n' ' '`
+ AC_MSG_RESULT([$SWIG_LIB])
+ m4_ifval([$2],[$2],[])
+ fi
+ else
+ AC_MSG_WARN([cannot determine SWIG version])
+ SWIG=''
+ m4_ifval([$3],[$3],[])
+ fi
+ fi
+ AC_SUBST([SWIG_LIB])
+])
diff --git a/usr.sbin/unbound/services/rpz.c b/usr.sbin/unbound/services/rpz.c
index 18d76c07bff..f036cc5fd64 100644
--- a/usr.sbin/unbound/services/rpz.c
+++ b/usr.sbin/unbound/services/rpz.c
@@ -478,43 +478,30 @@ new_cname_override(struct regional* region, uint8_t* ct, size_t ctlen)
return rrset;
}
-struct rpz*
-rpz_create(struct config_auth* p)
+/** delete the cname override */
+static void
+delete_cname_override(struct rpz* r)
{
- struct rpz* r = calloc(1, sizeof(*r));
- if(!r)
- goto err;
-
- r->region = regional_create_custom(sizeof(struct regional));
- if(!r->region) {
- goto err;
- }
-
- if(!(r->local_zones = local_zones_create())){
- goto err;
- }
-
- r->nsdname_zones = local_zones_create();
- if(r->local_zones == NULL){
- goto err;
- }
-
- if(!(r->respip_set = respip_set_create())) {
- goto err;
- }
-
- r->client_set = rpz_clientip_synthesized_set_create();
- if(r->client_set == NULL) {
- goto err;
+ if(r->cname_override) {
+ /* The cname override is what is allocated in the region. */
+ regional_free_all(r->region);
+ r->cname_override = NULL;
}
+}
- r->ns_set = rpz_clientip_synthesized_set_create();
- if(r->ns_set == NULL) {
- goto err;
+/** Apply rpz config elements to the rpz structure, false on failure. */
+static int
+rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p)
+{
+ if(p->rpz_taglist && p->rpz_taglistlen) {
+ r->taglistlen = p->rpz_taglistlen;
+ r->taglist = memdup(p->rpz_taglist, r->taglistlen);
+ if(!r->taglist) {
+ log_err("malloc failure on RPZ taglist alloc");
+ return 0;
+ }
}
- r->taglistlen = p->rpz_taglistlen;
- r->taglist = memdup(p->rpz_taglist, r->taglistlen);
if(p->rpz_action_override) {
r->action_override = rpz_config_to_action(p->rpz_action_override);
}
@@ -528,17 +515,17 @@ rpz_create(struct config_auth* p)
if(!p->rpz_cname) {
log_err("rpz: override with cname action found, but no "
"rpz-cname-override configured");
- goto err;
+ return 0;
}
if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) {
log_err("rpz: cannot parse cname override: %s",
p->rpz_cname);
- goto err;
+ return 0;
}
r->cname_override = new_cname_override(r->region, nm, nmlen);
if(!r->cname_override) {
- goto err;
+ return 0;
}
}
r->log = p->rpz_log;
@@ -546,9 +533,49 @@ rpz_create(struct config_auth* p)
if(p->rpz_log_name) {
if(!(r->log_name = strdup(p->rpz_log_name))) {
log_err("malloc failure on RPZ log_name strdup");
- goto err;
+ return 0;
}
}
+ return 1;
+}
+
+struct rpz*
+rpz_create(struct config_auth* p)
+{
+ struct rpz* r = calloc(1, sizeof(*r));
+ if(!r)
+ goto err;
+
+ r->region = regional_create_custom(sizeof(struct regional));
+ if(!r->region) {
+ goto err;
+ }
+
+ if(!(r->local_zones = local_zones_create())){
+ goto err;
+ }
+
+ r->nsdname_zones = local_zones_create();
+ if(r->local_zones == NULL){
+ goto err;
+ }
+
+ if(!(r->respip_set = respip_set_create())) {
+ goto err;
+ }
+
+ r->client_set = rpz_clientip_synthesized_set_create();
+ if(r->client_set == NULL) {
+ goto err;
+ }
+
+ r->ns_set = rpz_clientip_synthesized_set_create();
+ if(r->ns_set == NULL) {
+ goto err;
+ }
+
+ if(!rpz_apply_cfg_elements(r, p))
+ goto err;
return r;
err:
if(r) {
@@ -571,6 +598,32 @@ err:
return NULL;
}
+int
+rpz_config(struct rpz* r, struct config_auth* p)
+{
+ /* If the zonefile changes, it is read later, after which
+ * rpz_clear and rpz_finish_config is called. */
+
+ /* free taglist, if any */
+ if(r->taglist) {
+ free(r->taglist);
+ r->taglist = NULL;
+ r->taglistlen = 0;
+ }
+
+ /* free logname, if any */
+ if(r->log_name) {
+ free(r->log_name);
+ r->log_name = NULL;
+ }
+
+ delete_cname_override(r);
+
+ if(!rpz_apply_cfg_elements(r, p))
+ return 0;
+ return 1;
+}
+
/**
* Remove RPZ zone name from dname
* Copy dname to newdname, without the originlen number of trailing bytes
@@ -1191,16 +1244,20 @@ rpz_find_zone(struct local_zones* zones, uint8_t* qname, size_t qname_len, uint1
/** Find entry for RR type in the list of rrsets for the clientip. */
static struct local_rrset*
rpz_find_synthesized_rrset(uint16_t qtype,
- struct clientip_synthesized_rr* data)
+ struct clientip_synthesized_rr* data, int alias_ok)
{
- struct local_rrset* cursor = data->data;
+ struct local_rrset* cursor = data->data, *cname = NULL;
while( cursor != NULL) {
struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
if(htons(qtype) == packed_rrset->type) {
return cursor;
}
+ if(ntohs(packed_rrset->type) == LDNS_RR_TYPE_CNAME && alias_ok)
+ cname = cursor;
cursor = cursor->next;
}
+ if(alias_ok)
+ return cname;
return NULL;
}
@@ -1386,7 +1443,7 @@ static int rpz_remove_clientip_rr(struct clientip_synthesized_rr* node,
struct local_rrset* rrset;
struct packed_rrset_data* d;
size_t index;
- rrset = rpz_find_synthesized_rrset(rr_type, node);
+ rrset = rpz_find_synthesized_rrset(rr_type, node, 0);
if(rrset == NULL)
return 0; /* type not found, ignore */
d = (struct packed_rrset_data*)rrset->rrset->entry.data;
@@ -1789,7 +1846,7 @@ rpz_apply_clientip_localdata_action(struct clientip_synthesized_rr* raddr,
}
/* check query type / rr type */
- rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr);
+ rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr, 1);
if(rrset == NULL) {
verbose(VERB_ALGO, "rpz: unable to find local-data for query");
rrset_count = 0;
@@ -1823,6 +1880,28 @@ nodata:
rrset_count, rcode, rsoa);
}
+/** Apply the cname override action, during worker request callback.
+ * false on failure. */
+static int
+rpz_apply_cname_override_action(struct rpz* r,
+ struct query_info* qinfo, struct regional* temp)
+{
+ if(!r)
+ return 0;
+ qinfo->local_alias = regional_alloc_zero(temp,
+ sizeof(struct local_rrset));
+ if(qinfo->local_alias == NULL)
+ return 0; /* out of memory */
+ qinfo->local_alias->rrset = respip_copy_rrset(r->cname_override, temp);
+ if(qinfo->local_alias->rrset == NULL) {
+ qinfo->local_alias = NULL;
+ return 0; /* out of memory */
+ }
+ qinfo->local_alias->rrset->rk.dname = qinfo->qname;
+ qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
+ return 1;
+}
+
/** add additional section SOA record to the reply.
* Since this gets fed into the normal iterator answer creation, it
* gets minimal-responses applied to it, that can remove the additional SOA
@@ -1933,6 +2012,7 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs
msg = rpz_dns_msg_new(ms->region);
if(msg == NULL) { return NULL; }
+ msg->qinfo = *qi;
new_reply_info = construct_reply_info_base(ms->region,
LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA,
1, /* qd */
@@ -1975,40 +2055,42 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs
static inline struct dns_msg*
rpz_synthesize_nsip_localdata(struct rpz* r, struct module_qstate* ms,
- struct clientip_synthesized_rr* data, struct auth_zone* az)
+ struct query_info* qi, struct clientip_synthesized_rr* data,
+ struct auth_zone* az)
{
- struct query_info* qi = &ms->qinfo;
struct local_rrset* rrset;
- rrset = rpz_find_synthesized_rrset(qi->qtype, data);
+ rrset = rpz_find_synthesized_rrset(qi->qtype, data, 1);
if(rrset == NULL) {
verbose(VERB_ALGO, "rpz: nsip: no matching local data found");
return NULL;
}
- return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset, az);
+ return rpz_synthesize_localdata_from_rrset(r, ms, qi, rrset, az);
}
/* copy'n'paste from localzone.c */
static struct local_rrset*
local_data_find_type(struct local_data* data, uint16_t type, int alias_ok)
{
- struct local_rrset* p;
+ struct local_rrset* p, *cname = NULL;
type = htons(type);
for(p = data->rrsets; p; p = p->next) {
if(p->rrset->rk.type == type)
return p;
if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
- return p;
+ cname = p;
}
+ if(alias_ok)
+ return cname;
return NULL;
}
/* based on localzone.c:local_data_answer() */
static inline struct dns_msg*
rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
- struct local_zone* z, struct matched_delegation_point const* match,
- struct auth_zone* az)
+ struct query_info* qi, struct local_zone* z,
+ struct matched_delegation_point const* match, struct auth_zone* az)
{
struct local_data key;
struct local_data* ld;
@@ -2029,13 +2111,13 @@ rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
return NULL;
}
- rrset = local_data_find_type(ld, ms->qinfo.qtype, 1);
+ rrset = local_data_find_type(ld, qi->qtype, 1);
if(rrset == NULL) {
verbose(VERB_ALGO, "rpz: nsdname: no matching local data found");
return NULL;
}
- return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset, az);
+ return rpz_synthesize_localdata_from_rrset(r, ms, qi, rrset, az);
}
/* like local_data_answer for qname triggers after a cname */
@@ -2052,17 +2134,70 @@ rpz_synthesize_qname_localdata_msg(struct rpz* r, struct module_qstate* ms,
key.namelabs = dname_count_labels(qinfo->qname);
ld = (struct local_data*)rbtree_search(&z->data, &key.node);
if(ld == NULL) {
- verbose(VERB_ALGO, "rpz: qname after cname: name not found");
+ verbose(VERB_ALGO, "rpz: qname: name not found");
return NULL;
}
rrset = local_data_find_type(ld, qinfo->qtype, 1);
if(rrset == NULL) {
- verbose(VERB_ALGO, "rpz: qname after cname: type not found");
+ verbose(VERB_ALGO, "rpz: qname: type not found");
return NULL;
}
return rpz_synthesize_localdata_from_rrset(r, ms, qinfo, rrset, az);
}
+/** Synthesize a CNAME message for RPZ action override */
+static struct dns_msg*
+rpz_synthesize_cname_override_msg(struct rpz* r, struct module_qstate* ms,
+ struct query_info* qinfo)
+{
+ struct dns_msg* msg = NULL;
+ struct reply_info* new_reply_info;
+ struct ub_packed_rrset_key* rp;
+
+ msg = rpz_dns_msg_new(ms->region);
+ if(msg == NULL) { return NULL; }
+
+ msg->qinfo = *qinfo;
+ new_reply_info = construct_reply_info_base(ms->region,
+ LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA,
+ 1, /* qd */
+ 0, /* ttl */
+ 0, /* prettl */
+ 0, /* expttl */
+ 1, /* an */
+ 0, /* ns */
+ 0, /* ar */
+ 1, /* total */
+ sec_status_insecure,
+ LDNS_EDE_NONE);
+ if(new_reply_info == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ new_reply_info->authoritative = 1;
+
+ rp = respip_copy_rrset(r->cname_override, ms->region);
+ if(rp == NULL) {
+ log_err("out of memory");
+ return NULL;
+ }
+ rp->rk.dname = qinfo->qname;
+ rp->rk.dname_len = qinfo->qname_len;
+ /* this rrset is from the rpz data, or synthesized.
+ * It is not actually from the network, so we flag it with this
+ * flags as a fake RRset. If later the cache is used to look up
+ * rrsets, then the fake ones are not returned (if you look without
+ * the flag). For like CNAME lookups from the iterator or A, AAAA
+ * lookups for nameserver targets, it would use the without flag
+ * actual data. So that the actual network data and fake data
+ * are kept track of separately. */
+ rp->rk.flags |= PACKED_RRSET_RPZ;
+ new_reply_info->rrsets[0] = rp;
+
+ msg->rep = new_reply_info;
+ return msg;
+}
+
static int
rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
struct local_zone* z, enum localzone_type lzt, struct query_info* qinfo,
@@ -2072,17 +2207,8 @@ rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
struct local_data* ld = NULL;
int ret = 0;
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
- qinfo->local_alias = regional_alloc_zero(temp, sizeof(struct local_rrset));
- if(qinfo->local_alias == NULL) {
- return 0; /* out of memory */
- }
- qinfo->local_alias->rrset = regional_alloc_init(temp, r->cname_override,
- sizeof(*r->cname_override));
- if(qinfo->local_alias->rrset == NULL) {
- return 0; /* out of memory */
- }
- qinfo->local_alias->rrset->rk.dname = qinfo->qname;
- qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
+ if(!rpz_apply_cname_override_action(r, qinfo, temp))
+ return 0;
if(r->log) {
log_rpz_apply("qname", z->name, NULL, RPZ_CNAME_OVERRIDE_ACTION,
qinfo, repinfo, NULL, r->log_name);
@@ -2134,8 +2260,9 @@ rpz_delegation_point_ipbased_trigger_lookup(struct rpz* rpz, struct iter_qstate*
}
static struct dns_msg*
-rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
- struct clientip_synthesized_rr* raddr, struct auth_zone* az)
+rpz_apply_nsip_trigger(struct module_qstate* ms, struct query_info* qchase,
+ struct rpz* r, struct clientip_synthesized_rr* raddr,
+ struct auth_zone* az)
{
enum rpz_action action = raddr->action;
struct dns_msg* ret = NULL;
@@ -2148,16 +2275,16 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL) {
verbose(VERB_ALGO, "rpz: bug: nsip local data action but no local data");
- ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ ret = rpz_synthesize_nodata(r, ms, qchase, az);
goto done;
}
switch(action) {
case RPZ_NXDOMAIN_ACTION:
- ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az);
+ ret = rpz_synthesize_nxdomain(r, ms, qchase, az);
break;
case RPZ_NODATA_ACTION:
- ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ ret = rpz_synthesize_nodata(r, ms, qchase, az);
break;
case RPZ_TCP_ONLY_ACTION:
/* basically a passthru here but the tcp-only will be
@@ -2166,17 +2293,20 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
ret = NULL;
break;
case RPZ_DROP_ACTION:
- ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ ret = rpz_synthesize_nodata(r, ms, qchase, az);
ms->is_drop = 1;
break;
case RPZ_LOCAL_DATA_ACTION:
- ret = rpz_synthesize_nsip_localdata(r, ms, raddr, az);
- if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); }
+ ret = rpz_synthesize_nsip_localdata(r, ms, qchase, raddr, az);
+ if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); }
break;
case RPZ_PASSTHRU_ACTION:
ret = NULL;
ms->rpz_passthru = 1;
break;
+ case RPZ_CNAME_OVERRIDE_ACTION:
+ ret = rpz_synthesize_cname_override_msg(r, ms, qchase);
+ break;
default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
rpz_action_to_string(action));
@@ -2194,9 +2324,9 @@ done:
}
static struct dns_msg*
-rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
- struct local_zone* z, struct matched_delegation_point const* match,
- struct auth_zone* az)
+rpz_apply_nsdname_trigger(struct module_qstate* ms, struct query_info* qchase,
+ struct rpz* r, struct local_zone* z,
+ struct matched_delegation_point const* match, struct auth_zone* az)
{
struct dns_msg* ret = NULL;
enum rpz_action action = localzone_type_to_rpz_action(z->type);
@@ -2209,10 +2339,10 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
switch(action) {
case RPZ_NXDOMAIN_ACTION:
- ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az);
+ ret = rpz_synthesize_nxdomain(r, ms, qchase, az);
break;
case RPZ_NODATA_ACTION:
- ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ ret = rpz_synthesize_nodata(r, ms, qchase, az);
break;
case RPZ_TCP_ONLY_ACTION:
/* basically a passthru here but the tcp-only will be
@@ -2221,19 +2351,22 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
ret = NULL;
break;
case RPZ_DROP_ACTION:
- ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
+ ret = rpz_synthesize_nodata(r, ms, qchase, az);
ms->is_drop = 1;
break;
case RPZ_LOCAL_DATA_ACTION:
- ret = rpz_synthesize_nsdname_localdata(r, ms, z, match, az);
- if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); }
+ ret = rpz_synthesize_nsdname_localdata(r, ms, qchase, z, match, az);
+ if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); }
break;
case RPZ_PASSTHRU_ACTION:
ret = NULL;
ms->rpz_passthru = 1;
break;
+ case RPZ_CNAME_OVERRIDE_ACTION:
+ ret = rpz_synthesize_cname_override_msg(r, ms, qchase);
+ break;
default:
- verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
+ verbose(VERB_ALGO, "rpz: nsdname: bug: unhandled or invalid action: '%s'",
rpz_action_to_string(action));
ret = NULL;
}
@@ -2324,7 +2457,7 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
/* the nsdname has precedence over the nsip triggers */
z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones,
- ms->qinfo.qclass, &match);
+ is->qchase.qclass, &match);
if(z != NULL) {
lock_rw_unlock(&a->lock);
break;
@@ -2347,9 +2480,9 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
if(z) {
lock_rw_unlock(&z->lock);
}
- return rpz_apply_nsip_trigger(ms, r, raddr, a);
+ return rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a);
}
- return rpz_apply_nsdname_trigger(ms, r, z, &match, a);
+ return rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a);
}
struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
@@ -2412,10 +2545,10 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
dname_str(is->qchase.qname, nm);
dname_str(z->name, zn);
if(strcmp(zn, nm) != 0)
- verbose(VERB_ALGO, "rpz: qname trigger after cname %s on %s, with action=%s",
+ verbose(VERB_ALGO, "rpz: qname trigger %s on %s, with action=%s",
zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
else
- verbose(VERB_ALGO, "rpz: qname trigger after cname %s, with action=%s",
+ verbose(VERB_ALGO, "rpz: qname trigger %s, with action=%s",
nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
}
switch(localzone_type_to_rpz_action(lzt)) {
@@ -2444,7 +2577,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
ms->rpz_passthru = 1;
break;
default:
- verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'",
+ verbose(VERB_ALGO, "rpz: qname trigger: bug: unhandled or invalid action: '%s'",
rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
ret = NULL;
}
@@ -2472,8 +2605,21 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out);
client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action);
+ if(node != NULL && *r_out &&
+ (*r_out)->action_override != RPZ_NO_OVERRIDE_ACTION) {
+ client_action = (*r_out)->action_override;
+ }
if(client_action == RPZ_PASSTHRU_ACTION) {
+ if(*r_out && (*r_out)->log)
+ log_rpz_apply(
+ (node?"clientip":"qname"),
+ ((*z_out)?(*z_out)->name:NULL),
+ (node?&node->node:NULL),
+ client_action, qinfo, repinfo, NULL,
+ (*r_out)->log_name);
*passthru = 1;
+ ret = 0;
+ goto done;
}
if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION &&
client_action != RPZ_PASSTHRU_ACTION)) {
@@ -2488,14 +2634,15 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
if(client_action == RPZ_LOCAL_DATA_ACTION) {
rpz_apply_clientip_localdata_action(node, env, qinfo,
edns, repinfo, buf, temp, *a_out);
+ ret = 1;
+ } else if(client_action == RPZ_CNAME_OVERRIDE_ACTION) {
+ if(!rpz_apply_cname_override_action(*r_out, qinfo,
+ temp)) {
+ ret = 0;
+ goto done;
+ }
+ ret = 0;
} else {
- if(*r_out && (*r_out)->log)
- log_rpz_apply(
- (node?"clientip":"qname"),
- ((*z_out)?(*z_out)->name:NULL),
- (node?&node->node:NULL),
- client_action, qinfo, repinfo, NULL,
- (*r_out)->log_name);
local_zones_zone_answer(*z_out /*likely NULL, no zone*/, env, qinfo, edns,
repinfo, buf, temp, 0 /* no local data used */,
rpz_action_to_localzone_type(client_action));
@@ -2503,8 +2650,15 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
LDNS_RCODE_WIRE(sldns_buffer_begin(buf))
== LDNS_RCODE_NXDOMAIN)
LDNS_RA_CLR(sldns_buffer_begin(buf));
+ ret = 1;
}
- ret = 1;
+ if(*r_out && (*r_out)->log)
+ log_rpz_apply(
+ (node?"clientip":"qname"),
+ ((*z_out)?(*z_out)->name:NULL),
+ (node?&node->node:NULL),
+ client_action, qinfo, repinfo, NULL,
+ (*r_out)->log_name);
goto done;
}
ret = -1;
diff --git a/usr.sbin/unbound/services/rpz.h b/usr.sbin/unbound/services/rpz.h
index e6d8bf566e1..7f409087f77 100644
--- a/usr.sbin/unbound/services/rpz.h
+++ b/usr.sbin/unbound/services/rpz.h
@@ -226,6 +226,14 @@ int rpz_clear(struct rpz* r);
struct rpz* rpz_create(struct config_auth* p);
/**
+ * Change config on rpz, after reload.
+ * @param r: the rpz structure.
+ * @param p: the config that was read.
+ * @return false on failure.
+ */
+int rpz_config(struct rpz* r, struct config_auth* p);
+
+/**
* String for RPZ action enum
* @param a: RPZ action to get string for
* @return: string for RPZ action
diff --git a/usr.sbin/unbound/testcode/checklocks.c b/usr.sbin/unbound/testcode/checklocks.c
index 1b5ef282b5e..d1c87746730 100644
--- a/usr.sbin/unbound/testcode/checklocks.c
+++ b/usr.sbin/unbound/testcode/checklocks.c
@@ -68,6 +68,17 @@ static struct thr_check* thread_infos[THRDEBUG_MAX_THREADS];
int check_locking_order = 1;
/** the pid of this runset, reasonably unique. */
static pid_t check_lock_pid;
+/**
+ * Should checklocks print a trace of the lock and unlock calls.
+ * It uses fprintf for that because the log function uses a lock and that
+ * would loop otherwise.
+ */
+static int verbose_locking = 0;
+/**
+ * Assume lock 0 0 (create_thread, create_instance), is the log lock and
+ * do not print for that. Otherwise the output is full of log lock accesses.
+ */
+static int verbose_locking_not_loglock = 1;
/** print all possible debug info on the state of the system */
static void total_debug_info(void);
@@ -508,6 +519,9 @@ checklock_rdlock(enum check_lock_type type, struct checked_lock* lock,
if(key_deleted)
return;
+ if(verbose_locking && !(verbose_locking_not_loglock &&
+ lock->create_thread == 0 && lock->create_instance == 0))
+ fprintf(stderr, "checklock_rdlock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line);
log_assert(type == check_lock_rwlock);
checklock_lockit(type, lock, func, file, line,
try_rd, timed_rd, &lock->u.rwlock, 0, 0);
@@ -528,6 +542,9 @@ checklock_wrlock(enum check_lock_type type, struct checked_lock* lock,
if(key_deleted)
return;
log_assert(type == check_lock_rwlock);
+ if(verbose_locking && !(verbose_locking_not_loglock &&
+ lock->create_thread == 0 && lock->create_instance == 0))
+ fprintf(stderr, "checklock_wrlock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line);
checklock_lockit(type, lock, func, file, line,
try_wr, timed_wr, &lock->u.rwlock, 0, 1);
}
@@ -565,6 +582,9 @@ checklock_lock(enum check_lock_type type, struct checked_lock* lock,
if(key_deleted)
return;
log_assert(type != check_lock_rwlock);
+ if(verbose_locking && !(verbose_locking_not_loglock &&
+ lock->create_thread == 0 && lock->create_instance == 0))
+ fprintf(stderr, "checklock_lock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line);
switch(type) {
case check_lock_mutex:
checklock_lockit(type, lock, func, file, line,
@@ -602,6 +622,10 @@ checklock_unlock(enum check_lock_type type, struct checked_lock* lock,
if(lock->hold_count <= 0)
lock_error(lock, func, file, line, "too many unlocks");
+ if(verbose_locking && !(verbose_locking_not_loglock &&
+ lock->create_thread == 0 && lock->create_instance == 0))
+ fprintf(stderr, "checklock_unlock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line);
+
/* store this point as last touched by */
lock->holder = thr;
lock->hold_count --;
diff --git a/usr.sbin/unbound/testcode/fake_event.c b/usr.sbin/unbound/testcode/fake_event.c
index 13970c37726..09269289dd4 100644
--- a/usr.sbin/unbound/testcode/fake_event.c
+++ b/usr.sbin/unbound/testcode/fake_event.c
@@ -52,6 +52,7 @@
#include "util/data/msgreply.h"
#include "util/data/msgencode.h"
#include "util/data/dname.h"
+#include "util/storage/slabhash.h"
#include "util/edns.h"
#include "util/config_file.h"
#include "services/listen_dnsport.h"
@@ -65,6 +66,7 @@
#include "sldns/wire2str.h"
#include "sldns/str2wire.h"
#include "daemon/remote.h"
+#include "daemon/daemon.h"
#include "util/timeval_func.h"
#include <signal.h>
struct worker;
@@ -154,6 +156,8 @@ repevt_string(enum replay_event_type t)
case repevt_assign: return "ASSIGN";
case repevt_traffic: return "TRAFFIC";
case repevt_infra_rtt: return "INFRA_RTT";
+ case repevt_flush_message: return "FLUSH_MESSAGE";
+ case repevt_expire_message: return "EXPIRE_MESSAGE";
default: return "UNKNOWN";
}
}
@@ -691,6 +695,66 @@ do_infra_rtt(struct replay_runtime* runtime)
free(dp);
}
+/** Flush message from message cache. */
+static void
+do_flush_message(struct replay_runtime* runtime)
+{
+ struct replay_moment* now = runtime->now;
+ uint8_t rr[1024];
+ size_t rr_len = sizeof(rr), dname_len = 0;
+ hashvalue_type h;
+ struct query_info k;
+
+ if(sldns_str2wire_rr_question_buf(now->string, rr, &rr_len,
+ &dname_len, NULL, 0, NULL, 0) != 0)
+ fatal_exit("could not parse '%s'", now->string);
+
+ log_info("remove message %s", now->string);
+ k.qname = rr;
+ k.qname_len = dname_len;
+ k.qtype = sldns_wirerr_get_type(rr, rr_len, dname_len);
+ k.qclass = sldns_wirerr_get_class(rr, rr_len, dname_len);
+ k.local_alias = NULL;
+ h = query_info_hash(&k, 0);
+ slabhash_remove(runtime->daemon->env->msg_cache, h, &k);
+}
+
+/** Expire message from message cache. */
+static void
+do_expire_message(struct replay_runtime* runtime)
+{
+ struct replay_moment* now = runtime->now;
+ uint8_t rr[1024];
+ size_t rr_len = sizeof(rr), dname_len = 0;
+ hashvalue_type h;
+ struct query_info k;
+ struct lruhash_entry* e;
+
+ if(sldns_str2wire_rr_question_buf(now->string, rr, &rr_len,
+ &dname_len, NULL, 0, NULL, 0) != 0)
+ fatal_exit("could not parse '%s'", now->string);
+
+ log_info("expire message %s", now->string);
+ k.qname = rr;
+ k.qname_len = dname_len;
+ k.qtype = sldns_wirerr_get_type(rr, rr_len, dname_len);
+ k.qclass = sldns_wirerr_get_class(rr, rr_len, dname_len);
+ k.local_alias = NULL;
+ h = query_info_hash(&k, 0);
+
+ e = slabhash_lookup(runtime->daemon->env->msg_cache, h, &k, 0);
+ if(e) {
+ struct msgreply_entry* msg = (struct msgreply_entry*)e->key;
+ struct reply_info* rep = (struct reply_info*)msg->entry.data;
+ time_t expired = runtime->now_secs;
+ expired -= 3;
+ rep->ttl = expired;
+ rep->prefetch_ttl = expired;
+ rep->serve_expired_ttl = expired;
+ lock_rw_unlock(&msg->entry.lock);
+ }
+}
+
/** perform exponential backoff on the timeout */
static void
expon_timeout_backoff(struct replay_runtime* runtime)
@@ -796,6 +860,14 @@ do_moment_and_advance(struct replay_runtime* runtime)
do_infra_rtt(runtime);
advance_moment(runtime);
break;
+ case repevt_flush_message:
+ do_flush_message(runtime);
+ advance_moment(runtime);
+ break;
+ case repevt_expire_message:
+ do_expire_message(runtime);
+ advance_moment(runtime);
+ break;
default:
fatal_exit("testbound: unknown event type %d",
runtime->now->evt_type);
diff --git a/usr.sbin/unbound/testcode/replay.c b/usr.sbin/unbound/testcode/replay.c
index f896a5512c5..95dde405f64 100644
--- a/usr.sbin/unbound/testcode/replay.c
+++ b/usr.sbin/unbound/testcode/replay.c
@@ -348,6 +348,20 @@ replay_moment_read(char* remain, FILE* in, const char* name,
mom->string = strdup(m);
if(!mom->string) fatal_exit("out of memory");
if(!mom->variable) fatal_exit("out of memory");
+ } else if(parse_keyword(&remain, "FLUSH_MESSAGE")) {
+ mom->evt_type = repevt_flush_message;
+ while(isspace((unsigned char)*remain))
+ remain++;
+ strip_end_white(remain);
+ mom->string = strdup(remain);
+ if(!mom->string) fatal_exit("out of memory");
+ } else if(parse_keyword(&remain, "EXPIRE_MESSAGE")) {
+ mom->evt_type = repevt_expire_message;
+ while(isspace((unsigned char)*remain))
+ remain++;
+ strip_end_white(remain);
+ mom->string = strdup(remain);
+ if(!mom->string) fatal_exit("out of memory");
} else {
log_err("%d: unknown event type %s", pstate->lineno, remain);
free(mom);
diff --git a/usr.sbin/unbound/testcode/replay.h b/usr.sbin/unbound/testcode/replay.h
index 0271dff0393..809e8ee3977 100644
--- a/usr.sbin/unbound/testcode/replay.h
+++ b/usr.sbin/unbound/testcode/replay.h
@@ -85,6 +85,8 @@
* The file contents is macro expanded before match.
* o CHECK_TEMPFILE [fname] - followed by FILE_BEGIN [to match] FILE_END
* o INFRA_RTT [ip] [dp] [rtt] - update infra cache entry with rtt.
+ * o FLUSH_MESSAGE name type class - flushes entry in message cache.
+ * o EXPIRE_MESSAGE name type class - expires entry in message cache.
* o ERROR
* ; following entry starts on the next line, ENTRY_BEGIN.
* ; more STEP items
@@ -148,6 +150,7 @@ struct fake_timer;
struct replay_var;
struct infra_cache;
struct sldns_buffer;
+struct daemon;
/**
* A replay scenario.
@@ -212,6 +215,10 @@ struct replay_moment {
repevt_assign,
/** store infra rtt cache entry: addr and string (int) */
repevt_infra_rtt,
+ /** flush message cache entry */
+ repevt_flush_message,
+ /** expire message cache entry */
+ repevt_expire_message,
/** cause traffic to flow */
repevt_traffic
}
@@ -297,6 +304,8 @@ struct replay_runtime {
/** ref the infra cache (was passed to outside_network_create) */
struct infra_cache* infra;
+ /** the daemon structure passed in worker call to remote accept open */
+ struct daemon* daemon;
/** the current time in seconds */
time_t now_secs;
diff --git a/usr.sbin/unbound/testcode/testbound.c b/usr.sbin/unbound/testcode/testbound.c
index ec627cc8deb..f023860e086 100644
--- a/usr.sbin/unbound/testcode/testbound.c
+++ b/usr.sbin/unbound/testcode/testbound.c
@@ -48,6 +48,7 @@
#include "testcode/fake_event.h"
#include "daemon/remote.h"
#include "libunbound/worker.h"
+#include "daemon/worker.h"
#include "util/config_file.h"
#include "sldns/keyraw.h"
#ifdef UB_ON_WINDOWS
@@ -532,9 +533,10 @@ void daemon_remote_clear(struct daemon_remote* ATTR_UNUSED(rc))
}
int daemon_remote_open_accept(struct daemon_remote* ATTR_UNUSED(rc),
- struct listen_port* ATTR_UNUSED(ports),
- struct worker* ATTR_UNUSED(worker))
+ struct listen_port* ATTR_UNUSED(ports), struct worker* worker)
{
+ struct replay_runtime* runtime = (struct replay_runtime*)worker->base;
+ runtime->daemon = worker->daemon;
return 1;
}