* 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 */
}
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));
}
* 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];
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),
*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);
}
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)
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;
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;
}
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);
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
}
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);
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;
}
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);
* 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:
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.
*/
&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);
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;
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;
* 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;
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;
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);
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);
}
}
/*
- * 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);
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;
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;
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));
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);
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.
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,
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--;
}
/*
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) \
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;
}
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 {
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:
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 &&
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;
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:
* 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);
}
}
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
* 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.
* 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)
# 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
; 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
; 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
* 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 */ };
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";};
; 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"
; 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 .
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.
; 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
* 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;
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";};
# 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
; 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
; 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
; 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
; 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
; 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
# 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
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 () {
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
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
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"
# 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
# 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
- 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>
</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>
<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>
<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">
* 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 */
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));
}
* 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
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,
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.
* \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
* 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 */
#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
* 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
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;
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 */
};
/*
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.
*/
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;
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.
*/
#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);
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);
* 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 */
{ "lame-servers", 0 },
{ "delegation-only", 0 },
{ "edns-disabled", 0 },
+ { "rpz", 0 },
{ NULL, 0 }
};
* 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 */
* 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;
if (rbtdb->rpz_cidr == NULL) {
RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
- dns_db_detach(&db);
- dns_zone_detach(&zone);
return (ISC_R_UNEXPECTED);
}
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
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;
} 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;
/*
* 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);
}
* 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 */
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");
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.
*cidrp = NULL;
}
-
-
/*
* Forget a view's list of policy zones.
*/
* 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.
*/
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;
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
}
}
-
-
/*
* Mark a node as having IP or NSIP data and all of its parents
* as members of the IP or NSIP tree.
}
}
-
-
/*
* Make a radix tree node.
*/
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
return (ISC_R_SUCCESS);
}
-
-
/*
* Decide which kind of IP address response policy zone a name is in.
*/
return (DNS_RPZ_TYPE_QNAME);
}
-
-
/*
* Convert an IP address from canonical response policy domain name form
* to radix tree binary (host byte order).
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,
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
}
}
-
-
/*
* 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;
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) {
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:
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.
/*
* 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,
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;
}
} while (tgt != NULL);
}
-
-
/*
* Caller must hold tree lock.
* Return ISC_R_NOTFOUND
canon_name, search_name));
}
-
-
/*
* Translate CNAME rdata to a QNAME response policy action.
*/
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);
}
* 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 */
/*
* 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()
}
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,