]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Commit rt25172 changes to HEAD including
authorVernon Schryver <vjs@isc.org>
Thu, 13 Oct 2011 01:32:34 +0000 (01:32 +0000)
committerVernon Schryver <vjs@isc.org>
Thu, 13 Oct 2011 01:32:34 +0000 (01:32 +0000)
  - fix precedence among competing rules
  - improve ARM text including documenting rule precedence
  - try to rewrite CNAME chains until first hit
  - new "rpz" logging channel
  - same fix for "NS ." as in RT 24985

26 files changed:
bin/named/query.c
bin/tests/system/rpz/clean.sh
bin/tests/system/rpz/ns1/root.db
bin/tests/system/rpz/ns2/hints
bin/tests/system/rpz/ns2/named.conf
bin/tests/system/rpz/ns2/tld2.db
bin/tests/system/rpz/ns3/base.db
bin/tests/system/rpz/ns3/hints
bin/tests/system/rpz/ns3/named.conf
bin/tests/system/rpz/setup.sh
bin/tests/system/rpz/test1
bin/tests/system/rpz/test2
bin/tests/system/rpz/test3
bin/tests/system/rpz/test4
bin/tests/system/rpz/test5
bin/tests/system/rpz/tests.sh
bin/tests/system/start.pl
doc/arm/Bv9ARM-book.xml
lib/dns/db.c
lib/dns/include/dns/db.h
lib/dns/include/dns/log.h
lib/dns/include/dns/rpz.h
lib/dns/log.c
lib/dns/rbtdb.c
lib/dns/rpz.c
lib/isccfg/namedconf.c

index b74c49c683aece3492840ea393547db55a1feae5..c78a3128d0109aa03fb0fed446d2b6390cee75e3 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: query.c,v 1.373 2011/10/12 23:46:33 tbox Exp $ */
+/* $Id: query.c,v 1.374 2011/10/13 01:32:32 vjs Exp $ */
 
 /*! \file */
 
@@ -830,57 +830,41 @@ query_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
 }
 
 static void
-rpz_log(ns_client_t *client) {
-       char namebuf1[DNS_NAME_FORMATSIZE];
-       char namebuf2[DNS_NAME_FORMATSIZE];
-       dns_rpz_st_t *st;
-       const char *pat;
+rpz_log_rewrite(ns_client_t *client, const char *disabled,
+               dns_rpz_policy_t policy, dns_rpz_type_t type,
+               dns_name_t *rpz_qname) {
+       char qname_buf[DNS_NAME_FORMATSIZE];
+       char rpz_qname_buf[DNS_NAME_FORMATSIZE];
 
-       if (!ns_g_server->log_queries ||
-           !isc_log_wouldlog(ns_g_lctx, DNS_RPZ_INFO_LEVEL))
+       if (!isc_log_wouldlog(ns_g_lctx, DNS_RPZ_INFO_LEVEL))
                return;
 
-       st = client->query.rpz_st;
-       dns_name_format(client->query.qname, namebuf1, sizeof(namebuf1));
-       dns_name_format(st->qname, namebuf2, sizeof(namebuf2));
+       dns_name_format(client->query.qname, qname_buf, sizeof(qname_buf));
+       dns_name_format(rpz_qname, rpz_qname_buf, sizeof(rpz_qname_buf));
 
-       switch (st->m.policy) {
-       case DNS_RPZ_POLICY_NO_OP:
-               pat ="response policy %s rewrite %s NO-OP using %s";
-               break;
-       case DNS_RPZ_POLICY_NXDOMAIN:
-               pat = "response policy %s rewrite %s to NXDOMAIN using %s";
-               break;
-       case DNS_RPZ_POLICY_NODATA:
-               pat = "response policy %s rewrite %s to NODATA using %s";
-               break;
-       case DNS_RPZ_POLICY_RECORD:
-       case DNS_RPZ_POLICY_CNAME:
-               pat = "response policy %s rewrite %s using %s";
-               break;
-       default:
-               INSIST(0);
-       }
-       ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY,
-                     DNS_RPZ_INFO_LEVEL, pat, dns_rpz_type2str(st->m.type),
-                     namebuf1, namebuf2);
+       ns_client_log(client, DNS_LOGCATEGORY_RPZ, NS_LOGMODULE_QUERY,
+                     DNS_RPZ_INFO_LEVEL, "%srpz %s %s rewrite %s via %s",
+                     disabled,
+                     dns_rpz_type2str(type), dns_rpz_policy2str(policy),
+                     qname_buf, rpz_qname_buf);
 }
 
 static void
-rpz_fail_log(ns_client_t *client, int level, dns_rpz_type_t rpz_type,
-            dns_name_t *name, const char *str, isc_result_t result)
+rpz_log_fail(ns_client_t *client, int level,
+            dns_rpz_type_t rpz_type, dns_name_t *name,
+            const char *str, isc_result_t result)
 {
        char namebuf1[DNS_NAME_FORMATSIZE];
        char namebuf2[DNS_NAME_FORMATSIZE];
 
-       if (!ns_g_server->log_queries || !isc_log_wouldlog(ns_g_lctx, level))
+       if (!isc_log_wouldlog(ns_g_lctx, level))
                return;
 
        dns_name_format(client->query.qname, namebuf1, sizeof(namebuf1));
        dns_name_format(name, namebuf2, sizeof(namebuf2));
        ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS,
                      NS_LOGMODULE_QUERY, level,
-                     "response policy %s rewrite %s via %s %sfailed: %s",
+                     "rpz %s rewrite %s via %s %sfailed: %s",
                      dns_rpz_type2str(rpz_type),
                      namebuf1, namebuf2, str, isc_result_totext(result));
 }
