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