diff options
Diffstat (limited to 'lib/dns/rpz.c')
-rw-r--r-- | lib/dns/rpz.c | 183 |
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); } |