import unbound 1.20.0, ok florian
authorsthen <sthen@openbsd.org>
Thu, 13 Jun 2024 14:29:32 +0000 (14:29 +0000)
committersthen <sthen@openbsd.org>
Thu, 13 Jun 2024 14:29:32 +0000 (14:29 +0000)
usr.sbin/unbound/ax_pkg_swig.m4 [new file with mode: 0644]
usr.sbin/unbound/services/rpz.c
usr.sbin/unbound/services/rpz.h
usr.sbin/unbound/testcode/checklocks.c
usr.sbin/unbound/testcode/fake_event.c
usr.sbin/unbound/testcode/replay.c
usr.sbin/unbound/testcode/replay.h
usr.sbin/unbound/testcode/testbound.c

diff --git a/usr.sbin/unbound/ax_pkg_swig.m4 b/usr.sbin/unbound/ax_pkg_swig.m4
new file mode 100644 (file)
index 0000000..7a4196f
--- /dev/null
@@ -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])
+])
index 18d76c0..f036cc5 100644 (file)
@@ -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;
index e6d8bf5..7f40908 100644 (file)
@@ -225,6 +225,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
index 1b5ef28..d1c8774 100644 (file)
@@ -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 --;
index 13970c3..0926928 100644 (file)
@@ -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);
index f896a55..95dde40 100644 (file)
@@ -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);
index 0271dff..809e8ee 100644 (file)
@@ -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;
index ec627cc..f023860 100644 (file)
@@ -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;
 }