@@ -889,9 +873,8 @@ rpz_fail_log(ns_client_t *client, int level, dns_rpz_type_t rpz_type,
  * Get a policy rewrite zone database.
  */
 static isc_result_t
-rpz_getdb(ns_client_t *client, dns_rpz_type_t rpz_type,
-         dns_name_t *rpz_qname, dns_zone_t **zonep,
-         dns_db_t **dbp, dns_dbversion_t **versionp)
+rpz_getdb(ns_client_t *client, dns_rpz_type_t rpz_type, dns_name_t *rpz_qname,
+         dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp)
 {
        char namebuf1[DNS_NAME_FORMATSIZE];
        char namebuf2[DNS_NAME_FORMATSIZE];
@@ -901,12 +884,11 @@ rpz_getdb(ns_client_t *client, dns_rpz_type_t rpz_type,
        result = query_getzonedb(client, rpz_qname, dns_rdatatype_any,
                                 DNS_GETDB_IGNOREACL, zonep, dbp, &rpz_version);
        if (result == ISC_R_SUCCESS) {
-               if (ns_g_server->log_queries &&
-                   isc_log_wouldlog(ns_g_lctx, DNS_RPZ_DEBUG_LEVEL2)) {
+               if (isc_log_wouldlog(ns_g_lctx, DNS_RPZ_DEBUG_LEVEL2)) {
                        dns_name_format(client->query.qname, namebuf1,
                                        sizeof(namebuf1));
                        dns_name_format(rpz_qname, namebuf2, sizeof(namebuf2));
-                       ns_client_log(client, NS_LOGCATEGORY_QUERIES,
+                       ns_client_log(client, DNS_LOGCATEGORY_RPZ,
                                      NS_LOGMODULE_QUERY, DNS_RPZ_DEBUG_LEVEL2,
                                      "try rpz %s rewrite %s via %s",
                                      dns_rpz_type2str(rpz_type),
@@ -915,7 +897,7 @@ rpz_getdb(ns_client_t *client, dns_rpz_type_t rpz_type,
                *versionp = rpz_version;
                return (ISC_R_SUCCESS);
        }
-       rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, rpz_type, rpz_qname,
+       rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, rpz_type, rpz_qname,
                     "query_getzonedb() ", result);
        return (result);
 }
@@ -3848,11 +3830,11 @@ rpz_st_clear(ns_client_t *client) {
        if (st->m.rdataset != NULL)
                query_putrdataset(client, &st->m.rdataset);
 
-       rpz_clean(NULL, &st->ns.db, NULL, NULL);
-       if (st->ns.ns_rdataset != NULL)
-               query_putrdataset(client, &st->ns.ns_rdataset);
-       if (st->ns.r_rdataset != NULL)
-               query_putrdataset(client, &st->ns.r_rdataset);
+       rpz_clean(NULL, &st->r.db, NULL, NULL);
+       if (st->r.ns_rdataset != NULL)
+               query_putrdataset(client, &st->r.ns_rdataset);
+       if (st->r.r_rdataset != NULL)
+               query_putrdataset(client, &st->r.r_rdataset);
 
        rpz_clean(&st->q.zone, &st->q.db, &st->q.node, NULL);
        if (st->q.rdataset != NULL)
@@ -3860,15 +3842,18 @@ rpz_st_clear(ns_client_t *client) {
        if (st->q.sigrdataset != NULL)
                query_putrdataset(client, &st->q.sigrdataset);
        st->state = 0;
+       st->m.type = DNS_RPZ_TYPE_BAD;
+       st->m.policy = DNS_RPZ_POLICY_MISS;
 }
 
 /*
- * Get NS, A, or AAAA rrset for rpz nsdname or nsip checking.
+ * Get NS, A, or AAAA rrset for response policy zone checks.
  */
 static isc_result_t
-rpz_ns_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
-           dns_db_t **dbp, dns_dbversion_t *version,
-           dns_rdataset_t **rdatasetp, isc_boolean_t resuming)
+rpz_rrset_find(ns_client_t *client, dns_rpz_type_t rpz_type,
+              dns_name_t *name, dns_rdatatype_t type,
+              dns_db_t **dbp, dns_dbversion_t *version,
+              dns_rdataset_t **rdatasetp, isc_boolean_t resuming)
 {
        dns_rpz_st_t *st;
        isc_boolean_t is_zone;
@@ -3884,22 +3869,22 @@ rpz_ns_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
 
        st = client->query.rpz_st;
        if ((st->state & DNS_RPZ_RECURSING) != 0) {
-               INSIST(st->ns.r_type == type);
+               INSIST(st->r.r_type == type);
                INSIST(dns_name_equal(name, st->r_name));
                INSIST(*rdatasetp == NULL ||
                       !dns_rdataset_isassociated(*rdatasetp));
                st->state &= ~DNS_RPZ_RECURSING;
-               *dbp = st->ns.db;
-               st->ns.db = NULL;
+               *dbp = st->r.db;
+               st->r.db = NULL;
                if (*rdatasetp != NULL)
                        query_putrdataset(client, rdatasetp);
-               *rdatasetp = st->ns.r_rdataset;
-               st->ns.r_rdataset = NULL;
-               result = st->ns.r_result;
+               *rdatasetp = st->r.r_rdataset;
+               st->r.r_rdataset = NULL;
+               result = st->r.r_result;
                if (result == DNS_R_DELEGATION) {
-                       rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL,
-                                    DNS_RPZ_TYPE_NSIP, name,
-                                    "rpz_ns_find() ", result);
+                       rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
+                                    rpz_type, name,
+                                    "rpz_rrset_find(1) ", result);
                        st->m.policy = DNS_RPZ_POLICY_ERROR;
                        result = DNS_R_SERVFAIL;
                }
@@ -3921,9 +3906,9 @@ rpz_ns_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
                result = query_getdb(client, name, type, 0, &zone, dbp,
                                     &version, &is_zone);
                if (result != ISC_R_SUCCESS) {
-                       rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL,
-                                    DNS_RPZ_TYPE_NSIP, name, "NS getdb() ",
-                                    result);
+                       rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
+                                    rpz_type, name,
+                                    "rpz_rrset_find(2) ", result);
                        st->m.policy = DNS_RPZ_POLICY_ERROR;
                        if (zone != NULL)
                                dns_zone_detach(&zone);
@@ -3936,8 +3921,9 @@ rpz_ns_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
        node = NULL;
        dns_fixedname_init(&fixed);
        found = dns_fixedname_name(&fixed);
-       result = dns_db_findext(*dbp, name, version, type, 0, client->now,
-                               &node, found, &cm, &ci, *rdatasetp, NULL);
+       result = dns_db_findext(*dbp, name, version, type, DNS_DBFIND_GLUEOK,
+                               client->now, &node, found,
+                               &cm, &ci, *rdatasetp, NULL);
        if (result == DNS_R_DELEGATION && is_zone && USECACHE(client)) {
                /*
                 * Try the cache if we're authoritative for an
@@ -3952,16 +3938,21 @@ rpz_ns_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
        }
        rpz_clean(NULL, dbp, &node, NULL);
        if (result == DNS_R_DELEGATION) {
+               rpz_clean(NULL, NULL, NULL, rdatasetp);
                /*
-                * Recurse to get NS rrset or A or AAAA rrset for an NS name.
+                * Recurse for NS rrset or A or AAAA rrset for an NS.
+                * Do not recurse for addresses for the query name.
                 */
-               rpz_clean(NULL, NULL, NULL, rdatasetp);
-               dns_name_copy(name, st->r_name, NULL);
-               result = query_recurse(client, type, st->r_name, NULL, NULL,
-                                      resuming);
-               if (result == ISC_R_SUCCESS) {
-                       st->state |= DNS_RPZ_RECURSING;
-                       result = DNS_R_DELEGATION;
+               if (rpz_type == DNS_RPZ_TYPE_IP) {
+                       result = DNS_R_NXRRSET;
+               } else {
+                       dns_name_copy(name, st->r_name, NULL);
+                       result = query_recurse(client, type, st->r_name,
+                                              NULL, NULL, resuming);
+                       if (result == ISC_R_SUCCESS) {
+                               st->state |= DNS_RPZ_RECURSING;
+                               result = DNS_R_DELEGATION;
+                       }
                }
        }
        return (result);
@@ -3979,7 +3970,7 @@ rpz_rewrite_ip(ns_client_t *client, dns_rdataset_t *rdataset,
        dns_dbversion_t *version;
        dns_zone_t *zone;
        dns_db_t *db;
-       dns_rpz_zone_t *new_rpz;
+       dns_rpz_zone_t *rpz;
        isc_result_t result;
 
        st = client->query.rpz_st;
@@ -3990,16 +3981,26 @@ rpz_rewrite_ip(ns_client_t *client, dns_rdataset_t *rdataset,
        }
        zone = NULL;
        db = NULL;
-       for (new_rpz = ISC_LIST_HEAD(client->view->rpz_zones);
-            new_rpz != NULL;
-            new_rpz = ISC_LIST_NEXT(new_rpz, link)) {
-               version = NULL;
+       for (rpz = ISC_LIST_HEAD(client->view->rpz_zones);
+            rpz != NULL;
+            rpz = ISC_LIST_NEXT(rpz, link)) {
+               /*
+                * Do not check policy zones that cannot replace a policy
+                * already known to match.
+                */
+               if (st->m.policy != DNS_RPZ_POLICY_MISS) {
+                       if (st->m.rpz->num < rpz->num)
+                               break;
+                       if (st->m.rpz->num == rpz->num &&
+                           st->m.type < rpz_type)
+                               continue;
+               }
 
                /*
-                * Find the database for this policy zone to get its
-                * radix tree.
+                * Find the database for this policy zone to get its radix tree.
                 */
-               result = rpz_getdb(client, rpz_type, &new_rpz->origin,
+               version = NULL;
+               result = rpz_getdb(client, rpz_type, &rpz->origin,
                                   &zone, &db, &version);
                if (result != ISC_R_SUCCESS) {
                        rpz_clean(&zone, &db, NULL, NULL);
@@ -4011,26 +4012,31 @@ rpz_rewrite_ip(ns_client_t *client, dns_rdataset_t *rdataset,
                 * hit, if any.  Note the domain name and quality of the
                 * best hit.
                 */
-               result = dns_db_rpz_findips(new_rpz, rpz_type, zone, db,
-                                           version, rdataset, st);
-               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+               (void)dns_db_rpz_findips(rpz, rpz_type, zone, db, version,
+                                        rdataset, st,
+                                        client->query.rpz_st->qname);
                rpz_clean(&zone, &db, NULL, NULL);
        }
        return (ISC_R_SUCCESS);
 }
 
+/*
+ * Look for an A or AAAA rdataset
+ * and check for IP or NSIP rewrite policy rules.
+ */
 static isc_result_t
-rpz_rewrite_nsip(ns_client_t *client, dns_rdatatype_t type, dns_name_t *name,
-                dns_db_t **dbp, dns_dbversion_t *version,
-                dns_rdataset_t **rdatasetp, isc_boolean_t resuming)
+rpz_rewrite_rrset(ns_client_t *client, dns_rpz_type_t rpz_type,
+                 dns_rdatatype_t type, dns_name_t *name,
+                 dns_db_t **dbp, dns_dbversion_t *version,
+                 dns_rdataset_t **rdatasetp, isc_boolean_t resuming)
 {
        isc_result_t result;
 
-       result = rpz_ns_find(client, name, type, dbp, version, rdatasetp,
-                            resuming);
+       result = rpz_rrset_find(client, rpz_type, name, type, dbp, version,
+                               rdatasetp, resuming);
        switch (result) {
        case ISC_R_SUCCESS:
-               result = rpz_rewrite_ip(client, *rdatasetp, DNS_RPZ_TYPE_NSIP);
+               result = rpz_rewrite_ip(client, *rdatasetp, rpz_type);
                break;
        case DNS_R_EMPTYNAME:
        case DNS_R_EMPTYWILD:
@@ -4038,23 +4044,76 @@ rpz_rewrite_nsip(ns_client_t *client, dns_rdatatype_t type, dns_name_t *name,
        case DNS_R_NCACHENXDOMAIN:
        case DNS_R_NXRRSET:
        case DNS_R_NCACHENXRRSET:
+       case ISC_R_NOTFOUND:
                result = ISC_R_SUCCESS;
                break;
        case DNS_R_DELEGATION:
        case DNS_R_DUPLICATE:
        case DNS_R_DROP:
                break;
+       case DNS_R_CNAME:
+       case DNS_R_DNAME:
+               rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, rpz_type,
+                            name, "NS address rewrite rrset ", result);
+               result = ISC_R_SUCCESS;
+               break;
        default:
                if (client->query.rpz_st->m.policy != DNS_RPZ_POLICY_ERROR) {
                        client->query.rpz_st->m.policy = DNS_RPZ_POLICY_ERROR;
-                       rpz_fail_log(client, ISC_LOG_WARNING, DNS_RPZ_TYPE_NSIP,
-                                    name, "NS address rewrite nsip ", result);
+                       rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, rpz_type,
+                                    name, "NS address rewrite rrset ", result);
                }
                break;
        }
        return (result);
 }
 
+/*
+ * Look for both A and AAAA rdatasets
+ * and check for IP or NSIP rewrite policy rules.
+ * Look only for addresses that will be in the ANSWER section
+ * when checking for IP rules.
+ */
+static isc_result_t
+rpz_rewrite_rrsets(ns_client_t *client, dns_rpz_type_t rpz_type,
+                  dns_name_t *name, dns_rdatatype_t type,
+                  dns_rdataset_t **rdatasetp, isc_boolean_t resuming)
+{
+       dns_rpz_st_t *st;
+       dns_dbversion_t *version;
+       dns_db_t *ipdb;
+       isc_result_t result;
+
+       st = client->query.rpz_st;
+       version = NULL;
+       ipdb = NULL;
+       if ((st->state & DNS_RPZ_DONE_IPv4) == 0 &&
+           ((rpz_type == DNS_RPZ_TYPE_NSIP) ?
+            (st->state & DNS_RPZ_HAVE_NSIPv4) :
+            (st->state & DNS_RPZ_HAVE_IP)) != 0 &&
+           (type == dns_rdatatype_any || type == dns_rdatatype_a)) {
+               result = rpz_rewrite_rrset(client, rpz_type, dns_rdatatype_a,
+                                          name, &ipdb, version, rdatasetp,
+                                          resuming);
+               if (result == ISC_R_SUCCESS)
+                       st->state |= DNS_RPZ_DONE_IPv4;
+       } else {
+               result = ISC_R_SUCCESS;
+       }
+       if (result == ISC_R_SUCCESS &&
+           ((rpz_type == DNS_RPZ_TYPE_NSIP) ?
+            (st->state & DNS_RPZ_HAVE_NSIPv6) :
+            (st->state & DNS_RPZ_HAVE_IP)) != 0 &&
+           (type == dns_rdatatype_any || type == dns_rdatatype_aaaa)) {
+               result = rpz_rewrite_rrset(client, rpz_type, dns_rdatatype_aaaa,
+                                          name, &ipdb, version, rdatasetp,
+                                          resuming);
+       }
+       if (ipdb != NULL)
+               dns_db_detach(&ipdb);
+       return (result);
+}
+
 /*
  * Get the rrset from a response policy zone.
  */
@@ -4105,7 +4164,7 @@ rpz_find(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qnamef,
                                             &rdsiter);
                if (result != ISC_R_SUCCESS) {
                        dns_db_detachnode(*dbp, nodep);
-                       rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, rpz_type,
+                       rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, rpz_type,
                                     qnamef, "allrdatasets()", result);
                        *policyp = DNS_RPZ_POLICY_ERROR;
                        return (DNS_R_SERVFAIL);
@@ -4122,7 +4181,7 @@ rpz_find(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qnamef,
                dns_rdatasetiter_destroy(&rdsiter);
                if (result != ISC_R_SUCCESS) {
                        if (result != ISC_R_NOMORE) {
-                               rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL,
+                               rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
                                             rpz_type, qnamef, "rdatasetiter",
                                             result);
                                *policyp = DNS_RPZ_POLICY_ERROR;
@@ -4152,7 +4211,8 @@ rpz_find(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qnamef,
                        policy = DNS_RPZ_POLICY_RECORD;
                } else {
                        policy = dns_rpz_decode_cname(*rdatasetp, sname);
-                       if (policy == DNS_RPZ_POLICY_RECORD &&
+                       if ((policy == DNS_RPZ_POLICY_RECORD ||
+                            policy == DNS_RPZ_POLICY_WILDCNAME) &&
                            qtype != dns_rdatatype_cname &&
                            qtype != dns_rdatatype_any)
                                result = DNS_R_CNAME;
@@ -4163,8 +4223,8 @@ rpz_find(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qnamef,
                 * DNAME policy RRs have very few if any uses that are not
                 * better served with simple wildcards.  Making the work would
                 * require complications to get the number of labels matched
-                * in the name or the found name itself to the main DNS_R_DNAME
-                * case in query_find(). So fall through to treat them as NODATA.
+                * in the name or the found name to the main DNS_R_DNAME case
+                * in query_find(). So fall through to treat them as NODATA.
                 */
        case DNS_R_NXRRSET:
                policy = DNS_RPZ_POLICY_NODATA;
@@ -4183,7 +4243,7 @@ rpz_find(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qnamef,
        default:
                dns_db_detach(dbp);
                dns_zone_detach(zonep);
-               rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL, rpz_type, qnamef,
+               rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, rpz_type, qnamef,
                             "", result);
                policy = DNS_RPZ_POLICY_ERROR;
                result = DNS_R_SERVFAIL;
@@ -4221,7 +4281,18 @@ rpz_rewrite_name(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
             rpz != NULL;
             rpz = ISC_LIST_NEXT(rpz, link)) {
                /*
-                * Construct the rule's owner name.
+                * Do not check policy zones that cannot replace a policy
+                * already known to match.
+                */
+               if (st->m.policy != DNS_RPZ_POLICY_MISS) {
+                       if (st->m.rpz->num < rpz->num)
+                               break;
+                       if (st->m.rpz->num == rpz->num &&
+                           st->m.type < rpz_type)
+                               continue;
+               }
+               /*
+                * Construct the policy's owner name.
                 */
                dns_fixedname_init(&prefixf);
                prefix = dns_fixedname_name(&prefixf);
@@ -4240,13 +4311,13 @@ rpz_rewrite_name(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
                        INSIST(result == DNS_R_NAMETOOLONG);
                        labels = dns_name_countlabels(prefix);
                        if (labels < 2) {
-                               rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL,
+                               rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
                                             rpz_type, suffix,
                                             "concatentate() ", result);
                                return (ISC_R_SUCCESS);
                        }
                        if (labels+1 == dns_name_countlabels(qname)) {
-                               rpz_fail_log(client, DNS_RPZ_DEBUG_LEVEL1,
+                               rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1,
                                             rpz_type, suffix,
                                             "concatentate() ", result);
                        }
@@ -4254,7 +4325,7 @@ rpz_rewrite_name(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
                }
 
                /*
-                * See if the qname rule (or RR) exists.
+                * See if the policy record exists.
                 */
                result = rpz_find(client, qtype, rpz_qname, qname, rpz_type,
                                  &zone, &db, &node, rdatasetp, &policy);
@@ -4268,14 +4339,31 @@ rpz_rewrite_name(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
                        return (DNS_R_SERVFAIL);
                default:
                        /*
-                        * when more than one name or address hits a rule,
-                        * prefer the first set of names (qname or NS),
-                        * the first policy zone, and the smallest name
+                        * We are dealing with names here.
+                        * With more than one applicable policy, prefer
+                        * the earliest configured policy,
+                        * QNAME over IP over NSDNAME over NSIP,
+                        * and the smallest name.
+                        * Because of the testing above,
+                        * we known st->m.rpz->num >= rpz->num  and either
+                        * st->m.rpz->num > rpz->num or st->m.type >= rpz_type
+                        */
+                       if (st->m.policy != DNS_RPZ_POLICY_MISS &&
+                           rpz->num == st->m.rpz->num &&
+                           (st->m.type < rpz_type ||
+                            (st->m.type == rpz_type &&
+                             0 >= dns_name_compare(rpz_qname, st->qname))))
+                               continue;
+
+                       /*
+                        * Merely log DNS_RPZ_POLICY_DISABLED hits.
                         */
-                       if (st->m.type == rpz_type &&
-                           rpz->num > st->m.rpz->num &&
-                           0 <= dns_name_compare(rpz_qname, st->qname))
+                       if (rpz->policy == DNS_RPZ_POLICY_DISABLED) {
+                               rpz_log_rewrite(client, "disabled ",
+                                               policy, rpz_type, rpz_qname);
                                continue;
+                       }
+
                        rpz_clean(&st->m.zone, &st->m.db, &st->m.node,
                                  &st->m.rdataset);
                        st->m.rpz = rpz;
@@ -4284,7 +4372,8 @@ rpz_rewrite_name(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
                        st->m.policy = policy;
                        st->m.result = result;
                        dns_name_copy(rpz_qname, st->qname, NULL);
-                       if (dns_rdataset_isassociated(*rdatasetp)) {
+                       if (*rdatasetp != NULL &&
+                           dns_rdataset_isassociated(*rdatasetp)) {
                                dns_rdataset_t *trdataset;
 
                                trdataset = st->m.rdataset;
@@ -4307,24 +4396,38 @@ rpz_rewrite_name(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
        return (ISC_R_SUCCESS);
 }
 
+static void
+rpz_rewrite_ns_skip(ns_client_t *client, dns_name_t *nsname,
+                   isc_result_t result, int level, const char *str)
+{
+       dns_rpz_st_t *st;
+
+       st = client->query.rpz_st;
+
+       if (str != NULL)
+               rpz_log_fail(client, level, DNS_RPZ_TYPE_NSIP, nsname,
+                            str, result);
+       if (st->r.ns_rdataset != NULL &&
+           dns_rdataset_isassociated(st->r.ns_rdataset))
+               dns_rdataset_disassociate(st->r.ns_rdataset);
+
+       st->r.label--;
+}
+
 /*
- * Look for response policy zone NSIP and NSDNAME rewriting.
+ * Look for response policy zone QNAME, NSIP, and NSDNAME rewriting.
  */
 static isc_result_t
-rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
+rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype, isc_result_t qresult,
            isc_boolean_t resuming)
 {
        dns_rpz_st_t *st;
-       dns_db_t *ipdb;
        dns_rdataset_t *rdataset;
        dns_fixedname_t nsnamef;
        dns_name_t *nsname;
-       dns_dbversion_t *version;
+       isc_boolean_t ck_ip;
        isc_result_t result;
 
-       ipdb = NULL;
-       rdataset = NULL;
-
        st = client->query.rpz_st;
        if (st == NULL) {
                st = isc_mem_get(client->mctx, sizeof(*st));
@@ -4332,7 +4435,9 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
                        return (ISC_R_NOMEMORY);
                st->state = 0;
                memset(&st->m, 0, sizeof(st->m));
-               memset(&st->ns, 0, sizeof(st->ns));
+               st->m.type = DNS_RPZ_TYPE_BAD;
+               st->m.policy = DNS_RPZ_POLICY_MISS;
+               memset(&st->r, 0, sizeof(st->r));
                memset(&st->q, 0, sizeof(st->q));
                dns_fixedname_init(&st->_qnamef);
                dns_fixedname_init(&st->_r_namef);
@@ -4342,78 +4447,147 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
                st->fname = dns_fixedname_name(&st->_fnamef);
                client->query.rpz_st = st;
        }
-       if ((st->state & DNS_RPZ_DONE_QNAME) == 0) {
-               st->state = DNS_RPZ_DONE_QNAME;
-               st->m.type = DNS_RPZ_TYPE_BAD;
-               st->m.policy = DNS_RPZ_POLICY_MISS;
 
+       /*
+        * There is nothing to rewrite if the main query failed.
+        */
+       switch (qresult) {
+       case ISC_R_SUCCESS:
+       case DNS_R_GLUE:
+       case DNS_R_ZONECUT:
+               ck_ip = ISC_TRUE;
+               break;
+       case DNS_R_EMPTYNAME:
+       case DNS_R_NXRRSET:
+       case DNS_R_NXDOMAIN:
+       case DNS_R_EMPTYWILD:
+       case DNS_R_NCACHENXDOMAIN:
+       case DNS_R_NCACHENXRRSET:
+       case DNS_R_CNAME:
+       case DNS_R_DNAME:
+               ck_ip = ISC_FALSE;
+               break;
+       case DNS_R_DELEGATION:
+       case ISC_R_NOTFOUND:
+               return (ISC_R_SUCCESS);
+       case ISC_R_FAILURE:
+       case ISC_R_TIMEDOUT:
+       case DNS_R_BROKENCHAIN:
+               rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL3, DNS_RPZ_TYPE_QNAME,
+                            client->query.qname,
+                            "stop on qresult in rpz_rewrite()",
+                            qresult);
+               return (ISC_R_SUCCESS);
+       default:
+               rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, DNS_RPZ_TYPE_QNAME,
+                            client->query.qname,
+                            "stop on unrecognized qresult in rpz_rewrite()",
+                            qresult);
+               return (ISC_R_SUCCESS);
+       }
+
+       rdataset = NULL;
+       if ((st->state & DNS_RPZ_DONE_QNAME) == 0) {
                /*
-                * Check rules for the name if this it the first time,
-                * i.e. we've not been recursing.
+                * Check rules for the query name if this it the first time
+                * for the current qname, i.e. we've not been recursing.
+                * There is a first time for each name in a CNAME chain.
                 */
-               st->state &= ~(DNS_RPZ_HAVE_IP | DNS_RPZ_HAVE_NSIPv4 |
-                              DNS_RPZ_HAVE_NSIPv6 | DNS_RPZ_HAD_NSDNAME);
                result = rpz_rewrite_name(client, qtype, client->query.qname,
                                          DNS_RPZ_TYPE_QNAME, &rdataset);
                if (result != ISC_R_SUCCESS)
                        goto cleanup;
-               if (st->m.policy != DNS_RPZ_POLICY_MISS)
-                       goto cleanup;
-               if ((st->state & (DNS_RPZ_HAVE_NSIPv4 | DNS_RPZ_HAVE_NSIPv6 |
-                                 DNS_RPZ_HAD_NSDNAME)) == 0)
+
+               st->r.label = dns_name_countlabels(client->query.qname);
+
+               st->state &= ~(DNS_RPZ_DONE_QNAME_IP | DNS_RPZ_DONE_IPv4);
+               st->state |= DNS_RPZ_DONE_QNAME;
+       }
+
+       /*
+        * Check known IP addresses for the query name.
+        * Any recursion required for the query has already happened.
+        * Do not check addresses that will not be in the ANSWER section.
+        */
+       if ((st->state & DNS_RPZ_DONE_QNAME_IP) == 0 &&
+           (st->state & DNS_RPZ_HAVE_IP) != 0 && ck_ip) {
+               result = rpz_rewrite_rrsets(client, DNS_RPZ_TYPE_IP,
+                                           client->query.qname, qtype,
+                                           &rdataset, resuming);
+               if (result != ISC_R_SUCCESS)
                        goto cleanup;
-               st->ns.label = dns_name_countlabels(client->query.qname);
+               st->state &= ~DNS_RPZ_DONE_IPv4;
+               st->state |= DNS_RPZ_DONE_QNAME_IP;
+       }
+
+       /*
+        * Stop looking for rules if there are none of the other kinds.
+        */
+       if ((st->state & (DNS_RPZ_HAVE_NSIPv4 | DNS_RPZ_HAVE_NSIPv6 |
+                         DNS_RPZ_HAVE_NSDNAME)) == 0) {
+               result = ISC_R_SUCCESS;
+               goto cleanup;
        }
 
        dns_fixedname_init(&nsnamef);
        dns_name_clone(client->query.qname, dns_fixedname_name(&nsnamef));
-       while (st->ns.label > 1 && st->m.policy == DNS_RPZ_POLICY_MISS) {
-               if (st->ns.label == dns_name_countlabels(client->query.qname)) {
+       while (st->r.label > 1) {
+               /*
+                * Get NS rrset for each domain in the current qname.
+                */
+               if (st->r.label == dns_name_countlabels(client->query.qname)) {
                        nsname = client->query.qname;
                } else {
                        nsname = dns_fixedname_name(&nsnamef);
-                       dns_name_split(client->query.qname, st->ns.label,
+                       dns_name_split(client->query.qname, st->r.label,
                                       NULL, nsname);
                }
-               if (st->ns.ns_rdataset == NULL ||
-                   !dns_rdataset_isassociated(st->ns.ns_rdataset)) {
+               if (st->r.ns_rdataset == NULL ||
+                   !dns_rdataset_isassociated(st->r.ns_rdataset)) {
                        dns_db_t *db = NULL;
-                       result = rpz_ns_find(client, nsname, dns_rdatatype_ns,
-                                            &db, NULL, &st->ns.ns_rdataset,
-                                            resuming);
+                       result = rpz_rrset_find(client, DNS_RPZ_TYPE_NSDNAME,
+                                               nsname, dns_rdatatype_ns,
+                                               &db, NULL, &st->r.ns_rdataset,
+                                               resuming);
                        if (db != NULL)
                                dns_db_detach(&db);
-                       if (result != ISC_R_SUCCESS) {
-                               if (result == DNS_R_DELEGATION)
+                       if (st->m.policy == DNS_RPZ_POLICY_ERROR)
+                               goto cleanup;
+                       switch (result) {
+                       case ISC_R_SUCCESS:
+                               result = dns_rdataset_first(st->r.ns_rdataset);
+                               if (result != ISC_R_SUCCESS)
                                        goto cleanup;
-                               if (result == DNS_R_EMPTYNAME ||
-                                   result == DNS_R_NXRRSET ||
-                                   result == DNS_R_EMPTYWILD ||
-                                   result == DNS_R_NXDOMAIN ||
-                                   result == DNS_R_NCACHENXDOMAIN ||
-                                   result == DNS_R_NCACHENXRRSET ||
-                                   result == DNS_R_CNAME ||
-                                   result == DNS_R_DNAME) {
-                                       rpz_fail_log(client,
-                                                    DNS_RPZ_DEBUG_LEVEL2,
-                                                    DNS_RPZ_TYPE_NSIP, nsname,
-                                                    "NS db_find() ", result);
-                                       dns_rdataset_disassociate(st->ns.
-                                                       ns_rdataset);
-                                       st->ns.label--;
-                                       continue;
-                               }
-                               if (st->m.policy != DNS_RPZ_POLICY_ERROR) {
-                                       rpz_fail_log(client, DNS_RPZ_INFO_LEVEL,
-                                                    DNS_RPZ_TYPE_NSIP, nsname,
-                                                    "NS db_find() ", result);
-                                       st->m.policy = DNS_RPZ_POLICY_ERROR;
-                               }
+                               st->state &= ~(DNS_RPZ_DONE_NSDNAME |
+                                              DNS_RPZ_DONE_IPv4);
+                               break;
+                       case DNS_R_DELEGATION:
                                goto cleanup;
+                       case DNS_R_EMPTYNAME:
+                       case DNS_R_NXRRSET:
+                       case DNS_R_EMPTYWILD:
+                       case DNS_R_NXDOMAIN:
+                       case DNS_R_NCACHENXDOMAIN:
+                       case DNS_R_NCACHENXRRSET:
+                       case ISC_R_NOTFOUND:
+                       case DNS_R_CNAME:
+                       case DNS_R_DNAME:
+                               rpz_rewrite_ns_skip(client, nsname, result,
+                                                   0, NULL);
+                               continue;
+                       case ISC_R_TIMEDOUT:
+                       case DNS_R_BROKENCHAIN:
+                       case ISC_R_FAILURE:
+                               rpz_rewrite_ns_skip(client, nsname, result,
+                                               DNS_RPZ_DEBUG_LEVEL3,
+                                               "NS db_find() ");
+                               continue;
+                       default:
+                               rpz_rewrite_ns_skip(client, nsname, result,
+                                               DNS_RPZ_INFO_LEVEL,
+                                               "unrecognized NS db_find() ");
+                               continue;
                        }
-                       result = dns_rdataset_first(st->ns.ns_rdataset);
-                       if (result != ISC_R_SUCCESS)
-                               goto cleanup;
                }
                /*
                 * Check all NS names.
@@ -4422,17 +4596,30 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
                        dns_rdata_ns_t ns;
                        dns_rdata_t nsrdata = DNS_RDATA_INIT;
 
-                       dns_rdataset_current(st->ns.ns_rdataset, &nsrdata);
+                       dns_rdataset_current(st->r.ns_rdataset, &nsrdata);
                        result = dns_rdata_tostruct(&nsrdata, &ns, NULL);
                        dns_rdata_reset(&nsrdata);
                        if (result != ISC_R_SUCCESS) {
-                               rpz_fail_log(client, DNS_RPZ_ERROR_LEVEL,
+                               rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
                                             DNS_RPZ_TYPE_NSIP, nsname,
                                             "rdata_tostruct() ", result);
                                st->m.policy = DNS_RPZ_POLICY_ERROR;
                                goto cleanup;
                        }
-                       if ((st->state & DNS_RPZ_HAD_NSDNAME) != 0) {
+                       /*
+                        * Do nothing about "NS ."
+                        */
+                       if (dns_name_equal(&ns.name, dns_rootname)) {
+                               dns_rdata_freestruct(&ns);
+                               result = dns_rdataset_next(st->r.ns_rdataset);
+                               continue;
+                       }
+                       /*
+                        * Check this NS name if we did not handle it
+                        * during a previous recursion.
+                        */
+                       if ((st->state & DNS_RPZ_DONE_NSDNAME) == 0 &&
+                           (st->state & DNS_RPZ_HAVE_NSDNAME) != 0) {
                                result = rpz_rewrite_name(client, qtype,
                                                        &ns.name,
                                                        DNS_RPZ_TYPE_NSDNAME,
@@ -4441,42 +4628,23 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
                                        dns_rdata_freestruct(&ns);
                                        goto cleanup;
                                }
+                               st->state |= DNS_RPZ_DONE_NSDNAME;
                        }
                        /*
-                        * Check all IP addresses for this NS name, but don't
-                        * bother without NSIP rules or with a NSDNAME hit.
+                        * Check all IP addresses for this NS name.
                         */
-                       version = NULL;
-                       if ((st->state & DNS_RPZ_HAVE_NSIPv4) != 0 &&
-                           st->m.type != DNS_RPZ_TYPE_NSDNAME &&
-                           (st->state & DNS_RPZ_DONE_A) == 0) {
-                               result = rpz_rewrite_nsip(client,
-                                                         dns_rdatatype_a,
-                                                         &ns.name, &ipdb,
-                                                         version, &rdataset,
-                                                         resuming);
-                               if (result == ISC_R_SUCCESS)
-                                       st->state |= DNS_RPZ_DONE_A;
-                       }
-                       if (result == ISC_R_SUCCESS &&
-                           (st->state & DNS_RPZ_HAVE_NSIPv6) != 0 &&
-                           st->m.type != DNS_RPZ_TYPE_NSDNAME) {
-                               result = rpz_rewrite_nsip(client,
-                                                         dns_rdatatype_aaaa,
-                                                         &ns.name, &ipdb,
-                                                         version, &rdataset,
-                                                         resuming);
-                       }
+                       result = rpz_rewrite_rrsets(client, DNS_RPZ_TYPE_NSIP,
+                                                   &ns.name, dns_rdatatype_any,
+                                                   &rdataset, resuming);
                        dns_rdata_freestruct(&ns);
-                       if (ipdb != NULL)
-                               dns_db_detach(&ipdb);
                        if (result != ISC_R_SUCCESS)
                                goto cleanup;
-                       st->state &= ~DNS_RPZ_DONE_A;
-                       result = dns_rdataset_next(st->ns.ns_rdataset);
+                       st->state &= ~(DNS_RPZ_DONE_NSDNAME |
+                                      DNS_RPZ_DONE_IPv4);
+                       result = dns_rdataset_next(st->r.ns_rdataset);
                } while (result == ISC_R_SUCCESS);
-               dns_rdataset_disassociate(st->ns.ns_rdataset);
-               st->ns.label--;
+               dns_rdataset_disassociate(st->r.ns_rdataset);
+               st->r.label--;
        }
 
        /*
@@ -4486,31 +4654,76 @@ rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype,
 
 cleanup:
        if (st->m.policy != DNS_RPZ_POLICY_MISS &&
-           st->m.policy != DNS_RPZ_POLICY_NO_OP &&
            st->m.policy != DNS_RPZ_POLICY_ERROR &&
            st->m.rpz->policy != DNS_RPZ_POLICY_GIVEN)
                st->m.policy = st->m.rpz->policy;
-       if (st->m.policy == DNS_RPZ_POLICY_NO_OP)
-               rpz_log(client);
        if (st->m.policy == DNS_RPZ_POLICY_MISS ||
-           st->m.policy == DNS_RPZ_POLICY_NO_OP ||
-           st->m.policy == DNS_RPZ_POLICY_ERROR)
+           st->m.policy == DNS_RPZ_POLICY_PASSTHRU ||
+           st->m.policy == DNS_RPZ_POLICY_ERROR) {
+               if (st->m.policy == DNS_RPZ_POLICY_PASSTHRU)
+                       rpz_log_rewrite(client, "", st->m.policy, st->m.type,
+                                       st->qname);
                rpz_clean(&st->m.zone, &st->m.db, &st->m.node, &st->m.rdataset);
-       if (st->m.policy != DNS_RPZ_POLICY_MISS)
-               st->state |= DNS_RPZ_REWRITTEN;
+       }
        if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
                st->m.type = DNS_RPZ_TYPE_BAD;
                result = DNS_R_SERVFAIL;
        }
-       if (rdataset != NULL)
-               query_putrdataset(client, &rdataset);
-       if ((st->state & DNS_RPZ_RECURSING) == 0) {
-               rpz_clean(NULL, &st->ns.db, NULL, &st->ns.ns_rdataset);
-       }
+       query_putrdataset(client, &rdataset);
+       if ((st->state & DNS_RPZ_RECURSING) == 0)
+               rpz_clean(NULL, &st->r.db, NULL, &st->r.ns_rdataset);
 
        return (result);
 }
 
+/*
+ * Add a CNAME to the query response, including translating foo.evil.com and
+ *     *.evil.com CNAME *.example.com
+ * to
+ *     foo.evil.com CNAME foo.evil.com.example.com
+ */
+static isc_result_t
+rpz_add_cname(ns_client_t *client, dns_rpz_st_t *st,
+             dns_name_t *cname, dns_name_t *fname, isc_buffer_t *dbuf)
+{
+       dns_fixedname_t prefix, suffix;
+       unsigned int labels;
+       isc_result_t result;
+
+       labels = dns_name_countlabels(cname);
+       if (labels > 2 && dns_name_iswildcard(cname)) {
+               dns_fixedname_init(&prefix);
+               dns_name_split(client->query.qname, 1,
+                              dns_fixedname_name(&prefix), NULL);
+               dns_fixedname_init(&suffix);
+               dns_name_split(cname, labels-1,
+                              NULL, dns_fixedname_name(&suffix));
+               result = dns_name_concatenate(dns_fixedname_name(&prefix),
+                                             dns_fixedname_name(&suffix),
+                                             fname, NULL);
+               if (result == DNS_R_NAMETOOLONG)
+                       client->message->rcode = dns_rcode_yxdomain;
+       } else {
+               result = dns_name_copy(cname, fname, NULL);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       }
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       query_keepname(client, fname, dbuf);
+       result = query_add_cname(client, client->query.qname,
+                                fname, dns_trust_authanswer, st->m.ttl);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       rpz_log_rewrite(client, "", st->m.policy, st->m.type, st->qname);
+       ns_client_qnamereplace(client, fname);
+       /*
+        * Turn off DNSSEC because the results of a
+        * response policy zone cannot verify.
+        */
+       client->attributes &= ~NS_CLIENTATTR_WANTDNSSEC;
+       return (ISC_R_SUCCESS);
+}
+
 #define MAX_RESTARTS 16
 
 #define QUERY_ERROR(r) \
@@ -5208,14 +5421,12 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                        rpz_st->q.sigrdataset = NULL;
                        qtype = rpz_st->q.qtype;
 
+                       rpz_st->r.db = event->db;
                        if (event->node != NULL)
-                               dns_db_detachnode(db, &event->node);
-                       rpz_st->ns.db = event->db;
-                       rpz_st->ns.r_type = event->qtype;
-                       rpz_st->ns.r_rdataset = event->rdataset;
-                       if (event->sigrdataset != NULL &&
-                           dns_rdataset_isassociated(event->sigrdataset))
-                               dns_rdataset_disassociate(event->sigrdataset);
+                               dns_db_detachnode(event->db, &event->node);
+                       rpz_st->r.r_type = event->qtype;
+                       rpz_st->r.r_rdataset = event->rdataset;
+                       query_putrdataset(client, &event->sigrdataset);
                } else {
                        authoritative = ISC_FALSE;
 
@@ -5266,7 +5477,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                }
                if (rpz_st != NULL &&
                    (rpz_st->state & DNS_RPZ_RECURSING) != 0) {
-                       rpz_st->ns.r_result = event->result;
+                       rpz_st->r.r_result = event->result;
                        result = rpz_st->q.result;
                        isc_event_free(ISC_EVENT_PTR(&event));
                } else {
@@ -5429,13 +5640,12 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
 
        if (!ISC_LIST_EMPTY(client->view->rpz_zones) &&
            RECURSIONOK(client) && !RECURSING(client) &&
-           result != DNS_R_DELEGATION && result != ISC_R_NOTFOUND &&
            (client->query.rpz_st == NULL ||
             (client->query.rpz_st->state & DNS_RPZ_REWRITTEN) == 0) &&
            !dns_name_equal(client->query.qname, dns_rootname)) {
                isc_result_t rresult;
 
-               rresult = rpz_rewrite(client, qtype, resuming);
+               rresult = rpz_rewrite(client, qtype, result, resuming);
                rpz_st = client->query.rpz_st;
                switch (rresult) {
                case ISC_R_SUCCESS:
@@ -5466,16 +5676,19 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                        RECURSE_ERROR(rresult);
                        goto cleanup;
                }
+               if (rpz_st->m.policy != DNS_RPZ_POLICY_MISS)
+                       rpz_st->state |= DNS_RPZ_REWRITTEN;
                if (rpz_st->m.policy != DNS_RPZ_POLICY_MISS &&
-                   rpz_st->m.policy != DNS_RPZ_POLICY_NO_OP) {
-                       result = dns_name_copy(client->query.qname, fname,
-                                              NULL);
-                       RUNTIME_CHECK(result == ISC_R_SUCCESS);
- finish_rewrite:
-                       rpz_clean(&zone, &db, &node, NULL);
+                   rpz_st->m.policy != DNS_RPZ_POLICY_PASSTHRU &&
+                   rpz_st->m.policy != DNS_RPZ_POLICY_ERROR) {
+                       if (rpz_st->m.type == DNS_RPZ_TYPE_QNAME) {
+                               result = dns_name_copy(client->query.qname,
+                                                      fname, NULL);
+                               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                       }
+                       rpz_clean(&zone, &db, &node, NULL);
                        if (rpz_st->m.rdataset != NULL) {
-                               if (rdataset != NULL)
-                                       query_putrdataset(client, &rdataset);
+                               query_putrdataset(client, &rdataset);
                                rdataset = rpz_st->m.rdataset;
                                rpz_st->m.rdataset = NULL;
                        } else if (rdataset != NULL &&
@@ -5489,7 +5702,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                        zone = rpz_st->m.zone;
                        rpz_st->m.zone = NULL;
 
-                       result = rpz_st->m.result;
                        switch (rpz_st->m.policy) {
                        case DNS_RPZ_POLICY_NXDOMAIN:
                                result = DNS_R_NXDOMAIN;
@@ -5498,27 +5710,39 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                                result = DNS_R_NXRRSET;
                                break;
                        case DNS_RPZ_POLICY_RECORD:
+                               result = rpz_st->m.result;
                                if (type == dns_rdatatype_any &&
                                    result != DNS_R_CNAME &&
                                    dns_rdataset_isassociated(rdataset))
                                        dns_rdataset_disassociate(rdataset);
                                break;
-                       case DNS_RPZ_POLICY_CNAME:
-                               result = dns_name_copy(&rpz_st->m.rpz->cname,
-                                                      fname, NULL);
+                       case DNS_RPZ_POLICY_WILDCNAME:
+                               result = dns_rdataset_first(rdataset);
                                RUNTIME_CHECK(result == ISC_R_SUCCESS);
-                               query_keepname(client, fname, dbuf);
-                               result = query_add_cname(client,
-                                                       client->query.qname,
-                                                       fname,
-                                                       dns_trust_authanswer,
-                                                       rpz_st->m.ttl);
+                               dns_rdataset_current(rdataset, &rdata);
+                               result = dns_rdata_tostruct(&rdata, &cname,
+                                                           NULL);
+                               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                               dns_rdata_reset(&rdata);
+                               result = rpz_add_cname(client, rpz_st,
+                                                      &cname.cname,
+                                                      fname, dbuf);
+                               if (result != ISC_R_SUCCESS)
+                                       goto cleanup;
+                               fname = NULL;
+                               want_restart = ISC_TRUE;
+                               goto cleanup;
+                       case DNS_RPZ_POLICY_CNAME:
+                               /*
+                                * Add overridding CNAME from a named.conf
+                                * response-policy statement
+                                */
+                               result = rpz_add_cname(client, rpz_st,
+                                                      &rpz_st->m.rpz->cname,
+                                                      fname, dbuf);
                                if (result != ISC_R_SUCCESS)
                                        goto cleanup;
-                               ns_client_qnamereplace(client, fname);
                                fname = NULL;
-                               client->attributes &= ~NS_CLIENTATTR_WANTDNSSEC;
-                               rpz_log(client);
                                want_restart = ISC_TRUE;
                                goto cleanup;
                        default:
@@ -5530,11 +5754,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                         * response policy zone cannot verify.
                         */
                        client->attributes &= ~NS_CLIENTATTR_WANTDNSSEC;
-                       if (sigrdataset != NULL &&
-                           dns_rdataset_isassociated(sigrdataset))
-                               dns_rdataset_disassociate(sigrdataset);
+                       query_putrdataset(client, &sigrdataset);
                        is_zone = ISC_TRUE;
-                       rpz_log(client);
+                       rpz_log_rewrite(client, "", rpz_st->m.policy,
+                                       rpz_st->m.type, rpz_st->qname);
                }
        }
 
@@ -6427,53 +6650,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                        goto cleanup;
                }
 
-               /*
-                * Check all A and AAAA records in all response policy
-                * IP address zones
-                */
-               rpz_st = client->query.rpz_st;
-               if (rpz_st != NULL &&
-                   (rpz_st->state & DNS_RPZ_DONE_QNAME) != 0 &&
-                   (rpz_st->state & DNS_RPZ_REWRITTEN) == 0 &&
-                   RECURSIONOK(client) && !RECURSING(client) &&
-                   (rpz_st->state & DNS_RPZ_HAVE_IP) != 0) {
-                       for (result = dns_rdatasetiter_first(rdsiter);
-                            result == ISC_R_SUCCESS;
-                            result = dns_rdatasetiter_next(rdsiter)) {
-                               dns_rdatasetiter_current(rdsiter, rdataset);
-                               if (rdataset->type == dns_rdatatype_a ||
-                                   rdataset->type == dns_rdatatype_aaaa)
-                                       result = rpz_rewrite_ip(client,
-                                                             rdataset,
-                                                             DNS_RPZ_TYPE_IP);
-                               dns_rdataset_disassociate(rdataset);
-                               if (result != ISC_R_SUCCESS)
-                                       break;
-                       }
-                       if (result != ISC_R_NOMORE) {
-                               dns_rdatasetiter_destroy(&rdsiter);
-                               QUERY_ERROR(DNS_R_SERVFAIL);
-                               goto cleanup;
-                       }
-                       switch (rpz_st->m.policy) {
-                       case DNS_RPZ_POLICY_MISS:
-                               break;
-                       case DNS_RPZ_POLICY_NO_OP:
-                               rpz_log(client);
-                               rpz_st->state |= DNS_RPZ_REWRITTEN;
-                               break;
-                       case DNS_RPZ_POLICY_NXDOMAIN:
-                       case DNS_RPZ_POLICY_NODATA:
-                       case DNS_RPZ_POLICY_RECORD:
-                       case DNS_RPZ_POLICY_CNAME:
-                               dns_rdatasetiter_destroy(&rdsiter);
-                               rpz_st->state |= DNS_RPZ_REWRITTEN;
-                               goto finish_rewrite;
-                       default:
-                               INSIST(0);
-                       }
-               }
-
                /*
                 * Calling query_addrrset() with a non-NULL dbuf is going
                 * to either keep or release the name.  We don't want it to
@@ -6607,48 +6783,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                 * we know the answer.
                 */
 
-               /*
-                * Check all A and AAAA records in all response policy
-                * IP address zones
-                */
-               rpz_st = client->query.rpz_st;
-               if (rpz_st != NULL &&
-                   (rpz_st->state & DNS_RPZ_DONE_QNAME) != 0 &&
-                   (rpz_st->state & DNS_RPZ_REWRITTEN) == 0 &&
-                   RECURSIONOK(client) && !RECURSING(client) &&
-                   (rpz_st->state & DNS_RPZ_HAVE_IP) != 0 &&
-                   (qtype == dns_rdatatype_aaaa || qtype == dns_rdatatype_a)) {
-                       result = rpz_rewrite_ip(client, rdataset,
-                                               DNS_RPZ_TYPE_IP);
-                       if (result != ISC_R_SUCCESS) {
-                               QUERY_ERROR(DNS_R_SERVFAIL);
-                               goto cleanup;
-                       }
-                       /*
-                        * After a hit in the radix tree for the policy domain,
-                        * either stop trying to rewrite (DNS_RPZ_POLICY_NO_OP)
-                        * or restart to ask the ordinary database of the
-                        * policy zone for the DNS record corresponding to the
-                        * record in the radix tree.
-                        */
-                       switch (rpz_st->m.policy) {
-                       case DNS_RPZ_POLICY_MISS:
-                               break;
-                       case DNS_RPZ_POLICY_NO_OP:
-                               rpz_log(client);
-                               rpz_st->state |= DNS_RPZ_REWRITTEN;
-                               break;
-                       case DNS_RPZ_POLICY_NXDOMAIN:
-                       case DNS_RPZ_POLICY_NODATA:
-                       case DNS_RPZ_POLICY_RECORD:
-                       case DNS_RPZ_POLICY_CNAME:
-                               rpz_st->state |= DNS_RPZ_REWRITTEN;
-                               goto finish_rewrite;
-                       default:
-                               INSIST(0);
-                       }
-               }
-
 #ifdef ALLOW_FILTER_AAAA_ON_V4
                /*
                 * Optionally hide AAAAs from IPv4 clients if there is an A.
@@ -6856,9 +6990,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
         * General cleanup.
         */
        rpz_st = client->query.rpz_st;
-       if (rpz_st != NULL && (rpz_st->state & DNS_RPZ_RECURSING) == 0)
+       if (rpz_st != NULL && (rpz_st->state & DNS_RPZ_RECURSING) == 0) {
                rpz_clean(&rpz_st->m.zone, &rpz_st->m.db, &rpz_st->m.node,
                          &rpz_st->m.rdataset);
+               rpz_st->state &= ~DNS_RPZ_DONE_QNAME;
+       }
        if (rdataset != NULL)
                query_putrdataset(client, &rdataset);
        if (sigrdataset != NULL)
index 2ef3d3e3127a43fee4d29bb2f686cac9862cb7fe..9cf6c19b6bd26c0caa87eeb4f322f0f5b81a7795 100644 (file)
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: clean.sh,v 1.3 2011/01/13 04:59:24 tbox Exp $
+# $Id: clean.sh,v 1.4 2011/10/13 01:32:32 vjs Exp $
 
 
 # Clean up after rpz tests.
 
-rm -f dig.out* nsupdate.tmp
-rm -f  */named.memstats */named.run */session.key
-rm -f ns3/bl*.db */*.jnl
+rm -f proto.* dig.out* nsupdate.tmp
+rm -f  */named.memstats */named.run */named.rpz */session.key
+rm -f ns3/bl*.db */*.jnl */*.core */*.pid
index 36fd7ab6e7569fa8ee48bc30b028be2627124ee6..3adf0bf79ba93420eed5f5f92cf7adc5f71842df 100644 (file)
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: root.db,v 1.3 2011/01/13 04:59:24 tbox Exp $
+; $Id: root.db,v 1.4 2011/10/13 01:32:33 vjs Exp $
 
 $TTL   120
-@              SOA     s1. hostmaster.ns.s1. ( 1 3600 1200 604800 60 )
-@              NS      s1
-s1.            A       10.53.0.1
+@              SOA     ns. hostmaster.ns. ( 1 3600 1200 604800 60 )
+@              NS      ns.
+ns.            A       10.53.0.1
+.              A       10.53.0.1
 
 ; rewrite responses from this zone
 tld2.          NS      ns.tld2.
 ns.tld2.       A       10.53.0.2
+ns2.tld2.      A       10.53.0.2
 
 ; requests come from here
 tld3.          NS      ns.tld3.
 ns.tld3.       A       10.53.0.3
+
+; rewrite responses from this zone
+tld4.          NS      ns.tld4.
+ns.tld4.       A       10.53.0.4
+ns2.tld4.      A       10.53.0.4
index e6ad8425d668ee5ef7c673e7b81260fb3caec4a9..849e2e3ab4904ef3ab78c3c95536f7f0936e83d0 100644 (file)
@@ -12,7 +12,8 @@
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: hints,v 1.3 2011/01/13 04:59:25 tbox Exp $
+; $Id: hints,v 1.4 2011/10/13 01:32:33 vjs Exp $
 
-.      0       NS      s1.
-s1.    0       A       10.53.0.1
+
+.      0       NS      ns1.
+ns1.   0       A       10.53.0.1
index 5de1d51e7cea905b37f9454e93cb0f6cbca80c2f..581816fc47b6f89a121e039b1e11470e828b4630 100644 (file)
@@ -14,7 +14,8 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: named.conf,v 1.3 2011/01/13 04:59:25 tbox Exp $ */
+/* $Id: named.conf,v 1.4 2011/10/13 01:32:33 vjs Exp $ */
+
 
 controls { /* empty */ };
 
@@ -32,6 +33,10 @@ options {
 
 zone "." { type hint; file "hints"; };
 
-zone "tld2." {type master; file "tld2.db";};
-zone "sub1.tld2." {type master; file "tld2.db";};
-zone "sub2.sub1.tld2." {type master; file "tld2.db";};
+zone "tld2."               {type master; file "tld2.db";};
+zone "sub1.tld2."          {type master; file "tld2.db";};
+zone "subsub.sub1.tld2."    {type master; file "tld2.db";};
+zone "sub2.tld2."          {type master; file "tld2.db";};
+zone "subsub.sub2.tld2."    {type master; file "tld2.db";};
+zone "sub3.tld2."          {type master; file "tld2.db";};
+zone "subsub.sub3.tld2."    {type master; file "tld2.db";};
index 224f5e419070515523471a829594edc03718d109..5f5550a94c5ef57c920b32243cbb1436c6c6f6fb 100644 (file)
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: tld2.db,v 1.3 2011/01/13 04:59:25 tbox Exp $
+; $Id: tld2.db,v 1.4 2011/10/13 01:32:33 vjs Exp $
+
 
 ; RPZ rewrite responses from this zone
 
 $TTL   120
 @              SOA     tld2.  hostmaster.ns.tld2. ( 1 3600 1200 604800 60 )
-               NS      @
-               A       10.53.0.2
+               NS      ns
+               NS      ns2
+               NS      .                       ; check for RT 24985
+ns             A       10.53.0.2
+ns2            A       10.53.0.2
+
+
+txt-only       TXT     "txt-only-tld2"
 
-nodata         TXT     "nodata"
 a12            A       12.12.12.12
+               AAAA    2001::12
+               TXT     "a12 tld2 text"
+a12-cname      CNAME   a12
 
 a0-1           A       192.168.0.1
                AAAA    2001:2::1
-               TXT     "a0-1 text"
+               TXT     "a0-1 tld2 text"
 
 a3-1           A       192.168.3.1
                AAAA    2001:2:3::1
-               TXT     "a3-1 text"
+               TXT     "a3-1 tld2 text"
 
 a3-2           A       192.168.3.2
                AAAA    2001:2:3::2
-               TXT     "a3-2 text"
+               TXT     "a3-2 tld2 text"
+
+a3-3           A       192.168.3.3
+               AAAA    2001:2:3::3
+               TXT     "a3-3 tld2 text"
+
+a3-4           A       192.168.3.4
+               AAAA    2001:2:3::4
+               TXT     "a3-4 tld2 text"
+
+a3-5           A       192.168.3.5
+               AAAA    2001:2:3::5
+               TXT     "a3-5 tld2 text"
+
+a3-6           A       192.168.3.6
+               AAAA    2001:2:3::6
+               TXT     "a3-6 tld2 text"
+
+a3-7           A       192.168.3.7
+               AAAA    2001:2:3::7
+               TXT     "a3-7 tld2 text"
+
+a3-8           A       192.168.3.8
+               AAAA    2001:2:3::8
+               TXT     "a3-8 tld2 text"
+
+a3-9           A       192.168.3.9
+               AAAA    2001:2:3::9
+               TXT     "a3-9 tld2 text"
 
 a4-1           A       192.168.4.1
                AAAA    2001:2:4::1
-               TXT     "a4-1 text"
+               TXT     "a4-1 tld2 text"
 a4-1-aaaa      AAAA    2001:2:4::1
 
 a4-2           A       192.168.4.2
                AAAA    2001:2:4::2
-               TXT     "a4-2 text"
+               TXT     "a4-2 tld2 text"
+a4-2-cname     CNAME   a4-2
 
 a4-3           A       192.168.4.3
                AAAA    2001:2:4::3
-               TXT     "a4-3 text"
+               TXT     "a4-3 tld2 text"
+a4-3-cname     CNAME   a4-3
 
 a4-4           A       192.168.4.4
                AAAA    2001:2:4::4
-               TXT     "a4-4 text"
+               TXT     "a4-4 tld2 text"
+
+a4-5           A       192.168.4.5
+               AAAA    2001:2:4::5
+               TXT     "a4-5 tld2 text"
+a4-5-cname     CNAME   a4-5
+a4-5-cname2    CNAME   a4-5-cname
+a4-5-cname3    CNAME   a4-5-cname2
+
+a4-6           A       192.168.4.6
+               AAAA    2001:2:4::6
+               TXT     "a4-6 tld2 text"
+a4-6-cname     CNAME   a4-6
+a4-6-cname2    CNAME   a4-6-cname
+a4-6-cname3    CNAME   a4-6-cname2
+
+a5-1-2         A       192.168.5.1
+               A       192.168.5.2
+               TXT     "a5-1-2 tld2 text"
 
-a4-5           CNAME   a12
+a5-3           A       192.168.5.3
+               TXT     "a5-3 tld2 text"
 
+a5-4           A       192.168.5.4
+               TXT     "a5-4 tld2 text"
index 47b502ec436763c51da00f94a764acb74f59588d..23bf71d016fd8314e6e8f12213e42012304fbecb 100644 (file)
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: base.db,v 1.5 2011/06/09 00:42:50 marka Exp $
+; $Id: base.db,v 1.6 2011/10/13 01:32:33 vjs Exp $
+
 
 ; RPZ test
 
 $TTL   120
-@              SOA     tld3.  hostmaster.ns.tld3. ( 1 3600 1200 604800 60 )
-@              NS      ns.utld.
+@      SOA     blx.  hostmaster.ns.blx. ( 1 3600 1200 604800 60 )
+       NS      ns.tld.
+ns     A       10.53.0.3
 
 ; Poke the radix tree a little.
 128.1111.2222.3333.4444.5555.6666.7777.8888.rpz-ip     CNAME   .
@@ -30,7 +32,8 @@ $TTL  120
 128.zz.3333.4444.0.8777.8888.rpz-ip                    CNAME   .
 127.zz.3333.4444.0.8777.8888.rpz-ip                    CNAME   .
 
-; for testing rrset replacement
+
+; regression testing for some old crashes
 redirect       IN      A       127.0.0.1
 *.redirect     IN      A       127.0.0.1
-*.cname-redirect       IN      CNAME   google.com.
+*.credirect    IN      CNAME   google.com.
index e6ad8425d668ee5ef7c673e7b81260fb3caec4a9..849e2e3ab4904ef3ab78c3c95536f7f0936e83d0 100644 (file)
@@ -12,7 +12,8 @@
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: hints,v 1.3 2011/01/13 04:59:25 tbox Exp $
+; $Id: hints,v 1.4 2011/10/13 01:32:33 vjs Exp $
 
-.      0       NS      s1.
-s1.    0       A       10.53.0.1
+
+.      0       NS      ns1.
+ns1.   0       A       10.53.0.1
index b3483cbc4419beb6ee907b765cc94cccb9d2b744..c12b6f5d588af3b11be917951857ca8bd69d5ad8 100644 (file)
@@ -14,9 +14,8 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: named.conf,v 1.3 2011/01/13 04:59:25 tbox Exp $ */
+/* $Id: named.conf,v 1.4 2011/10/13 01:32:33 vjs Exp $ */
 
-controls { /* empty */ };
 
 options {
        query-source address 10.53.0.3;
@@ -31,47 +30,62 @@ options {
 
        response-policy {
            zone "bl";
-           zone "bl-given" policy given;
-           zone "bl-no-op" policy no-op;
-           zone "bl-nodata" policy nodata;
-           zone "bl-nxdomain" policy nxdomain;
-           zone "bl-cname" policy cname nodata.tld2.;
+           zone "bl-2";
+           zone "bl-given"     policy given;
+           zone "bl-passthru"  policy passthru;
+           zone "bl-no-op"     policy no-op;       # obsolete for passthru
+           zone "bl-disabled"  policy disabled;
+           zone "bl-nodata"    policy nodata;
+           zone "bl-nxdomain"  policy nxdomain;
+           zone "bl-cname"     policy cname txt-only.tld2.;
+           zone "bl-wildcname" policy cname *.tld4.;
+           zone "bl-garden"    policy cname a12.tld2.;
        };
 };
 
 key rndc_key {
-        secret "1234abcd8765";
-        algorithm hmac-md5;
+       secret "1234abcd8765";
+       algorithm hmac-md5;
 };
 controls {
-        inet 10.53.0.3 port 9953 allow { any; } keys { rndc_key; };
+       inet 10.53.0.3 port 9953 allow { any; } keys { rndc_key; };
 };
 
 logging {
-       category queries { default_stderr; };
+       # change "-c named.conf -d 99 -g" to "-c named.conf -d 99 -f"
+       #   in ../start.pl to check the rpz log category
+       channel rpz { severity debug 10;
+               print-category yes; print-time yes; print-severity yes;
+               file "named.rpz";};
+       category rpz { default_stderr; rpz; };
+       category queries { default_stderr; rpz; };
        category query-errors { default_stderr; };
 };
 
 
 zone "." { type hint; file "hints"; };
 
+zone "bl."             {type master; file "bl.db";
+                               allow-update {any;};};
+zone "bl-2."           {type master; file "bl-2.db";
+                               allow-update {any;};};
+zone "bl-given."       {type master; file "bl-given.db";
+                               allow-update {any;};};
+zone "bl-passthru."    {type master; file "bl-passthru.db";
+                               allow-update {any;};};
+zone "bl-no-op."       {type master; file "bl-no-op.db";
+                               allow-update {any;};};
+zone "bl-disabled."    {type master; file "bl-disabled.db";
+                               allow-update {any;};};
+zone "bl-nodata."      {type master; file "bl-nodata.db";
+                               allow-update {any;};};
+zone "bl-nxdomain."    {type master; file "bl-nxdomain.db";
+                               allow-update {any;};};
+zone "bl-cname."       {type master; file "bl-cname.db";
+                               allow-update {any;};};
+zone "bl-wildcname."   {type master; file "bl-wildcname.db";
+                               allow-update {any;};};
+zone "bl-garden."      {type master; file "bl-garden.db";
+                               allow-update {any;};};
 
-zone "bl."         {type master; file "bl.db";
-                       allow-update {any;};
-};
-zone "bl-given."    {type master; file "bl-given.db";
-                       allow-update {any;};
-};
-zone "bl-no-op."    {type master; file "bl-no-op.db";
-                       allow-update {any;};
-};
-zone "bl-nodata."   {type master; file "bl-nodata.db";
-                       allow-update {any;};
-};
-zone "bl-nxdomain." {type master; file "bl-nxdomain.db";
-                       allow-update {any;};
-};
-zone "bl-cname."    {type master; file "bl-cname.db";
-                       allow-update {any;};
-};
-
+zone "crash1.tld2"     {type master; file "crash1";};
index 1d74dcfdbb14880d5987d60ea4ddd2e5539b3b01..680e2378469a92e836550aeb5dcf6a532109fc60 100644 (file)
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: setup.sh,v 1.3 2011/01/13 04:59:24 tbox Exp $
+# $Id: setup.sh,v 1.4 2011/10/13 01:32:32 vjs Exp $
 
 sh clean.sh
 
-for NM in '' -given -no-op -nodata -nxdomain -cname; do
-    cp -f ns3/base.db ns3/bl$NM.db
+#  NO-OP is an obsolete synonym for PASSHTRU
+for NM in '' -2 -given -disabled -passthru -no-op -nodata -nxdomain -cname -wildcname -garden; do
+    sed -e "/SOA/s/blx/bl$NM/g" ns3/base.db >ns3/bl$NM.db
 done
index 3ad35d27bb6877ff9728753803ce0f4e86f5f565..5fd1336ce8ba2ada8901de50d3ff0008d5dd18cf 100644 (file)
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: test1,v 1.5 2011/06/09 03:10:17 marka Exp $
+; $Id: test1,v 1.6 2011/10/13 01:32:32 vjs Exp $
 
 
+; Use comment lines instead of blank lines to combine update requests into
+;      single requests
+; Separate update requests for distinct TLDs with blank lines or 'send'
+; End the file with a blank line or 'send'
+
 server 10.53.0.3 5300
 
+; QNAME tests
+
 ; NXDOMAIN
 update add  a0-1.tld2.bl.      300 CNAME .
-
+;
 ; NODATA
-update add  a1-1.tld2.bl.      300 CNAME *.
-;      and no assert-botch
-update add  a1-2.tld2.bl.      300 DNAME example.com.
-
-update add  *.sub1.tld2.bl.    300 A 12.12.12.12
-
+update add  a3-1.tld2.bl.      300 CNAME *.
+; and no assert-botch
+;      5
+update add  a3-2.tld2.bl.      300 DNAME example.com.
+;
+; NXDOMAIN for a4-2-cname.tld2 via its target a4-2.tld2.
+;      6 and 7
+update add  a4-2.tld2.bl       300 CNAME .
+;      8
+; NODATA for a4-3-cname.tld2 via its target a4-3.tld2.
+update add  a4-3.tld2.bl       300 CNAME *.
+;
+; replace the A for a4-1.sub1.tld2 with 12.12.12.12
+;      9
+update add  a4-1.sub1.tld2.bl. 300 A 12.12.12.12
+;
+; replace the A for *.sub2.tld2 with 12.12.12.12
+;      10
+update add  a4-1.sub2.tld2.bl. 300 A 12.12.12.12
+;
+; replace NXDOMAIN for {nxc1,nxc2}.sub1.tld2 with 12.12.12.12 using CNAMEs
+;      11
+update add nxc1.sub1.tld2.bl.  300 CNAME a12.tld2.
+;      12
+update add nxc2.sub1.tld2.bl.  300 CNAME a12-cname.tld2.
+;
+; prefer the first conflicting zone
+;      13
+update add a4-4.tld2.bl.       300 A   127.0.0.1
+send
+update add a4-4.tld2.bl-2.     300 A   127.0.0.2
+send
+;
+; wildcard CNAME
+;      14
+update add  a3-6.tld2.bl.      300 CNAME *.tld4.
+;      15
+update add  *.sub1.tld2.bl.    300 CNAME *.tld4.
+; CNAME chains
+;      16
+update add  a4-5.tld2.bl.      300 A   127.0.0.16
+;      17
+update add  a4-6.tld2.bl.      300 CNAME .
+update add  a4-6-cname.tld2.bl.        300 A   127.0.0.17
 send
index 7fff0e48075867ef2cb0b5443f91e69ce38d98df..9f157d99d6d7236ab7f999589e1f7f4d702cd544 100644 (file)
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: test2,v 1.4 2011/01/13 19:30:41 each Exp $
+; $Id: test2,v 1.5 2011/10/13 01:32:32 vjs Exp $
 
 
+; Use comment lines instead of blank lines to combine update requests into
+;      single requests
+; Separate update requests for distinct TLDs with blank lines or 'send'
+; End the file with a blank line or 'send'
+
+; IP tests
+
 server 10.53.0.3 5300
 
 ; NODATA a3-1.tld2
 update add  32.1.3.168.192.rpz-ip.bl   300 CNAME *.
-
-; NXDOMAIN for network of a4-1.tld2
+;
+; NXDOMAIN for 192.168.4.0/24, the network of a4-1.tld2
 update add  24.0.4.168.192.rpz-ip.bl   300 CNAME .
-
+;
 ; poke hole in NXDOMAIN CIDR block to leave a4-1.tld2 unchanged
 update add  32.1.4.168.192.rpz-ip.bl   300 CNAME 32.1.4.168.192
-
-; NODATA a4-3.tld2
+;
+; NODATA for a4-3.tld2
 update add  32.3.4.168.192.rpz-ip.bl   300 CNAME *.
-
+;
 ; NXDOMAIN for IPv6 a3-1.tld2
 update add  128.1.zz.3.2.2001.rpz-ip.bl        300 CNAME .
-
+;
+; apply the policy with the lexically smallest address of 192.168.5.1
+; to an RRset of more than one A RR
+update add  32.1.5.168.192.rpz-ip.bl   300 A   127.0.0.1
+update add  32.2.5.168.192.rpz-ip.bl   300 A   127.0.0.2
+;
+; prefer first conflicting IP zone for a5-3.tld2
+update add 32.3.5.168.192.rpz-ip.bl    300 A   127.0.0.1
+send
+update add 32.3.5.168.192.rpz-ip.bl-2  300 A   127.0.0.2
 send
+
+; prefer QNAME to IP for a5-4.tld2
+update add 32.4.5.168.192.rpz-ip.bl    300 CNAME a12.tld2.
+update add a5-4.tld2.bl                        300 CNAME a14.tld4.
+
+; wildcard CNAMEs
+;update add 
index c37c73e0103d0ee00462b4bb659a4d8f8a9c688a..fa8575f1b1be75aeae9a305bf4accff23c3d9f7d 100644 (file)
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: test3,v 1.4 2011/01/13 19:30:41 each Exp $
+; $Id: test3,v 1.5 2011/10/13 01:32:32 vjs Exp $
 
 
-server 10.53.0.3 5300
+; Use comment lines instead of blank lines to combine update requests into
+;      single requests
+; Separate update requests for distinct TLDs with blank lines or 'send'
+; End the file with a blank line or 'send'
+
+; NSDNAME tests
 
-update add  *.tld2.rpz-nsdname.bl.     300 CNAME .
+server 10.53.0.3 5300
 
+; NXDOMAIN for *.sub1.tld2 by NSDNAME
+update add  *.sub1.tld2.rpz-nsdname.bl.        300 CNAME .
+;
+; walled garden for *.sub2.tld2
+update add  *.sub2.tld2.rpz-nsdname.bl.        300 CNAME a12-cname.tld2.
+;
+; exempt a3-2.tld2 and anything in 192.168.0.0/24
+;   also checks that IP policies are preferred over NSDNAME policies
+update add  a3-2.tld2.bl               300 CNAME a3-2.tld2.
+update add  24.0.0.168.192.rpz-ip.bl   300 CNAME 24.0.0.168.192.
+;
+; prefer QNAME policy to NSDNAME policy
+update add  a4-1.tld2.bl.              300 A 12.12.12.12
+;
+; prefer policy for largest NS name
+update add  ns.sub3.tld2.rpz-nsdname.bl.       300 A   127.0.0.1
+update add  ns.subsub.sub3.tld2.rpz-nsdname.bl. 300 A  127.0.0.2
 send
index 9ed3d92360ffdf28f0fc894e8475a03e798cdbec..40bd83fa9dd2ee9ed73354877d7bbd420f1ffe2e 100644 (file)
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: test4,v 1.4 2011/01/13 19:30:41 each Exp $
+; $Id: test4,v 1.5 2011/10/13 01:32:33 vjs Exp $
 
 
+; Use comment lines instead of blank lines to combine update requests into
+;      single requests
+; Separate update requests for distinct TLDs with blank lines or 'send'
+; End the file with a blank line or 'send'
+
+; NSIP tests
+
 server 10.53.0.3 5300
 
+; NXDOMAIN for all of tld2 based on its server IP address
 update add  32.2.0.53.10.rpz-nsip.bl.  300 CNAME .
-
+;
+; exempt a3-2.tld2 and anything in 192.168.0.0/24
+;   also checks that IP policies are preferred over NSIP policies
+update add  a3-2.tld2.bl               300 CNAME a3-2.tld2.
+update add  24.0.0.168.192.rpz-ip.bl   300 CNAME 24.0.0.168.192.
+;
+; prefer NSIP policy to NSDNAME policy
+update add  ns.tld2.rpz-nsdname.bl.    300 CNAME 10.0.0.1
 send
index 8fae920519068cdfacaa968aa99014f59e106117..481118e49735ea4f3fe910e4302a232d425cf1a0 100644 (file)
 ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 ; PERFORMANCE OF THIS SOFTWARE.
 
-; $Id: test5,v 1.4 2011/01/13 19:30:41 each Exp $
+; $Id: test5,v 1.5 2011/10/13 01:32:33 vjs Exp $
 
 
-server 10.53.0.3 5300
-update add  a3-1.tld2.bl-given.            300 CNAME .
-send
+; Use comment lines instead of blank lines to combine update requests into
+;      single requests
+; Separate update requests for distinct TLDs with blank lines or 'send'
+; End the file with a blank line or 'send'
 
-server 10.53.0.3 5300
-update add  a3-2.tld2.bl-no-op.            300 CNAME .
-send
+; the policies or replacements specified in ns3/named.conf override these
 
 server 10.53.0.3 5300
-update add  a3-3.tld2.bl-nodata.    300 CNAME .
-send
 
-server 10.53.0.3 5300
-update add  a3-4.tld2.bl-nxdomain.  300 CNAME *.
+update add  a3-1.tld2.bl-given.            300 A 127.0.0.1
 send
-
-server 10.53.0.3 5300
-update add  a3-5.tld2.bl-cname.            300 CNAME .
+update add  a3-2.tld2.bl-passthru.  300 A 127.0.0.2
+send
+update add  a3-3.tld2.bl-no-op.            300 A 127.0.0.3
+send
+update add  a3-4.tld2.bl-disabled.  300 A 127.0.0.4
+send
+update add  a3-5.tld2.bl-nodata.    300 A 127.0.0.5
+send
+update add  a3-6.tld2.bl-nxdomain.  300 A 127.0.0.6
+send
+update add  a3-7.tld2.bl-cname.            300 A 127.0.0.7
+send
+update add  a3-8.tld2.bl-wildcname. 300 A 127.0.0.8
+update add  *.sub9.tld2.bl-wildcname. 300 A 127.0.1.9
+send
+update add  a3-10.tld2.bl-garden.    300 A 127.0.0.10
 send
index 4c3e52c4c11c25184fdf6ea687a13234666887ab..32dc2b715d46c28c9598d54f339851b2f3aa0f2e 100644 (file)
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: tests.sh,v 1.6 2011/06/09 03:10:17 marka Exp $
+# $Id: tests.sh,v 1.7 2011/10/13 01:32:33 vjs Exp $
 
 # test response policy zones (RPZ)
 
 SYSTEMTESTTOP=..
 . $SYSTEMTESTTOP/conf.sh
 
-root=10.53.0.1
-s2=10.53.0.2
-s3=10.53.0.3
+ns1=10.53.0.1                      # root, defining the other two
+ns2=10.53.0.2                      # server whose answers are rewritten
+ns3=10.53.0.3                      # resolve that does the rewriting
+ns4=10.53.0.4                      # another server that is rewritten
 
-DIGCMD="$DIG +noadd +nosea +nocmd -p 5300"
+RNDCCMD="$RNDC -c ../common/rndc.conf -s $ns3 -p 9953"
 
+HAVE_CORE=
 
 USAGE="$0: [-x]"
 while getopts "x" c; do
@@ -42,16 +44,21 @@ fi
 trap 'exit 1' 1 2 15
 
 
+digcmd () {
+    #echo I:dig +noadd +noauth +nosearch +time=1 +tries=1 -p 5300 $* 1>&2
+    $DIG +noadd +noauth +nosearch +time=1 +tries=1 -p 5300 $*
+}
+
 # set DIGNM=file name for dig output
-# $1=target domain  $2=optional query type  $3=optional string
-dignm () {
-    DIGNM=dig.out-$DIGNM_SUB-$1
-    if test -n "$3"; then
-       DIGNM=$DIGNM-$3
-    fi
-    if test -n "$2"; then
-       DIGNM=$DIGNM-`expr "x$2" : 'x-t *\(.*\)'`
-    fi
+GROUP_NM=
+TEST_NUM=0
+make_dignm () {
+    TEST_NUM=`expr $TEST_NUM + 1`
+    DIGNM=dig.out$GROUP_NM-$TEST_NUM
+    while test -e $DIGNM; do
+       TEST_NUM="$TEST_NUM+"
+       DIGNM=dig.out$GROUP_NM-$TEST_NUM
+    done
 }
 
 setret () {
@@ -59,109 +66,159 @@ setret () {
     echo "$*"
 }
 
+# (re)load the reponse policy zones with the rules in the file $TEST_FILE
+load_db () {
+    if test -n "$TEST_FILE"; then
+       if $NSUPDATE -v $TEST_FILE; then : ; else
+           echo "I:failed to update policy zone with $TEST_FILE"
+           exit 1
+       fi
+    fi
+}
+
+restart () {
+    $RNDCCMD stop >/dev/null 2>&1
+    rm -f ns3/*.jnl
+    for NM in ns3/bl*.db; do
+       cp -f ns3/base.db $NM
+    done
+    (cd ..; $PERL start.pl --noclean --restart rpz ns3)
+    load_db
+}
+
+ckalive () {
+    $RNDCCMD status >/dev/null 2>&1 && return 0
+    HAVE_CORE=yes
+    setret "$1"
+    restart
+    return 1
+}
+
+# $1=message  $2=optional test file name
+start_group () {
+    ret=0
+    test -n "$1" && echo "I:checking $1"
+    TEST_FILE=$2
+    if test -n "$TEST_FILE"; then
+       GROUP_NM="-$TEST_FILE"
+       load_db
+    else
+       GROUP_NM=
+    fi
+    TEST_NUM=0
+}
+
+end_group () {
+    if test -n "$TEST_FILE"; then
+       sed -e 's/[      ]add[   ]/ delete /' $TEST_FILE | $NSUPDATE
+       TEST_FILE=
+    fi
+    status=`expr $status + $ret`
+    ckalive "I:failed; server crashed"
+    GROUP_NM=
+}
+
+# $1=dig args $2=other dig output file
+ckresult () {
+    #ckalive "I:server crashed by 'dig $1'" || return 1
+    if $PERL ../digcomp.pl $DIGNM $2 >/dev/null; then
+       rm -f ${DIGNM}*
+       return 0
+    fi
+    setret "I:'dig $1' wrong; diff $DIGNM $2"
+    return 1
+}
+
+# check only that the server does not crash
+# $1=target domain  $2=optional query type
+nocrash () {
+    digcmd $* @$ns3 >/dev/null
+    ckalive "I:server crashed by 'dig $*'"
+}
+
+
 # check rewrite to NXDOMAIN
 # $1=target domain  $2=optional query type
 nxdomain () {
-    dignm $1 "$2"
-    $DIGCMD +noauth $1 $2 @$s3 >$DIGNM
-    $PERL ../digcomp.pl dig.out-nxdomain $DIGNM || setret "   in $DIGNM"
+    make_dignm
+    digcmd +noauth $* @$ns3                                            \
+       | sed -e 's/^[a-z].*    IN      CNAME   /;xxx &/' >$DIGNM
+    ckresult "$*" proto.nxdomain
 }
 
 # check rewrite to NODATA
 # $1=target domain  $2=optional query type
 nodata () {
-    dignm $1 "$2"
-    $DIGCMD +noauth $1 $2 @$s3 >$DIGNM
-    $PERL ../digcomp.pl dig.out-nodata $DIGNM ||  setret "   in $DIGNM"
+    make_dignm
+    digcmd +noauth $* @$ns3                                            \
+       | sed -e 's/^[a-z].*    IN      CNAME   /;xxx &/' >$DIGNM
+    ckresult "$*" proto.nodata
 }
 
-# check rewrite to "A 12.12.12.12"
-#   modify the output so that it is easily matched, but save the original line
-# $1=target domain  $2=optional query type
-a12 () {
-    dignm $1 "$2"
-    $DIGCMD +noauth $1 $2 @$s3                                         \
-       | sed -e "/^$1\.        /{"                                     \
-           -e "s/.*/;xxx &/p" -e "s/^;xxx $1/a12.tld2/" -e '}'         \
-       >$DIGNM
-    $PERL ../digcomp.pl dig.out-a12 $DIGNM || ret=1
+# check rewrite to an address
+#   modify the output so that it is easily compared, but save the original line
+# $1=IPv4 address, $2=target domain  $3=optional query type
+addr () {
+    ADDR=$1
+    shift
+    ADDR_ESC=`echo "$ADDR" | sed -e 's/\./\\\\./g'`
+    make_dignm
+    digcmd +noauth $* @$ns3 >$DIGNM
+    #ckalive "I:server crashed by 'dig $*'" || return
+    if grep -i '^[a-z].*       A       '"$ADDR_ESC"'$' $DIGNM >/dev/null; then
+       rm -f ${DIGNM}*
+       return 0
+    fi
+    setret "I:'dig $*' wrong; no A $ADDR record in $DIGNM $2"
 }
 
 # check that a response is not rewritten
 # $1=target domain  $2=optional query type
 nochange () {
-    dignm $1 "$2" ok
-    DIGNM_OK=$DIGNM
-    dignm $1 "$2"
-    $DIGCMD $1 $2 @$s3 >$DIGNM
-    $DIGCMD $1 $2 @$s2 >$DIGNM_OK
-    $PERL ../digcomp.pl $DIGNM_OK $DIGNM || ret=1
+    make_dignm
+    digcmd $* @$ns3 >$DIGNM
+    digcmd $* @$ns2 >${DIGNM}_OK
+    ckresult "$*" ${DIGNM}_OK && rm -f ${DIGNM}_OK
 }
 
-flush_db () {
-    if $RNDC -c ../common/rndc.conf -s $s3 -p 9953 freeze; then : ; else
-       echo "I:failed to freeze policy zone $1"
-       exit 1
-    fi
-    if $RNDC -c ../common/rndc.conf -s $s3 -p 9953 thaw; then : ; else
-       echo "I:failed to thaw policy zone $1"
-       exit 1
-    fi
+# check against a 'here document'
+here () {
+    make_dignm
+    sed -e 's/^[        ]*//' >${DIGNM}_OK
+    digcmd $* @$ns3 >$DIGNM
+    ckresult "$*" ${DIGNM}_OK
 }
 
-# $1=message  $2=test file
-start_test () {
-    ret=0
-    if test -n "$1"; then
-       echo "I:checking $1"
-    fi
-    PREV_FILE=$2
-    if test -n "$2"; then
-       DIGNM_SUB=`expr "$2" : 'test\(.\)'`
-       if $NSUPDATE -v $PREV_FILE; then : ; else
-           echo "I:failed to update policy zone $1 with $2"
-           exit 1
-       fi
-       #flush_db
-    else
-       DIGNM_SUB="${DIGNM_SUB}x"
-    fi
-}
-
-end_test () {
-    if test $ret != 0; then
-       echo "I:failed"
-    else
-       rm -f dig.out-${DIGNM_SUB}*
-    fi
-    if test -n "$PREV_FILE"; then
-       sed -e 's/ add / delete /' $PREV_FILE | $NSUPDATE
-       status=`expr $status + $ret`
-       #flush_db
-    fi
-}
+# make prototype files to check against rewritten results
+digcmd +noauth nonexistent @$ns2 >proto.nxdomain
+digcmd +noauth txt-only.tld2 @$ns2 >proto.nodata
 
 
-# make NXDOMAIN and NODATA prototypes
-echo "I:making prototype RPZ NXDOMAIN, NODATA, and CNAME results"
-$DIGCMD +noauth nonexistent @$s2 >dig.out-nxdomain
-$DIGCMD +noauth nodata.tld2 @$s2 >dig.out-nodata
-$DIGCMD +noauth a12.tld2    @$s2 >dig.out-a12
-
 status=0
 
-start_test "RPZ QNAME rewrites" test1
+start_group "QNAME rewrites" test1
+nochange .
 nxdomain a0-1.tld2
-nodata a1-1.tld2
-nodata a1-2.tld2
-nodata sub.a1-2.tld2
-a12 a4-1.sub1.tld2
-end_test
-
-start_test "RPZ IP rewrites" test2
+nodata a3-1.tld2
+nodata a3-2.tld2
+nodata sub.a3-2.tld2                   # 5 no crash on DNAME
+nxdomain a4-2.tld2                     # 6 rewrite based on CNAME target
+nxdomain a4-2-cname.tld2               # 7
+nodata a4-3-cname.tld2                 # 8
+addr 12.12.12.12  a4-1.sub1.tld2       # 9 A replacement
+addr 12.12.12.12  a4-1.sub2.tld2       # 10 A replacement with wildcard
+addr 12.12.12.12  nxc1.sub1.tld2       # 11 replace NXDOMAIN with CNAME
+addr 12.12.12.12  nxc2.sub1.tld2       # 12 replace NXDOMAIN with CNAME chain
+addr 127.0.0.1   a4-4.tld2             # 13 prefer 1st conflicting QNAME zone
+addr 56.56.56.56  a3-6.tld2            # 14 wildcard CNAME
+addr 57.57.57.57  a3-7.sub1.tld2       # 15 wildcard CNAME
+addr 127.0.0.16          a4-5-cname3.tld2      # 16 CNAME chain
+addr 127.0.0.17          a4-6-cname3.tld2      # 17 stop short in CNAME chain
+end_group
+
+start_group "IP rewrites" test2
 nodata a3-1.tld2
 nochange a3-2.tld2
-nxdomain a3-99.tld2
 nochange a4-1.tld2
 nxdomain a4-2.tld2
 nochange a4-2.tld2 -taaaa
@@ -170,9 +227,13 @@ nxdomain a4-2.tld2 -tany
 nodata a4-3.tld2
 nxdomain a3-1.tld2 -tAAAA
 nochange a4-1-aaaa.tld2 -tAAAA
-end_test
+addr 127.0.0.1  a5-1-2.tld2            # 11 prefer smallest policy address
+addr 127.0.0.1  a5-3.tld2              # 12 prefer first conflicting IP zone
+addr 14.14.14.14 a5-4.tld2             # 13 prefer QNAME to IP
+end_group
 
-start_test "RPZ radix tree deletions"
+# check that IP addresses for previous group were deleted from the radix tree
+start_group "radix tree deletions"
 nochange a3-1.tld2
 nochange a3-2.tld2
 nochange a4-1.tld2
@@ -183,94 +244,73 @@ nochange a4-2.tld2 -tany
 nochange a4-3.tld2
 nochange a3-1.tld2 -tAAAA
 nochange a4-1-aaaa.tld2 -tAAAA
-end_test
+nochange a5-1-2.tld2
+end_group
 
 if ./rpz nsdname; then
-    start_test "RPZ NSDNAME rewrites" test3
+    start_group "NSDNAME rewrites" test3
     nochange a3-1.tld2
-    nxdomain a3-1.sub1.tld2
-    nxdomain a3-1.sub2.sub1.tld2
-    end_test
+    nochange a3-1.tld2 +dnssec         # 2 this once caused problems
+    nxdomain a3-1.sub1.tld2            # 3 NXDOMAIN *.sub1.tld2 by NSDNAME
+    nxdomain a3-1.subsub.sub1.tld2
+    nxdomain a3-1.subsub.sub1.tld2 -tany
+    addr 12.12.12.12 a4-2.subsub.sub2.tld2 # 6 walled garden for *.sub2.tld2
+    nochange a3-2.tld2.                        # 7 exempt rewrite by name
+    nochange a0-1.tld2.                        # 8 exempt rewrite by address block
+    addr 12.12.12.12 a4-1.tld2         # 9 prefer QNAME policy to NSDNAME
+    addr 127.0.0.1 a3-1.sub3.tld2      # 10 prefer policy for largest NSDNAME
+    addr 127.0.0.2 a3-1.subsub.sub3.tld2
+    nxdomain xxx.crash1.tld2           # 12 dns_db_detachnode() crash
+    end_group
 else
-    echo "I:RPZ NSDNAME not checked; named was not built with --enable-rpz-nsdname"
+    echo "I:NSDNAME not checked; named not configured with --enable-rpz-nsdname"
 fi
 
 if ./rpz nsip; then
-    start_test "RPZ NSIP rewrites" test4
-    nxdomain a3-1.tld2
-    nochange .
-    end_test
+    start_group "NSIP rewrites" test4
+    nxdomain a3-1.tld2                 # 1 NXDOMAIN for all of tld2 by NSIP
+    nochange a3-2.tld2.                        # 2 exempt rewrite by name
+    nochange a0-1.tld2.                        # 3 exempt rewrite by address block
+    nochange a3-1.tld4                 # 4 different NS IP address
+    end_group
 else
-    echo "I:RPZ NSIP not checked; named was not built with --enable-rpz-nsip"
-fi
-
-start_test "RPZ policy overrides" test5
-nxdomain a3-1.tld2
-nochange a3-2.tld2
-nodata a3-3.tld2
-nxdomain a3-4.tld2
-dignm a3-5.tld2 -tany
-$DIGCMD +noauth a3-5.tld2 -tany @$s3 >$DIGNM
-if grep CNAME $DIGNM >/dev/null; then : ; else
-    echo "'policy cname' failed"
-    ret=1
+    echo "I:NSIP not checked; named not configured with --enable-rpz-nsip"
 fi
-end_test
-
-ret=0
-echo "I:checking RRSIG queries"
-# We don't actually care about the query results; the important
-# thing is the server handles RRSIG queries okay
-$DIGCMD a3-1.tld2 -trrsig @$s3 > /dev/null 2>&1
-$DIGCMD a3-2.tld2 -trrsig @$s3 > /dev/null 2>&1
-$DIGCMD a3-5.tld2 -trrsig @$s3 > /dev/null 2>&1
-$DIGCMD www.redirect -trrsig @$s3 > /dev/null 2>&1
-$DIGCMD www.cname-redirect -trrsig @$s3 > /dev/null 2>&1
-
-$RNDC -c ../common/rndc.conf -s $s3 -p 9953 status > /dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then
-    echo "I:failed";
-    (cd ..; $PERL start.pl --noclean --restart rpz ns3)
-fi
-status=`expr $status + $ret`
-
-ret=0
-echo "I:checking SIG queries"
-# We don't actually care about the query results; the important
-# thing is the server handles SIG queries okay
-$DIGCMD a3-1.tld2 -tsig @$s3 > /dev/null 2>&1
-$DIGCMD a3-2.tld2 -tsig @$s3 > /dev/null 2>&1
-$DIGCMD a3-5.tld2 -tsig @$s3 > /dev/null 2>&1
-$DIGCMD www.redirect -tsig @$s3 > /dev/null 2>&1
-$DIGCMD www.cname-redirect -tsig @$s3 > /dev/null 2>&1
-
-$RNDC -c ../common/rndc.conf -s $s3 -p 9953 status > /dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then
-    echo "I:failed";
-    (cd ..; $PERL start.pl --noclean --restart rpz ns3)
-fi
-status=`expr $status + $ret`
-
-ret=0
-echo "I:checking ANY queries"
-# We don't actually care about the query results; the important
-# thing is the server handles SIG queries okay
-$DIGCMD a3-1.tld2 -tany @$s3 > /dev/null 2>&1
-$DIGCMD a3-2.tld2 -tany @$s3 > /dev/null 2>&1
-$DIGCMD a3-5.tld2 -tany @$s3 > /dev/null 2>&1
-$DIGCMD www.redirect -tany @$s3 > /dev/null 2>&1
-$DIGCMD www.cname-redirect -tany @$s3 > /dev/null 2>&1
-
-$RNDC -c ../common/rndc.conf -s $s3 -p 9953 status > /dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then
-    echo "I:failed";
-    (cd ..; $PERL start.pl --noclean --restart rpz ns3)
-fi
-status=`expr $status + $ret`
 
+# policies in ./test5 overridden by response-policy{} in ns3/named.conf
+start_group "policy overrides" test5
+addr 127.0.0.1 a3-1.tld2               # 1 bl-given
+nochange a3-2.tld2                     # 2 bl-passthru
+nochange a3-3.tld2                     # 3 bl-no-op    obsolete for passthru
+nochange a3-4.tld2                     # 4 bl-disabled
+nodata a3-5.tld2                       # 5 bl-nodata
+nxdomain a3-6.tld2                     # 6 bl-nxdomain
+here +noauth a3-7.tld2 -tany <<'EOF'   # 7 bl_cname
+    ;; status: NOERROR, x
+    a3-7.tld2.     300 IN      CNAME   txt-only.tld2.
+    txt-only.tld2.  120 IN     TXT     "txt-only-tld2"
+EOF
+addr 58.58.58.58 a3-8.tld2             # 8 bl_wildcname
+addr 59.59.59.59 a3-9.sub9.tld2                # 9 bl_wildcname
+addr 12.12.12.12 a3-10.tld2            # 10 bl-garden
+end_group
+
+# check that miscellaneous bugs are still absent
+start_group "crashes"
+for Q in RRSIG SIG ANY 'ANY +dnssec'; do
+    nocrash a3-1.tld2 -t$Q
+    nocrash a3-2.tld2 -t$Q
+    nocrash a3-5.tld2 -t$Q
+    nocrash www.redirect -t$Q
+    nocrash www.credirect -t$Q
+done
+end_group
 
-if test "$status" -eq 0; then
-    rm -f dig.out*
+# restart the server to see if that creates a core file
+if test -z "$HAVE_CORE"; then
+    $RNDCCMD halt
+    restart
+    test -s ns3/named.core && setret "I:found stray core file; memory leak?"
 fi
 
 echo "I:exit status: $status"
index 1fa4c96de2811290ceecbede46d193aed13826cf..5b683f0bc3f7635779e170a8ddfe7841118f4c6a 100644 (file)
@@ -15,7 +15,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: start.pl,v 1.27 2011/10/10 23:18:17 smann Exp $
+# $Id: start.pl,v 1.28 2011/10/13 01:32:32 vjs Exp $
 
 # Framework for starting test servers.
 # Based on the type of server specified, check for port availability, remove
@@ -232,14 +232,15 @@ sub start_server {
        # already been started
        my $tries = 0;
        while (!-s $pid_file) {
-               if (++$tries > 14) {
+               if (++$tries > 140) {
                        print "I:Couldn't start server $server (pid=$child)\n";
                        print "R:FAIL\n";
                        system "kill -9 $child" if ("$child" ne "");
                        system "$PERL $topdir/stop.pl $testdir";
                        exit 1;
                }
-               sleep 1;
+               # sleep for 0.1 seconds
+               select undef,undef,undef,0.1;
        }
 
         # go back to the top level directory
index 2012d1c91aca03147d0b3a677d7b378409a33fa8..d3099eb4ec603372cb179e75080c859f12a6df17 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- File: $Id: Bv9ARM-book.xml,v 1.504 2011/10/06 11:50:20 marka Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.505 2011/10/13 01:32:33 vjs Exp $ -->
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
   <title>BIND 9 Administrator Reference Manual</title>
 
@@ -4682,6 +4682,19 @@ category notify { null; };
                    </para>
                  </entry>
                </row>
+                <row rowsep="0">
+                  <entry colname="1">
+                    <para><command>RPZ</command></para>
+                  </entry>
+                 <entry colname="2">
+                   <para>
+                     Information about errors in response policy zone files,
+                     rewritten responses, and at the highest
+                     <command>debug</command> levels, mere rewriting
+                     attempts.
+                   </para>
+                 </entry>
+               </row>
              </tbody>
            </tgroup>
          </informaltable>
@@ -5211,7 +5224,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
     <optional> resolver-query-timeout <replaceable>number</replaceable> ; </optional>
     <optional> deny-answer-addresses { <replaceable>address_match_list</replaceable> } <optional> except-from { <replaceable>namelist</replaceable> } </optional>;</optional>
     <optional> deny-answer-aliases { <replaceable>namelist</replaceable> } <optional> except-from { <replaceable>namelist</replaceable> } </optional>;</optional>
-    <optional> response-policy { <replaceable>zone_name</replaceable> <optional> policy <replaceable>given</replaceable> | <replaceable>no-op</replaceable> | <replaceable>nxdomain</replaceable> | <replaceable>nodata</replaceable> | <replaceable>cname domain</replaceable> </optional> ; } ; </optional>
+    <optional> response-policy { <replaceable>zone_name</replaceable> <optional> policy given | disabled | passthru | nxdomain | nodata | cname <replaceable>domain</replaceable> </optional> ; } ; </optional>
 };
 </programlisting>
 
@@ -9322,141 +9335,213 @@ deny-answer-aliases { "example.net"; };
          <title>Response Policy Zone (RPZ) Rewriting</title>
          <para>
            <acronym>BIND</acronym> 9 includes an intentionally limited
-            mechanism to modify DNS responses for recursive requests
-            similar to email anti-spam DNS blacklists.
-            All response policy zones are named in the
-            <command>response-policy</command> option for the view or among the
-            global options if there is no response-policy option for the view.
-          </para>
+           mechanism to modify DNS responses for recursive requests
+           somewhat similar to email anti-spam DNS blacklists.
+           Responses can be changed to deny the existence of domains(NXDOMAIN),
+           deny the existence of IP addresses for domains (NODATA),
+           or contain other IP addresses or data.
+         </para>
 
-          <para>
-            The rules encoded in a response policy zone (RPZ) are applied
-            only to responses to queries that ask for recursion (RD=1).
-            RPZs are normal DNS zones containing RRsets
-            that can be queried normally if allowed.
-            It is usually best to restrict those queries with something like
-            <command>allow-query {none; };</command> or
-            <command>allow-query { 127.0.0.1; };</command>.
-          </para>
+         <para>
+           The actions encoded in a response policy zone (RPZ) are applied
+           only to queries that ask for recursion (RD=1).
+           Response policy zones are named in the
+           <command>response-policy</command> option for the view or among the
+           global options if there is no response-policy option for the view.
+           RPZs are ordinary DNS zones containing RRsets
+           that can be queried normally if allowed.
+           It is usually best to restrict those queries with something like
+           <command>allow-query { localhost; };</command>.
+         </para>
 
-          <para>
-            There are four kinds of RPZ rewrite rules.  QNAME rules are
-            applied to query names in requests and to targets of CNAME
-            records resolved in the process of generating the response.
-            The owner name of a QNAME rule is the query name relativized
-            to the RPZ.
-           The records in a rewrite rule are usually A, AAAA, or special
-           CNAMEs, but can be any type except DNAME.
-          </para>
+         <para>
+           There are four kinds of RPZ records, QNAME, IP, NSIP,
+           and NSDNAME.
+           QNAME records are applied to query names of requests and targets
+           of CNAME records resolved to generate the response.
+           The owner name of a QNAME RPZ record is the query name relativized
+           to the RPZ.
+         </para>
 
-          <para>
-            IP rules are triggered by addresses in A and AAAA records.
-            All IP addresses in A or AAAA RRsets are tested and the rule
-            longest prefix is applied.  Ties between rules with equal prefixes
-            are broken in favor of the first RPZ mentioned in the
-            response-policy option.
-            The rule matching the smallest IP address is chosen among equal
-            prefix rules from a single RPZ.
-            IP rules are expressed in RRsets with owner names that are
-            subdomains of rpz-ip and encoding an IP address block, reversed
-            as in IN-ARPA.
-            prefix.B.B.B.B with prefix between 1 and 32 and B between 1 and 255
-            encodes an IPv4 address.
-            IPv6 addresses are encoded by with prefix.W.W.W.W.W.W.W.W or
-            prefix.WORDS.zz.WORDS.  The words in the standard IPv6 text
-            representation are reversed, "::" is replaced with ".zz.",
-            and ":" becomes ".".
-          </para>
+         <para>
+           The second kind of RPZ record, an IP policy record,
+           is triggered by addresses in A and AAAA records
+           for the ANSWER sections of responses.
+           IP policy records have owner names that are
+           subdomains of <userinput>rpz-ip</userinput> relativized to the
+           RPZ origin name and encode an IP address or address block.
+           IPv4 addresses are encoded as
+           <userinput>prefixlength.B4.B3.B2.B1.rpz-ip</userinput>.
+           The prefix length must be between 1 and 32.
+           All four bytes, B4, B3, B2, and B1, must be present.
+           B4 is the decimal value of the least significant byte of the
+           IPv4 address as in IN-ADDR.ARPA.
+           IPv6 addresses are encoded in a format similar to the standard
+           IPv6 text representation,
+           <userinput>prefixlength.W8.W7.W6.W5.W4.W3.W2.W1.rpz-ip</userinput>.
+           Each of W8,...,W1 is a one to four digit hexadecimal number
+           representing 16 bits of the IPv6 address as in the standard text
+           representation of IPv6 addresses, but reversed as in IN-ADDR.ARPA.
+           All 8 words must be present except when consecutive
+           zero words are replaced with <userinput>.zz.</userinput>
+           analogous to double colons (::) in standard IPv6 text encodings.
+           The prefix length must be between 1 and 128.
+         </para>
 
-          <para>
-            NSDNAME rules match names in NS RRsets for the response or a
-            parent.  They are encoded as subdomains of rpz-nsdomain relativized
-            to the RPZ origin name.
-          </para>
+         <para>
+           NSDNAME policy records match names of authoritative servers
+           for the query name, a parent of the query name, a CNAME,
+           or a parent of a CNAME.
+           They are encoded as subdomains of
+           <userinput>rpz-nsdomain</userinput> relativized
+           to the RPZ origin name.
+         </para>
 
-          <para>
-            NSIP rules match IP addresses in A and AAAA RRsets for names of
-            responsible servers or the names that can be matched by NSDNAME
-            rules.  The are encoded like IP rules except as subdomains of
-            rpz-nsip.
+         <para>
+           NSIP policy records match IP addresses in A and AAAA RRsets
+           for domains that can be checked against NSDNAME policy records.
+           The are encoded like IP policies except as subdomains of
+           <userinput>rpz-nsip</userinput>.
+         </para>
+
+         <para>
+           The query response is checked against all RPZs, so
+           two or more policy records can apply to a single response.
+           Because DNS responses can be rewritten according by at most a
+           single policy record, a single policy (other than
+           <command>DISABLED</command> policies) must be chosen.
+           Policies are chosen in the following order:
+           <itemizedlist>
+             <listitem>Among applicable zones, use the RPZ that appears first
+               in the response-policy option.
+             <listitem>Prefer QNAME to IP to NSDNAME to NSIP policy records
+               in a single RPZ
+             <listitem>Among applicable NSDNAME policy records, prefer the
+               policy record that matches the lexically smallest name
+             <listitem>Among IP or NSIP policy records, prefer the record
+               with the longest prefix.
+             <listitem>Among records with the same prefex length,
+               prefer the IP or NSIP policy record that matches
+               the smallest IP address.
+           </itemizedlist>
          </para>
 
          <para>
-            Authority verification issues and variations in authority data in
-           the current version of <acronym>BIND</acronym> 9 can cause
-           inconsistent results from NSIP and NSDNAME.  So they are available
+           When the processing of a response is restarted to resolve
+           DNAME or CNAME records and an applicable policy record set has
+           not been found,
+           all RPZs are again consulted for the DNAME or CNAME names
+           and addresses.
+         </para>
+
+         <para>
+           Authority verification issues and variations in authority data
+           can cause inconsistent results for NSIP and NSDNAME policy records.
+           Glue NS records often differ from authoritative NS records.
+           So they are available
            only when <acronym>BIND</acronym> is built with the
            <userinput>--enable-rpz-nsip</userinput> or
            <userinput>--enable-rpz-nsdname</userinput> options
-            on the "configure" command line.
-          </para>
+           on the "configure" command line.
+         </para>
 
-          <para>
-            Four policies can be expressed.
-            The <command>NXDOMAIN</command> policy causes a NXDOMAIN response
-            and is expressed with an RRset consisting of a single CNAME
-            whose target is the root domain (.).
-            <command>NODATA</command> generates NODATA or ANCOUNT=1 regardless
-            of query type.
-            It is expressed with a CNAME whose target is the wildcard
-            top-level domain (*.).
-            The <command>NO-OP</command> policy does not change the response
-            and is used to "poke holes" in policies for larger CIDR blocks or in
-            zones named later in the <command>response-policy</command> option.
-            The NO-OP policy is expressed by a CNAME with a target consisting
-            of the variable part of the owner name, such as "example.com." for
-            a QNAME rule or "128.1.0.0.127." for an IP rule.
-            The <command>CNAME</command> policy is used to replace the RRsets
-            of response.
-            A and AAAA RRsets are most common and useful to capture
-            an evil domain in a walled garden, but any valid set of RRsets
-            is possible.
-          </para>
+         <para>
+           RPZ record sets are special CNAME records or one or more
+           of any types of DNS record except DNAME or DNSSEC.
+           Except when a policy record is a CNAME, there can be more
+           more than one record and more than one type
+           in a set of policy records.
+           Except for three kinds of CNAME records that are illegal except
+           in policy zones, the records in a set are used in the response as if
+           their owner name were the query name.  They are copied to the
+           response as dictated by their types.
+           <itemizedlist>
+             <listitem>A CNAME whose target is the root domain (.)
+               specifies the <command>NXDOMAIN</command> policy,
+               which generates an NXDOMAIN response.
+             <listitem>A CNAME whose target is the wildcard top-level
+               domain (*.) specifies the <command>NODATA</command> policy,
+               which rewrites the response to NODATA or ANCOUNT=1.
+             <listitem>A CNAME whose target is a wildcard hostname such
+               as *.example.com is used normally after the astrisk (*)
+               has been replaced with the query name.
+               These records are usually resolved with ordinary CNAMEs
+               outside the policy zones.  They can be useful for logging.
+             <listitem>The <command>PASSTHRU</command> policy is specified
+               by a CNAME whose target is the variable part of its own
+               owner name.  It causes the response to not be rewritten
+               and is most often used to "poke holes" in policies for
+               CIDR blocks.
+           </itemizedlist>
+         </para>
 
-          <para>
-            All of the policies in an RPZ can be overridden with a
-            <command>policy</command> clause.
-            <command>given</command> says "do not override."
-            <command>no-op</command> says "do nothing" regardless of the policy
-            in RPZ records.
-            <command>nxdomain</command> causes all RPZ rules to generate
-            NXDOMAIN results.
-            <command>nodata</command> gives nodata.
-            <command>cname domain</command> causes all RPZ rules to act as if
-            the consisted of a "cname domain" record.
-          </para>
+         <para>
+           The policies specified in individual records
+           in an RPZ can be overridden with a <command>policy</command> clause
+           in the <command>response-policy</command> option.
+           An organization using an RPZ provided by another organization might
+           use this mechanism to redirect domains to its own walled garden.
+           <itemizedlist>
+             <listitem><command>GIVEN</command> says "do not override."
+             <listitem><command>DISABLED</command> causes policy records to do
+               nothing but log what they might have done.
+               The response to the DNS query will be written according to
+               any matching policy records that are not disabled.
+               Policy zones overridden with <command>DISABLED</command> should
+               appear first, because they will often not be logged
+               if a higher precedence policy is found first.
+             <listitem><command>PASSTHRU</command> causes all policy records
+               to act as if they were CNAME records with targets the variable
+               part of their owner name.  They protect the response from
+               being changed.
+             <listitem><command>NXDOMAIN</command> causes all RPZ records
+               to specify NXDOMAIN policies.
+             <listitem><command>NODATA</command> overrides with the
+               NODATA policy
+             <listitem><command>CNAME domain</command> causes all RPZ
+               policy records to act as if they were "cname domain" records.
+           </itemizedlist>
+         </para>
 
-          <para>
-            For example, you might use this option statement
+         <para>
+           For example, you might use this option statement
           </para>
-<programlisting>response-policy { zone "bl"; };</programlisting>
+<programlisting>    response-policy { zone "badlist"; };</programlisting>
           <para>
             and this zone statement
           </para>
-<programlisting>zone "bl" {type master; file "example/bl"; allow-query {none;}; };</programlisting>
+<programlisting>    zone "badlist" {type master; file "master/badlist"; allow-query {none;}; };</programlisting>
           <para>
             with this zone file
           </para>
 <programlisting>$TTL 1H
-@                   SOA LOCALHOST. named-mgr.example.com (1 1h 15m 30d 2h)
+@                       SOA LOCALHOST. named-mgr.example.com (1 1h 15m 30d 2h)
+                        NS  LOCALHOST.
+
+; QNAME policy records.  There are no periods (.) after the owner names.
+nxdomain.domain.com     CNAME   .               ; NXDOMAIN policy
+nodata.domain.com       CNAME   *.              ; NODATA policy
+bad.domain.com          A       10.0.0.1        ; redirect to a walled garden
+                        AAAA    2001:2::1
+
+; do not rewrite (PASSTHRU) OK.DOMAIN.COM
+ok.domain.com           CNAME   ok.domain.com.
+
+bzone.domain.com        CNAME   garden.example.com.
 
-; QNAME rules
-nxdomain.domain.com         CNAME   .
-nodata.domain.com           CNAME   *.
-bad.domain.com              A       10.0.0.1
-                            AAAA    2001:2::1
-ok.domain.com               CNAME   ok.domain.com.
-*.badzone.domain.com       CNAME   garden.example.com.
+; redirect x.bzone.domain.com to x.bzone.domain.com.garden.example.com
+*.bzone.domain.com      CNAME   *.garden.example.com.
 
-; IP rules rewriting all answers for 127/8 except 127.0.0.1
-8.0.0.0.127.ip              CNAME   .
-32.1.0.0.127.ip             CNAME   32.1.0.0.127.
 
-; NSDNAME and NSIP rules
+; IP policy records that rewrite all answers for 127/8 except 127.0.0.1
+8.0.0.0.127.rpz-ip      CNAME   .
+32.1.0.0.127.rpz-ip     CNAME   32.1.0.0.127.   ; PASSTHRU for 127.0.0.1
+
+; NSDNAME and NSIP policy records
 ns.domain.com.rpz-nsdname   CNAME   .
 48.zz.2.2001.rpz-nsip       CNAME   .
 </programlisting>
-       </sect3>
+        </sect3>
       </sect2>
 
       <sect2 id="server_statement_grammar">
index 13778873f3edf0839eff23dfe050fa3eb2557d77..e7e4bf154f917c84397a7d22ec1f8557560c5f51 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: db.c,v 1.98 2011/10/11 00:09:03 each Exp $ */
+/* $Id: db.c,v 1.99 2011/10/13 01:32:33 vjs Exp $ */
 
 /*! \file */
 
@@ -1017,10 +1017,11 @@ dns_db_rpz_enabled(dns_db_t *db, dns_rpz_st_t *st)
 isc_result_t
 dns_db_rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
                   dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
-                  dns_rdataset_t *ardataset, dns_rpz_st_t *st)
+                  dns_rdataset_t *ardataset, dns_rpz_st_t *st,
+                  dns_name_t *query_qname)
 {
        if (db->methods->rpz_findips == NULL)
                return (ISC_R_NOTIMPLEMENTED);
        return ((db->methods->rpz_findips)(rpz, rpz_type, zone, db, version,
-                                          ardataset, st));
+                                          ardataset, st, query_qname));
 }
index 0c3ebb799c126cf1b70a68ebb30477392b756860..48b5a26eab996fa2a8e371b052b2ea13e36115fc 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: db.h,v 1.106 2011/10/11 00:09:03 each Exp $ */
+/* $Id: db.h,v 1.107 2011/10/13 01:32:34 vjs Exp $ */
 
 #ifndef DNS_DB_H
 #define DNS_DB_H 1
@@ -178,7 +178,8 @@ typedef struct dns_dbmethods {
                                       dns_zone_t *zone, dns_db_t *db,
                                       dns_dbversion_t *version,
                                       dns_rdataset_t *ardataset,
-                                      dns_rpz_st_t *st);
+                                      dns_rpz_st_t *st,
+                                      dns_name_t *query_qname);
        isc_result_t    (*findnodeext)(dns_db_t *db, dns_name_t *name,
                                     isc_boolean_t create,
                                     dns_clientinfomethods_t *methods,
@@ -1547,7 +1548,8 @@ dns_db_rpz_enabled(dns_db_t *db, dns_rpz_st_t *st);
 isc_result_t
 dns_db_rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
                   dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
-                  dns_rdataset_t *ardataset, dns_rpz_st_t *st);
+                  dns_rdataset_t *ardataset, dns_rpz_st_t *st,
+                  dns_name_t *query_qname);
 /*%<
  * Search the CDIR block tree of a response policy tree of trees for the best
  * match to any of the IP addresses in an A or AAAA rdataset.
@@ -1560,6 +1562,10 @@ dns_db_rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
  * \li 'ardataset' is an A or AAAA rdataset of addresses to check
  * \li 'found' specifies the previous best match if any or
  *         or NULL, an empty name, 0, DNS_RPZ_POLICY_MISS, and 0
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_UNEXPECTED
  */
 
 ISC_LANG_ENDDECLS
index fef8bd32ed4da69947aac0d25113b5334d539108..e211a48808d9256740f22cd9d2b23237eea8e4e8 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: log.h,v 1.45 2009/12/18 22:16:49 each Exp $ */
+/* $Id: log.h,v 1.46 2011/10/13 01:32:34 vjs Exp $ */
 
 /*! \file dns/log.h
  * \author  Principal Authors: DCL */
@@ -42,6 +42,7 @@ LIBDNS_EXTERNAL_DATA extern isc_logmodule_t dns_modules[];
 #define DNS_LOGCATEGORY_LAME_SERVERS   (&dns_categories[9])
 #define DNS_LOGCATEGORY_DELEGATION_ONLY        (&dns_categories[10])
 #define DNS_LOGCATEGORY_EDNS_DISABLED  (&dns_categories[11])
+#define DNS_LOGCATEGORY_RPZ            (&dns_categories[12])
 
 /* Backwards compatibility. */
 #define DNS_LOGCATEGORY_GENERAL                ISC_LOGCATEGORY_GENERAL
index 7fa702b83980a5c2fe2417816594663bda769342..6b0d8077f1526835f86d46229a23b42b2c20487d 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rpz.h,v 1.3 2011/01/13 04:59:26 tbox Exp $ */
+/* $Id: rpz.h,v 1.4 2011/10/13 01:32:34 vjs Exp $ */
 
 #ifndef DNS_RPZ_H
 #define DNS_RPZ_H 1
@@ -37,21 +37,24 @@ typedef enum {
        DNS_RPZ_TYPE_BAD,
        DNS_RPZ_TYPE_QNAME,
        DNS_RPZ_TYPE_IP,
-       DNS_RPZ_TYPE_NSIP,
-       DNS_RPZ_TYPE_NSDNAME
+       DNS_RPZ_TYPE_NSDNAME,
+       DNS_RPZ_TYPE_NSIP
 } dns_rpz_type_t;
 
 /*
- * Require DNS_RPZ_POLICY_NO_OP < DNS_RPZ_POLICY_NXDOMAIN <
- *        DNS_RPZ_POLICY_NODATA < DNS_RPZ_POLICY_CNAME.
+ * Require DNS_RPZ_POLICY_PASSTHRU < DNS_RPZ_POLICY_NXDOMAIN <
+ * DNS_RPZ_POLICY_NODATA < DNS_RPZ_POLICY_CNAME to choose among competing
+ * policies.
  */
 typedef enum {
-       DNS_RPZ_POLICY_GIVEN = 0,       /* 'given': what something else says */
-       DNS_RPZ_POLICY_NO_OP = 1,       /* 'no-op': do not rewrite */
-       DNS_RPZ_POLICY_NXDOMAIN = 2,    /* 'nxdomain': answer with NXDOMAIN */
-       DNS_RPZ_POLICY_NODATA = 3,      /* 'nodata': answer with ANCOUNT=0 */
-       DNS_RPZ_POLICY_CNAME = 4,       /* 'cname x': answer with x's rrsets */
-       DNS_RPZ_POLICY_RECORD = 5,
+       DNS_RPZ_POLICY_GIVEN = 0,       /* 'given': what policy record says */
+       DNS_RPZ_POLICY_DISABLED = 1,    /* 'cname x': answer with x's rrsets */
+       DNS_RPZ_POLICY_PASSTHRU = 2,    /* 'passthru': do not rewrite */
+       DNS_RPZ_POLICY_NXDOMAIN = 3,    /* 'nxdomain': answer with NXDOMAIN */
+       DNS_RPZ_POLICY_NODATA = 4,      /* 'nodata': answer with ANCOUNT=0 */
+       DNS_RPZ_POLICY_CNAME = 5,       /* 'cname x': answer with x's rrsets */
+       DNS_RPZ_POLICY_RECORD,
+       DNS_RPZ_POLICY_WILDCNAME,
        DNS_RPZ_POLICY_MISS,
        DNS_RPZ_POLICY_ERROR
 } dns_rpz_policy_t;
@@ -65,10 +68,9 @@ struct dns_rpz_zone {
        ISC_LINK(dns_rpz_zone_t) link;
        int                      num;
        dns_name_t               origin;  /* Policy zone name */
-       dns_name_t               nsdname; /* RPZ_NSDNAME_ZONE.origin */
-       dns_rpz_policy_t         policy;  /* RPZ_POLICY_GIVEN or override */
-       dns_name_t               cname;   /* override name for
-                                            RPZ_POLICY_CNAME */
+       dns_name_t               nsdname; /* DNS_RPZ_NSDNAME_ZONE.origin */
+       dns_rpz_policy_t         policy;  /* DNS_RPZ_POLICY_GIVEN or override */
+       dns_name_t               cname;   /* override value for ..._CNAME */
 };
 
 /*
@@ -82,13 +84,15 @@ typedef struct dns_rpz_cidr dns_rpz_cidr_t;
 typedef struct {
        unsigned int            state;
 # define DNS_RPZ_REWRITTEN     0x0001
-# define DNS_RPZ_DONE_QNAME    0x0002
-# define DNS_RPZ_DONE_A                0x0004
-# define DNS_RPZ_RECURSING     0x0008
-# define DNS_RPZ_HAVE_IP       0x0010
-# define DNS_RPZ_HAVE_NSIPv4   0x0020
-# define DNS_RPZ_HAVE_NSIPv6   0x0040
-# define DNS_RPZ_HAD_NSDNAME   0x0080
+# define DNS_RPZ_DONE_QNAME    0x0002  /* qname checked */
+# define DNS_RPZ_DONE_QNAME_IP 0x0004  /* IP addresses of qname checked */
+# define DNS_RPZ_DONE_NSDNAME  0x0008  /* NS name missed; checking addresses */
+# define DNS_RPZ_DONE_IPv4     0x0010
+# define DNS_RPZ_RECURSING     0x0020
+# define DNS_RPZ_HAVE_IP       0x0040  /* a policy zone has IP addresses */
+# define DNS_RPZ_HAVE_NSIPv4   0x0080  /*                IPv4 NISP addresses */
+# define DNS_RPZ_HAVE_NSIPv6   0x0100  /*                IPv6 NISP addresses */
+# define DNS_RPZ_HAVE_NSDNAME  0x0200  /*                NS names */
        /*
         * Best match so far.
         */
@@ -105,7 +109,7 @@ typedef struct {
                dns_rdataset_t          *rdataset;
        } m;
        /*
-        * State for chasing NS names and addresses including recursion.
+        * State for chasing IP addresses and NS names including recursion.
         */
        struct {
                unsigned int            label;
@@ -114,7 +118,7 @@ typedef struct {
                dns_rdatatype_t         r_type;
                isc_result_t            r_result;
                dns_rdataset_t          *r_rdataset;
-       } ns;
+       } r;
        /*
         * State of real query while recursing for NSIP or NSDNAME.
         */
@@ -146,6 +150,7 @@ typedef struct {
 #define DNS_RPZ_INFO_LEVEL     ISC_LOG_INFO
 #define DNS_RPZ_DEBUG_LEVEL1   ISC_LOG_DEBUG(1)
 #define DNS_RPZ_DEBUG_LEVEL2   ISC_LOG_DEBUG(2)
+#define DNS_RPZ_DEBUG_LEVEL3   ISC_LOG_DEBUG(3)
 
 const char *
 dns_rpz_type2str(dns_rpz_type_t type);
@@ -153,6 +158,9 @@ dns_rpz_type2str(dns_rpz_type_t type);
 dns_rpz_policy_t
 dns_rpz_str2policy(const char *str);
 
+const char *
+dns_rpz_policy2str(dns_rpz_policy_t policy);
+
 void
 dns_rpz_set_need(isc_boolean_t need);
 
index 388dd8f79bbbc82ef1eeb06d99f86ab9593c3a54..001ca8c995d17940f020aded0d0be0b9096abee0 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: log.c,v 1.47 2009/12/18 23:49:03 tbox Exp $ */
+/* $Id: log.c,v 1.48 2011/10/13 01:32:33 vjs Exp $ */
 
 /*! \file */
 
@@ -44,6 +44,7 @@ LIBDNS_EXTERNAL_DATA isc_logcategory_t dns_categories[] = {
        { "lame-servers", 0 },
        { "delegation-only", 0 },
        { "edns-disabled", 0 },
+       { "rpz",        0 },
        { NULL,         0 }
 };
 
index d95c2b4c882acc0cc2e7e4a27f17066b5df90671..1571126c8e4c44f29b7690937c0c97c11f0fe6fe 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.318 2011/10/12 23:09:35 marka Exp $ */
+/* $Id: rbtdb.c,v 1.319 2011/10/13 01:32:33 vjs Exp $ */
 
 /*! \file */
 
@@ -4588,15 +4588,19 @@ get_rpz_enabled(dns_db_t *db, dns_rpz_st_t *st)
  * Search the CDIR block tree of a response policy tree of trees for all of
  * the IP addresses in an A or AAAA rdataset.
  * Among the policies for all IPv4 and IPv6 addresses for a name, choose
- * the longest prefix.  Among those with the longest prefix, the first
- * configured policy.  Among answers for with the longest prefixes for
- * two or more IP addresses in the A and AAAA rdatasets the lexically
- * smallest address.
+ *     the earliest configured policy,
+ *     QNAME over IP over NSDNAME over NSIP,
+ *     the longest prefix,
+ *     the lexically smallest address.
+ * The caller must have already checked that any existing policy was not
+ * configured earlier than this policy zone and does not have a higher
+ * precedence type.
  */
 static isc_result_t
 rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
            dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
-           dns_rdataset_t *ardataset, dns_rpz_st_t *st)
+           dns_rdataset_t *ardataset, dns_rpz_st_t *st,
+           dns_name_t *query_qname)
 {
        dns_rbtdb_t *rbtdb;
        struct in_addr ina;
@@ -4617,8 +4621,6 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
 
        if (rbtdb->rpz_cidr == NULL) {
                RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
-               dns_db_detach(&db);
-               dns_zone_detach(&zone);
                return (ISC_R_UNEXPECTED);
        }
 
@@ -4653,17 +4655,19 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
                        continue;
 
                /*
-                * Choose the policy with the longest matching prefix.
-                * Between policies with the same prefix, choose the first
-                * configured.
+                * If we already have a rule, discard this new rule if
+                * is not better.
+                * The caller has checked that st->m.rpz->num > rpz->num
+                * or st->m.rpz->num == rpz->num and st->m.type >= rpz_type
                 */
-               if (st->m.policy != DNS_RPZ_POLICY_MISS) {
-                       if (prefix < st->m.prefix)
-                               continue;
-                       if (prefix == st->m.prefix &&
-                           rpz->num > st->m.rpz->num)
-                               continue;
-               }
+               if (st->m.policy != DNS_RPZ_POLICY_MISS &&
+                   st->m.rpz->num == rpz->num &&
+                   (st->m.type < rpz_type ||
+                    (st->m.type == rpz_type &&
+                     (st->m.prefix > prefix ||
+                      (st->m.prefix == prefix &&
+                       0 > dns_name_rdatacompare(st->qname, qname))))))
+                       continue;
 
                /*
                 * We have rpz_st an entry with a prefix at least as long as
@@ -4677,8 +4681,8 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
                        char namebuf[DNS_NAME_FORMATSIZE];
 
                        dns_name_format(qname, namebuf, sizeof(namebuf));
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                                     DNS_LOGMODULE_CACHE, DNS_RPZ_ERROR_LEVEL,
+                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
+                                     DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
                                      "rpz_findips findnode(%s): %s",
                                      namebuf, isc_result_totext(result));
                        continue;
@@ -4702,7 +4706,8 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
                        } else {
                                rpz_policy = dns_rpz_decode_cname(&zrdataset,
                                                                  selfname);
-                               if (rpz_policy == DNS_RPZ_POLICY_RECORD)
+                               if (rpz_policy == DNS_RPZ_POLICY_RECORD ||
+                                   rpz_policy == DNS_RPZ_POLICY_WILDCNAME)
                                        result = DNS_R_CNAME;
                        }
                        ttl = zrdataset.ttl;
@@ -4715,44 +4720,59 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
                /*
                 * Use an overriding action specified in the configuration file
                 */
-               if (rpz->policy != DNS_RPZ_POLICY_GIVEN &&
-                   rpz_policy != DNS_RPZ_POLICY_NO_OP)
+               if (rpz->policy != DNS_RPZ_POLICY_GIVEN) {
+                       /*
+                        * only log DNS_RPZ_POLICY_DISABLED hits
+                        */
+                       if (rpz->policy == DNS_RPZ_POLICY_DISABLED) {
+                               if (isc_log_wouldlog(dns_lctx,
+                                                    DNS_RPZ_INFO_LEVEL)) {
+                                       char qname_buf[DNS_NAME_FORMATSIZE];
+                                       char rpz_qname_buf[DNS_NAME_FORMATSIZE];
+                                       dns_name_format(query_qname, qname_buf,
+                                                       sizeof(qname_buf));
+                                       dns_name_format(qname, rpz_qname_buf,
+                                                       sizeof(rpz_qname_buf));
+
+                                       isc_log_write(dns_lctx,
+                                               DNS_LOGCATEGORY_RPZ,
+                                               DNS_LOGMODULE_RBTDB,
+                                               DNS_RPZ_INFO_LEVEL,
+                                               "disabled rpz %s %s rewrite"
+                                               " %s via %s",
+                                               dns_rpz_type2str(rpz_type),
+                                               dns_rpz_policy2str(rpz_policy),
+                                               qname_buf, rpz_qname_buf);
+                               }
+                               continue;
+                       }
+
                        rpz_policy = rpz->policy;
+               }
 
-               /*
-                * We know the new prefix is at least as long as the current.
-                * Prefer the new answer if the new prefix is longer.
-                * Prefer the zone configured first if the prefixes are equal.
-                * With two actions from the same zone, prefer the action
-                * on the "smallest" name.
-                */
-               if (st->m.policy == DNS_RPZ_POLICY_MISS ||
-                   prefix > st->m.prefix ||
-                   rpz->num <= st->m.rpz->num ||
-                   0 > dns_name_compare(qname, st->qname)) {
-                       if (dns_rdataset_isassociated(st->m.rdataset))
-                               dns_rdataset_disassociate(st->m.rdataset);
-                       if (st->m.node != NULL)
-                               dns_db_detachnode(st->m.db, &st->m.node);
-                       if (st->m.db != NULL)
-                               dns_db_detach(&st->m.db);
-                       if (st->m.zone != NULL)
-                               dns_zone_detach(&st->m.zone);
-                       st->m.rpz = rpz;
-                       st->m.type = rpz_type;
-                       st->m.prefix = prefix;
-                       st->m.policy = rpz_policy;
-                       st->m.ttl = ttl;
-                       st->m.result = result;
-                       dns_name_copy(qname, st->qname, NULL);
-                       if (rpz_policy == DNS_RPZ_POLICY_RECORD &&
-                           result != DNS_R_NXRRSET) {
-                               dns_rdataset_clone(&zrdataset,st->m.rdataset);
-                               dns_db_attachnode(db, node, &st->m.node);
-                       }
-                       dns_db_attach(db, &st->m.db);
-                       dns_zone_attach(zone, &st->m.zone);
+               if (dns_rdataset_isassociated(st->m.rdataset))
+                       dns_rdataset_disassociate(st->m.rdataset);
+               if (st->m.node != NULL)
+                       dns_db_detachnode(st->m.db, &st->m.node);
+               if (st->m.db != NULL)
+                       dns_db_detach(&st->m.db);
+               if (st->m.zone != NULL)
+                       dns_zone_detach(&st->m.zone);
+               st->m.rpz = rpz;
+               st->m.type = rpz_type;
+               st->m.prefix = prefix;
+               st->m.policy = rpz_policy;
+               st->m.ttl = ttl;
+               st->m.result = result;
+               dns_name_copy(qname, st->qname, NULL);
+               if ((rpz_policy == DNS_RPZ_POLICY_RECORD ||
+                   rpz_policy == DNS_RPZ_POLICY_WILDCNAME) &&
+                   result != DNS_R_NXRRSET) {
+                       dns_rdataset_clone(&zrdataset,st->m.rdataset);
+                       dns_db_attachnode(db, node, &st->m.node);
                }
+               dns_db_attach(db, &st->m.db);
+               dns_zone_attach(zone, &st->m.zone);
                if (dns_rdataset_isassociated(&zrdataset))
                        dns_rdataset_disassociate(&zrdataset);
        }
index d3f990a38a585fba8da5f3fa27b88c415c6b7a69..b41f1fe05783f65e7fffc7935574c148f4153fd7 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rpz.c,v 1.7 2011/01/17 04:27:23 marka Exp $ */
+/* $Id: rpz.c,v 1.8 2011/10/13 01:32:34 vjs Exp $ */
 
 /*! \file */
 
@@ -116,20 +116,17 @@ struct dns_rpz_cidr_node {
 
 struct dns_rpz_cidr {
        isc_mem_t               *mctx;
-       isc_boolean_t           had_nsdname;
+       isc_boolean_t           have_nsdname;   /* zone has NSDNAME record */
        dns_rpz_cidr_node_t     *root;
-       dns_name_t              ip_name;        /* RPZ_IP_ZONE.LOCALHOST. */
+       dns_name_t              ip_name;        /* RPZ_IP_ZONE.LOCALHOST. */
        dns_name_t              nsip_name;      /* RPZ_NSIP_ZONE.LOCALHOST. */
        dns_name_t              nsdname_name;   /* RPZ_NSDNAME_ZONE.LOCALHOST */
 };
 
-
 static isc_boolean_t           have_rpz_zones = ISC_FALSE;
 
-
 const char *
-dns_rpz_type2str(dns_rpz_type_t type)
-{
+dns_rpz_type2str(dns_rpz_type_t type) {
        switch (type) {
        case DNS_RPZ_TYPE_QNAME:
                return ("QNAME");
@@ -143,31 +140,61 @@ dns_rpz_type2str(dns_rpz_type_t type)
                break;
        }
        FATAL_ERROR(__FILE__, __LINE__,
-                   "impossible response policy zone type %d", type);
+                   "impossible rpz type %d", type);
        return ("impossible");
 }
 
-
-
 dns_rpz_policy_t
-dns_rpz_str2policy(const char *str)
-{
+dns_rpz_str2policy(const char *str) {
        if (str == NULL)
                return (DNS_RPZ_POLICY_ERROR);
        if (!strcasecmp(str, "given"))
                return (DNS_RPZ_POLICY_GIVEN);
-       if (!strcasecmp(str, "no-op"))
-               return (DNS_RPZ_POLICY_NO_OP);
+       if (!strcasecmp(str, "disabled"))
+               return (DNS_RPZ_POLICY_DISABLED);
+       if (!strcasecmp(str, "passthru"))
+               return (DNS_RPZ_POLICY_PASSTHRU);
        if (!strcasecmp(str, "nxdomain"))
                return (DNS_RPZ_POLICY_NXDOMAIN);
        if (!strcasecmp(str, "nodata"))
                return (DNS_RPZ_POLICY_NODATA);
        if (!strcasecmp(str, "cname"))
                return (DNS_RPZ_POLICY_CNAME);
+       /*
+        * Obsolete
+        */
+       if (!strcasecmp(str, "no-op"))
+               return (DNS_RPZ_POLICY_PASSTHRU);
        return (DNS_RPZ_POLICY_ERROR);
 }
 
+const char *
+dns_rpz_policy2str(dns_rpz_policy_t policy) {
+       const char *str;
 
+       switch (policy) {
+       case DNS_RPZ_POLICY_PASSTHRU:
+               str = "PASSTHRU";
+               break;
+       case DNS_RPZ_POLICY_NXDOMAIN:
+               str = "NXDOMAIN";
+               break;
+       case DNS_RPZ_POLICY_NODATA:
+               str = "NODATA";
+               break;
+       case DNS_RPZ_POLICY_RECORD:
+               str = "records";
+               break;
+       case DNS_RPZ_POLICY_CNAME:
+       case DNS_RPZ_POLICY_WILDCNAME:
+               str = "CNAME";
+               break;
+       default:
+               str = "";
+               INSIST(0);
+       }
+       return (str);
+}
 
 /*
  * Free the radix tree of a response policy database.
@@ -214,8 +241,6 @@ dns_rpz_cidr_free(dns_rpz_cidr_t **cidrp) {
        *cidrp = NULL;
 }
 
-
-
 /*
  * Forget a view's list of policy zones.
  */
@@ -244,20 +269,15 @@ dns_rpz_view_destroy(dns_view_t *view) {
  * zone is in at least one view's list of policy zones.
  */
 void
-dns_rpz_set_need(isc_boolean_t need)
-{
+dns_rpz_set_need(isc_boolean_t need) {
        have_rpz_zones = need;
 }
 
-
 isc_boolean_t
-dns_rpz_needed(void)
-{
+dns_rpz_needed(void) {
        return (have_rpz_zones);
 }
 
-
-
 /*
  * Start a new radix tree for a response policy zone.
  */
@@ -313,12 +333,13 @@ dns_rpz_new_cidr(isc_mem_t *mctx, dns_name_t *origin,
        return (ISC_R_SUCCESS);
 }
 
-
 /*
  * See if a policy zone has IP, NSIP, or NSDNAME rules or records.
  */
 void
 dns_rpz_enabled(dns_rpz_cidr_t *cidr, dns_rpz_st_t *st) {
+       if (cidr == NULL)
+               return;
        if (cidr->root != NULL &&
            (cidr->root->flags & DNS_RPZ_CIDR_FG_IP) != 0)
                st->state |= DNS_RPZ_HAVE_IP;
@@ -328,8 +349,8 @@ dns_rpz_enabled(dns_rpz_cidr_t *cidr, dns_rpz_st_t *st) {
        if (cidr->root != NULL &&
            (cidr->root->flags & DNS_RPZ_CIDR_FG_NSIPv6) != 0)
                st->state |= DNS_RPZ_HAVE_NSIPv6;
-       if (cidr->had_nsdname)
-               st->state |= DNS_RPZ_HAD_NSDNAME;
+       if (cidr->have_nsdname)
+               st->state |= DNS_RPZ_HAVE_NSDNAME;
 }
 
 static inline dns_rpz_cidr_flags_t
@@ -350,8 +371,6 @@ get_flags(const dns_rpz_cidr_key_t *ip, dns_rpz_cidr_bits_t prefix,
        }
 }
 
-
-
 /*
  * Mark a node as having IP or NSIP data and all of its parents
  * as members of the IP or NSIP tree.
@@ -371,8 +390,6 @@ set_node_flags(dns_rpz_cidr_node_t *node, dns_rpz_type_t rpz_type) {
        }
 }
 
-
-
 /*
  * Make a radix tree node.
  */
@@ -409,24 +426,18 @@ new_node(dns_rpz_cidr_t *cidr, const dns_rpz_cidr_key_t *ip,
        return (node);
 }
 
-
-
 static void
-badname(int level, dns_name_t *name, const char *comment)
-{
+badname(int level, dns_name_t *name, const char *comment) {
        char printname[DNS_NAME_FORMATSIZE];
 
        if (isc_log_wouldlog(dns_lctx, level)) {
                dns_name_format(name, printname, sizeof(printname));
-               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
                              DNS_LOGMODULE_RBTDB, level,
-                             "invalid response policy name \"%s\"%s",
-                             printname, comment);
+                             "invalid rpz \"%s\"%s", printname, comment);
        }
 }
 
-
-
 /*
  * Convert an IP address from radix tree binary (host byte order) to
  * to its canonical response policy domain name and its name in the
@@ -520,8 +531,6 @@ ip2name(dns_rpz_cidr_t *cidr, const dns_rpz_cidr_key_t *tgt_ip,
        return (ISC_R_SUCCESS);
 }
 
-
-
 /*
  * Decide which kind of IP address response policy zone a name is in.
  */
@@ -548,8 +557,6 @@ set_type(dns_rpz_cidr_t *cidr, dns_name_t *name) {
        return (DNS_RPZ_TYPE_QNAME);
 }
 
-
-
 /*
  * Convert an IP address from canonical response policy domain name form
  * to radix tree binary (host byte order).
@@ -695,26 +702,37 @@ name2ipkey(dns_rpz_cidr_t *cidr, int level, dns_name_t *src_name,
        return (ISC_R_SUCCESS);
 }
 
-
-
 /*
- * find first differing bit
+ * Find first differing bit.
  */
 static int
 ffbit(dns_rpz_cidr_word_t w) {
        int bit;
 
-       if (w == 0)
-               return (DNS_RPZ_CIDR_WORD_BITS);
-       for (bit = 0; (w & (1U << (DNS_RPZ_CIDR_WORD_BITS-1))) == 0; bit++)
-               w <<= 1;
+       bit = DNS_RPZ_CIDR_WORD_BITS-1;
+       if ((w & 0xffff0000) != 0) {
+               w >>= 16;
+               bit -= 16;
+       }
+       if ((w & 0xff00) != 0) {
+               w >>= 8;
+               bit -= 8;
+       }
+       if ((w & 0xf0) != 0) {
+               w >>= 4;
+               bit -= 4;
+       }
+       if ((w & 0xc) != 0) {
+               w >>= 2;
+               bit -= 2;
+       }
+       if ((w & 2) != 0)
+               --bit;
        return (bit);
 }
 
-
-
 /*
- * find the first differing bit in two keys
+ * Find the first differing bit in two keys.
  */
 static int
 diff_keys(const dns_rpz_cidr_key_t *key1, dns_rpz_cidr_bits_t bits1,
@@ -741,14 +759,12 @@ diff_keys(const dns_rpz_cidr_key_t *key1, dns_rpz_cidr_bits_t bits1,
        return (ISC_MIN(bit, maxbit));
 }
 
-
-
 /*
  * Search a radix tree for an IP address for ordinary lookup
  *     or for a CIDR block adding or deleting an entry
  * The tree read (for simple search) or write lock must be held by the caller.
  *
- * return ISC_R_SUCCESS, ISC_R_NOTFOUND, DNS_R_PARTIALMATCH, ISC_R_EXISTS,
+ * Return ISC_R_SUCCESS, ISC_R_NOTFOUND, DNS_R_PARTIALMATCH, ISC_R_EXISTS,
  *     ISC_R_NOMEMORY
  */
 static isc_result_t
@@ -912,15 +928,12 @@ search(dns_rpz_cidr_t *cidr, const dns_rpz_cidr_key_t *tgt_ip,
        }
 }
 
-
-
 /*
  * Add an IP address to the radix tree of a response policy database.
  *     The tree write lock must be held by the caller.
  */
 void
-dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name)
-{
+dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name) {
        dns_rpz_cidr_key_t tgt_ip;
        dns_rpz_cidr_bits_t tgt_prefix;
        dns_rpz_type_t type;
@@ -929,7 +942,7 @@ dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name)
                return;
 
        /*
-        * no worries if the new name is not an IP address
+        * No worries if the new name is not an IP address.
         */
        type = set_type(cidr, name);
        switch (type) {
@@ -937,7 +950,7 @@ dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name)
        case DNS_RPZ_TYPE_NSIP:
                break;
        case DNS_RPZ_TYPE_NSDNAME:
-               cidr->had_nsdname = ISC_TRUE;
+               cidr->have_nsdname = ISC_TRUE;
                return;
        case DNS_RPZ_TYPE_QNAME:
        case DNS_RPZ_TYPE_BAD:
@@ -953,15 +966,12 @@ dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name)
                char printname[DNS_NAME_FORMATSIZE];
 
                dns_name_format(name, printname, sizeof(printname));
-               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
                              DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
-                             "duplicate response policy name \"%s\"",
-                             printname);
+                             "duplicate rpz name \"%s\"", printname);
        }
 }
 
-
-
 /*
  * Delete an IP address from the radix tree of a response policy database.
  *     The tree write lock must be held by the caller.
@@ -1000,7 +1010,7 @@ dns_rpz_cidr_deleteip(dns_rpz_cidr_t *cidr, dns_name_t *name) {
        /*
         * Do not get excited about the deletion of interior rbt nodes.
         */
-       if (ISC_R_SUCCESS != name2ipkey(cidr, DNS_RPZ_DEBUG_LEVEL2, name,
+       if (ISC_R_SUCCESS != name2ipkey(cidr, DNS_RPZ_DEBUG_LEVEL3, name,
                                        type, &tgt_ip, &tgt_prefix))
                return;
        if (ISC_R_SUCCESS != search(cidr, &tgt_ip, tgt_prefix, type,
@@ -1009,10 +1019,9 @@ dns_rpz_cidr_deleteip(dns_rpz_cidr_t *cidr, dns_name_t *name) {
                        char printname[DNS_NAME_FORMATSIZE];
 
                        dns_name_format(name, printname, sizeof(printname));
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
                                      DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
-                                     "missing response policy node \"%s\"",
-                                     printname);
+                                     "missing rpz node \"%s\"", printname);
                }
                return;
        }
@@ -1073,8 +1082,6 @@ dns_rpz_cidr_deleteip(dns_rpz_cidr_t *cidr, dns_name_t *name) {
        } while (tgt != NULL);
 }
 
-
-
 /*
  * Caller must hold tree lock.
  * Return  ISC_R_NOTFOUND
@@ -1124,8 +1131,6 @@ dns_rpz_cidr_find(dns_rpz_cidr_t *cidr, const isc_netaddr_t *netaddr,
                        canon_name, search_name));
 }
 
-
-
 /*
  * Translate CNAME rdata to a QNAME response policy action.
  */
@@ -1148,21 +1153,31 @@ dns_rpz_decode_cname(dns_rdataset_t *rdataset, dns_name_t *selfname) {
        if (dns_name_equal(&cname.cname, dns_rootname))
                return (DNS_RPZ_POLICY_NXDOMAIN);
 
-       /*
-        * CNAME *. means NODATA
-        */
-       if (dns_name_countlabels(&cname.cname) == 2
-           && dns_name_iswildcard(&cname.cname))
-               return (DNS_RPZ_POLICY_NODATA);
+       if (dns_name_iswildcard(&cname.cname)) {
+               /*
+                * CNAME *. means NODATA
+                */
+               if (dns_name_countlabels(&cname.cname) == 2)
+                       return (DNS_RPZ_POLICY_NODATA);
+
+               /*
+                * A qname of www.evil.com and a policy of
+                *      *.evil.com    CNAME   *.garden.net
+                * gives a result of
+                *      evil.com    CNAME   evil.com.garden.net
+                */
+               if (dns_name_countlabels(&cname.cname) > 2)
+                       return (DNS_RPZ_POLICY_WILDCNAME);
+       }
 
        /*
         * 128.1.0.127.rpz-ip CNAME  128.1.0.0.127. means "do not rewrite"
         */
        if (selfname != NULL && dns_name_equal(&cname.cname, selfname))
-               return (DNS_RPZ_POLICY_NO_OP);
+               return (DNS_RPZ_POLICY_PASSTHRU);
 
        /*
-        * evil.com CNAME garden.net rewrites www.evil.com to www.garden.net.
+        * Any other rdata gives a response consisting of the rdata.
         */
        return (DNS_RPZ_POLICY_RECORD);
 }
index 62fd560b497d8b63a918b08278be6b2441b922eb..a5f9dc50f5a6051fca1825ebb5f056db45da06c1 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: namedconf.c,v 1.141 2011/09/06 22:29:33 smann Exp $ */
+/* $Id: namedconf.c,v 1.142 2011/10/13 01:32:34 vjs Exp $ */
 
 /*! \file */
 
@@ -1027,7 +1027,8 @@ static cfg_type_t cfg_type_masterformat = {
 
 /*
  *  response-policy {
- *     zone <string> [ policy (given|no-op|nxdomain|nodata|cname <domain> ) ];
+ *     zone <string> [ policy (given|disabled|passthru|
+ *                                     nxdomain|nodata|cname <domain> ) ];
  *  };
  *
  * this is a chimera of doc_optional_keyvalue() and cfg_doc_enum()
@@ -1095,7 +1096,8 @@ cleanup:
 }
 
 static const char *rpz_policies[] = {
-       "given", "no-op", "nxdomain", "nodata", "cname", NULL
+       "given", "disabled", "passthru", "no-op", "nxdomain", "nodata",
+       "cname", NULL
 };
 static cfg_type_t cfg_type_rpz_policylist = {
        "policies", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,