aboutsummaryrefslogtreecommitdiff
path: root/lib/dns/rpz.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/rpz.c')
-rw-r--r--lib/dns/rpz.c183
1 files changed, 99 insertions, 84 deletions
diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c
index f809e7b06485..e3f49897865d 100644
--- a/lib/dns/rpz.c
+++ b/lib/dns/rpz.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rpz.c,v 1.7 2011-01-17 04:27:23 marka Exp $ */
+/* $Id$ */
/*! \file */
@@ -116,20 +116,17 @@ struct dns_rpz_cidr_node {
struct dns_rpz_cidr {
isc_mem_t *mctx;
- isc_boolean_t had_nsdname;
+ isc_boolean_t have_nsdname; /* zone has NSDNAME record */
dns_rpz_cidr_node_t *root;
- dns_name_t ip_name; /* RPZ_IP_ZONE.LOCALHOST. */
+ dns_name_t ip_name; /* RPZ_IP_ZONE.LOCALHOST. */
dns_name_t nsip_name; /* RPZ_NSIP_ZONE.LOCALHOST. */
dns_name_t nsdname_name; /* RPZ_NSDNAME_ZONE.LOCALHOST */
};
-
static isc_boolean_t have_rpz_zones = ISC_FALSE;
-
const char *
-dns_rpz_type2str(dns_rpz_type_t type)
-{
+dns_rpz_type2str(dns_rpz_type_t type) {
switch (type) {
case DNS_RPZ_TYPE_QNAME:
return ("QNAME");
@@ -143,31 +140,61 @@ dns_rpz_type2str(dns_rpz_type_t type)
break;
}
FATAL_ERROR(__FILE__, __LINE__,
- "impossible response policy zone type %d", type);
+ "impossible rpz type %d", type);
return ("impossible");
}
-
-
dns_rpz_policy_t
-dns_rpz_str2policy(const char *str)
-{
+dns_rpz_str2policy(const char *str) {
if (str == NULL)
return (DNS_RPZ_POLICY_ERROR);
if (!strcasecmp(str, "given"))
return (DNS_RPZ_POLICY_GIVEN);
- if (!strcasecmp(str, "no-op"))
- return (DNS_RPZ_POLICY_NO_OP);
+ if (!strcasecmp(str, "disabled"))
+ return (DNS_RPZ_POLICY_DISABLED);
+ if (!strcasecmp(str, "passthru"))
+ return (DNS_RPZ_POLICY_PASSTHRU);
if (!strcasecmp(str, "nxdomain"))
return (DNS_RPZ_POLICY_NXDOMAIN);
if (!strcasecmp(str, "nodata"))
return (DNS_RPZ_POLICY_NODATA);
if (!strcasecmp(str, "cname"))
return (DNS_RPZ_POLICY_CNAME);
+ /*
+ * Obsolete
+ */
+ if (!strcasecmp(str, "no-op"))
+ return (DNS_RPZ_POLICY_PASSTHRU);
return (DNS_RPZ_POLICY_ERROR);
}
+const char *
+dns_rpz_policy2str(dns_rpz_policy_t policy) {
+ const char *str;
+ switch (policy) {
+ case DNS_RPZ_POLICY_PASSTHRU:
+ str = "PASSTHRU";
+ break;
+ case DNS_RPZ_POLICY_NXDOMAIN:
+ str = "NXDOMAIN";
+ break;
+ case DNS_RPZ_POLICY_NODATA:
+ str = "NODATA";
+ break;
+ case DNS_RPZ_POLICY_RECORD:
+ str = "records";
+ break;
+ case DNS_RPZ_POLICY_CNAME:
+ case DNS_RPZ_POLICY_WILDCNAME:
+ str = "CNAME";
+ break;
+ default:
+ str = "";
+ INSIST(0);
+ }
+ return (str);
+}
/*
* Free the radix tree of a response policy database.
@@ -214,8 +241,6 @@ dns_rpz_cidr_free(dns_rpz_cidr_t **cidrp) {
*cidrp = NULL;
}
-
-
/*
* Forget a view's list of policy zones.
*/
@@ -244,20 +269,15 @@ dns_rpz_view_destroy(dns_view_t *view) {
* zone is in at least one view's list of policy zones.
*/
void
-dns_rpz_set_need(isc_boolean_t need)
-{
+dns_rpz_set_need(isc_boolean_t need) {
have_rpz_zones = need;
}
-
isc_boolean_t
-dns_rpz_needed(void)
-{
+dns_rpz_needed(void) {
return (have_rpz_zones);
}
-
-
/*
* Start a new radix tree for a response policy zone.
*/
@@ -313,12 +333,13 @@ dns_rpz_new_cidr(isc_mem_t *mctx, dns_name_t *origin,
return (ISC_R_SUCCESS);
}
-
/*
* See if a policy zone has IP, NSIP, or NSDNAME rules or records.
*/
void
dns_rpz_enabled(dns_rpz_cidr_t *cidr, dns_rpz_st_t *st) {
+ if (cidr == NULL)
+ return;
if (cidr->root != NULL &&
(cidr->root->flags & DNS_RPZ_CIDR_FG_IP) != 0)
st->state |= DNS_RPZ_HAVE_IP;
@@ -328,8 +349,8 @@ dns_rpz_enabled(dns_rpz_cidr_t *cidr, dns_rpz_st_t *st) {
if (cidr->root != NULL &&
(cidr->root->flags & DNS_RPZ_CIDR_FG_NSIPv6) != 0)
st->state |= DNS_RPZ_HAVE_NSIPv6;
- if (cidr->had_nsdname)
- st->state |= DNS_RPZ_HAD_NSDNAME;
+ if (cidr->have_nsdname)
+ st->state |= DNS_RPZ_HAVE_NSDNAME;
}
static inline dns_rpz_cidr_flags_t
@@ -350,8 +371,6 @@ get_flags(const dns_rpz_cidr_key_t *ip, dns_rpz_cidr_bits_t prefix,
}
}
-
-
/*
* Mark a node as having IP or NSIP data and all of its parents
* as members of the IP or NSIP tree.
@@ -371,8 +390,6 @@ set_node_flags(dns_rpz_cidr_node_t *node, dns_rpz_type_t rpz_type) {
}
}
-
-
/*
* Make a radix tree node.
*/
@@ -409,24 +426,18 @@ new_node(dns_rpz_cidr_t *cidr, const dns_rpz_cidr_key_t *ip,
return (node);
}
-
-
static void
-badname(int level, dns_name_t *name, const char *comment)
-{
+badname(int level, dns_name_t *name, const char *comment) {
char printname[DNS_NAME_FORMATSIZE];
if (isc_log_wouldlog(dns_lctx, level)) {
dns_name_format(name, printname, sizeof(printname));
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, level,
- "invalid response policy name \"%s\"%s",
- printname, comment);
+ "invalid rpz \"%s\"%s", printname, comment);
}
}
-
-
/*
* Convert an IP address from radix tree binary (host byte order) to
* to its canonical response policy domain name and its name in the
@@ -520,8 +531,6 @@ ip2name(dns_rpz_cidr_t *cidr, const dns_rpz_cidr_key_t *tgt_ip,
return (ISC_R_SUCCESS);
}
-
-
/*
* Decide which kind of IP address response policy zone a name is in.
*/
@@ -548,8 +557,6 @@ set_type(dns_rpz_cidr_t *cidr, dns_name_t *name) {
return (DNS_RPZ_TYPE_QNAME);
}
-
-
/*
* Convert an IP address from canonical response policy domain name form
* to radix tree binary (host byte order).
@@ -695,26 +702,37 @@ name2ipkey(dns_rpz_cidr_t *cidr, int level, dns_name_t *src_name,
return (ISC_R_SUCCESS);
}
-
-
/*
- * find first differing bit
+ * Find first differing bit.
*/
static int
ffbit(dns_rpz_cidr_word_t w) {
int bit;
- if (w == 0)
- return (DNS_RPZ_CIDR_WORD_BITS);
- for (bit = 0; (w & (1U << (DNS_RPZ_CIDR_WORD_BITS-1))) == 0; bit++)
- w <<= 1;
+ bit = DNS_RPZ_CIDR_WORD_BITS-1;
+ if ((w & 0xffff0000) != 0) {
+ w >>= 16;
+ bit -= 16;
+ }
+ if ((w & 0xff00) != 0) {
+ w >>= 8;
+ bit -= 8;
+ }
+ if ((w & 0xf0) != 0) {
+ w >>= 4;
+ bit -= 4;
+ }
+ if ((w & 0xc) != 0) {
+ w >>= 2;
+ bit -= 2;
+ }
+ if ((w & 2) != 0)
+ --bit;
return (bit);
}
-
-
/*
- * find the first differing bit in two keys
+ * Find the first differing bit in two keys.
*/
static int
diff_keys(const dns_rpz_cidr_key_t *key1, dns_rpz_cidr_bits_t bits1,
@@ -741,14 +759,12 @@ diff_keys(const dns_rpz_cidr_key_t *key1, dns_rpz_cidr_bits_t bits1,
return (ISC_MIN(bit, maxbit));
}
-
-
/*
* Search a radix tree for an IP address for ordinary lookup
* or for a CIDR block adding or deleting an entry
* The tree read (for simple search) or write lock must be held by the caller.
*
- * return ISC_R_SUCCESS, ISC_R_NOTFOUND, DNS_R_PARTIALMATCH, ISC_R_EXISTS,
+ * Return ISC_R_SUCCESS, ISC_R_NOTFOUND, DNS_R_PARTIALMATCH, ISC_R_EXISTS,
* ISC_R_NOMEMORY
*/
static isc_result_t
@@ -912,15 +928,12 @@ search(dns_rpz_cidr_t *cidr, const dns_rpz_cidr_key_t *tgt_ip,
}
}
-
-
/*
* Add an IP address to the radix tree of a response policy database.
* The tree write lock must be held by the caller.
*/
void
-dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name)
-{
+dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name) {
dns_rpz_cidr_key_t tgt_ip;
dns_rpz_cidr_bits_t tgt_prefix;
dns_rpz_type_t type;
@@ -929,7 +942,7 @@ dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name)
return;
/*
- * no worries if the new name is not an IP address
+ * No worries if the new name is not an IP address.
*/
type = set_type(cidr, name);
switch (type) {
@@ -937,7 +950,7 @@ dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name)
case DNS_RPZ_TYPE_NSIP:
break;
case DNS_RPZ_TYPE_NSDNAME:
- cidr->had_nsdname = ISC_TRUE;
+ cidr->have_nsdname = ISC_TRUE;
return;
case DNS_RPZ_TYPE_QNAME:
case DNS_RPZ_TYPE_BAD:
@@ -953,15 +966,12 @@ dns_rpz_cidr_addip(dns_rpz_cidr_t *cidr, dns_name_t *name)
char printname[DNS_NAME_FORMATSIZE];
dns_name_format(name, printname, sizeof(printname));
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
- "duplicate response policy name \"%s\"",
- printname);
+ "duplicate rpz name \"%s\"", printname);
}
}
-
-
/*
* Delete an IP address from the radix tree of a response policy database.
* The tree write lock must be held by the caller.
@@ -1000,7 +1010,7 @@ dns_rpz_cidr_deleteip(dns_rpz_cidr_t *cidr, dns_name_t *name) {
/*
* Do not get excited about the deletion of interior rbt nodes.
*/
- if (ISC_R_SUCCESS != name2ipkey(cidr, DNS_RPZ_DEBUG_LEVEL2, name,
+ if (ISC_R_SUCCESS != name2ipkey(cidr, DNS_RPZ_DEBUG_LEVEL3, name,
type, &tgt_ip, &tgt_prefix))
return;
if (ISC_R_SUCCESS != search(cidr, &tgt_ip, tgt_prefix, type,
@@ -1009,10 +1019,9 @@ dns_rpz_cidr_deleteip(dns_rpz_cidr_t *cidr, dns_name_t *name) {
char printname[DNS_NAME_FORMATSIZE];
dns_name_format(name, printname, sizeof(printname));
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
- "missing response policy node \"%s\"",
- printname);
+ "missing rpz node \"%s\"", printname);
}
return;
}
@@ -1073,8 +1082,6 @@ dns_rpz_cidr_deleteip(dns_rpz_cidr_t *cidr, dns_name_t *name) {
} while (tgt != NULL);
}
-
-
/*
* Caller must hold tree lock.
* Return ISC_R_NOTFOUND
@@ -1124,8 +1131,6 @@ dns_rpz_cidr_find(dns_rpz_cidr_t *cidr, const isc_netaddr_t *netaddr,
canon_name, search_name));
}
-
-
/*
* Translate CNAME rdata to a QNAME response policy action.
*/
@@ -1148,21 +1153,31 @@ dns_rpz_decode_cname(dns_rdataset_t *rdataset, dns_name_t *selfname) {
if (dns_name_equal(&cname.cname, dns_rootname))
return (DNS_RPZ_POLICY_NXDOMAIN);
- /*
- * CNAME *. means NODATA
- */
- if (dns_name_countlabels(&cname.cname) == 2
- && dns_name_iswildcard(&cname.cname))
- return (DNS_RPZ_POLICY_NODATA);
+ if (dns_name_iswildcard(&cname.cname)) {
+ /*
+ * CNAME *. means NODATA
+ */
+ if (dns_name_countlabels(&cname.cname) == 2)
+ return (DNS_RPZ_POLICY_NODATA);
+
+ /*
+ * A qname of www.evil.com and a policy of
+ * *.evil.com CNAME *.garden.net
+ * gives a result of
+ * evil.com CNAME evil.com.garden.net
+ */
+ if (dns_name_countlabels(&cname.cname) > 2)
+ return (DNS_RPZ_POLICY_WILDCNAME);
+ }
/*
* 128.1.0.127.rpz-ip CNAME 128.1.0.0.127. means "do not rewrite"
*/
if (selfname != NULL && dns_name_equal(&cname.cname, selfname))
- return (DNS_RPZ_POLICY_NO_OP);
+ return (DNS_RPZ_POLICY_PASSTHRU);
/*
- * evil.com CNAME garden.net rewrites www.evil.com to www.garden.net.
+ * Any other rdata gives a response consisting of the rdata.
*/
return (DNS_RPZ_POLICY_RECORD);
}