rpz.c revision dcf426e9b546d4bcc0681904551752af43c1bcd6
0782f6cf216295b70cd608451422f5db560f2cf0kess * Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC")
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * Permission to use, copy, modify, and/or distribute this software for any
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * purpose with or without fee is hereby granted, provided that the above
0782f6cf216295b70cd608451422f5db560f2cf0kess * copyright notice and this permission notice appear in all copies.
0782f6cf216295b70cd608451422f5db560f2cf0kess * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
0782f6cf216295b70cd608451422f5db560f2cf0kess * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
0782f6cf216295b70cd608451422f5db560f2cf0kess * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
0782f6cf216295b70cd608451422f5db560f2cf0kess * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2e545ce2450a9953665f701bb05350f0d3f26275nd * PERFORMANCE OF THIS SOFTWARE.
0782f6cf216295b70cd608451422f5db560f2cf0kess/*! \file */
0782f6cf216295b70cd608451422f5db560f2cf0kess * Parallel radix trees for databases of response policy IP addresses
0782f6cf216295b70cd608451422f5db560f2cf0kess * The radix or patricia trees are somewhat specialized to handle response
0782f6cf216295b70cd608451422f5db560f2cf0kess * policy addresses by representing the two sets of IP addresses and name
0782f6cf216295b70cd608451422f5db560f2cf0kess * server IP addresses in a single tree. One set of IP addresses is
0782f6cf216295b70cd608451422f5db560f2cf0kess * for rpz-ip policies or policies triggered by addresses in A or
0782f6cf216295b70cd608451422f5db560f2cf0kess * AAAA records in responses.
d1348237b33bc1755b9f1165eea52317465a7671nd * The second set is for rpz-nsip policies or policies triggered by addresses
0782f6cf216295b70cd608451422f5db560f2cf0kess * in A or AAAA records for NS records that are authorities for responses.
0782f6cf216295b70cd608451422f5db560f2cf0kess * Each leaf indicates that an IP address is listed in the IP address or the
0782f6cf216295b70cd608451422f5db560f2cf0kess * name server IP address policy sub-zone (or both) of the corresponding
0782f6cf216295b70cd608451422f5db560f2cf0kess * response response zone. The policy data such as a CNAME or an A record
d1348237b33bc1755b9f1165eea52317465a7671nd * is kept in the policy zone. After an IP address has been found in a radix
0782f6cf216295b70cd608451422f5db560f2cf0kess * tree, the node in the policy zone's database is found by converting
b21197dc8e6b8c764fdcc24d4bae8b0eebb6bc4end * the IP address to a domain name in a canonical form.
20189240503ef2c8f5dc6e2248b57faab4b23b5and * The response policy zone canonical form of an IPv6 address is one of:
20189240503ef2c8f5dc6e2248b57faab4b23b5and * prefix.W.W.W.W.W.W.W.W
20189240503ef2c8f5dc6e2248b57faab4b23b5and * prefix.WORDS.zz
20189240503ef2c8f5dc6e2248b57faab4b23b5and * prefix.WORDS.zz.WORDS
20189240503ef2c8f5dc6e2248b57faab4b23b5and * prefix.zz.WORDS
20189240503ef2c8f5dc6e2248b57faab4b23b5and * prefix is the prefix length of the IPv6 address between 1 and 128
20189240503ef2c8f5dc6e2248b57faab4b23b5and * W is a number between 0 and 65535
20189240503ef2c8f5dc6e2248b57faab4b23b5and * WORDS is one or more numbers W separated with "."
0782f6cf216295b70cd608451422f5db560f2cf0kess * zz corresponds to :: in the standard IPv6 text representation
0782f6cf216295b70cd608451422f5db560f2cf0kess * The canonical form of IPv4 addresses is:
0782f6cf216295b70cd608451422f5db560f2cf0kess * prefix.B.B.B.B
0782f6cf216295b70cd608451422f5db560f2cf0kess * prefix is the prefix length of the address between 1 and 32
0782f6cf216295b70cd608451422f5db560f2cf0kess * B is a number between 0 and 255
0782f6cf216295b70cd608451422f5db560f2cf0kess * Names for IPv4 addresses are distinguished from IPv6 addresses by having
0782f6cf216295b70cd608451422f5db560f2cf0kess * 5 labels all of which are numbers, and a prefix between 1 and 32.
0782f6cf216295b70cd608451422f5db560f2cf0kess * Use a private definition of IPv6 addresses because s6_addr32 is not
0782f6cf216295b70cd608451422f5db560f2cf0kess * always defined and our IPv6 addresses are in non-standard byte order
0782f6cf216295b70cd608451422f5db560f2cf0kess#define DNS_RPZ_CIDR_WORD_BITS ((int)sizeof(dns_rpz_cidr_word_t)*8)
0782f6cf216295b70cd608451422f5db560f2cf0kess#define DNS_RPZ_CIDR_KEY_BITS ((int)sizeof(dns_rpz_cidr_key_t)*8)
0782f6cf216295b70cd608451422f5db560f2cf0kesstypedef struct {
d1348237b33bc1755b9f1165eea52317465a7671nd#define KEY_IS_IPV4(prefix,ip) ((prefix) >= 96 && (ip)->w[0] == 0 && \
0782f6cf216295b70cd608451422f5db560f2cf0kess#define DNS_RPZ_WORD_MASK(b) ((b) == 0 ? (dns_rpz_cidr_word_t)(-1) \
0782f6cf216295b70cd608451422f5db560f2cf0kess * Get bit #n from the array of words of an IP address.
0782f6cf216295b70cd608451422f5db560f2cf0kess#define DNS_RPZ_IP_BIT(ip, n) (1 & ((ip)->w[(n)/DNS_RPZ_CIDR_WORD_BITS] >> \
d1348237b33bc1755b9f1165eea52317465a7671nd * A pair of arrays of bits flagging the existence of
d1348237b33bc1755b9f1165eea52317465a7671nd * IP or QNAME (d) and NSIP or NSDNAME (ns) policy triggers.
0782f6cf216295b70cd608451422f5db560f2cf0kess * A CIDR or radix tree node.
0782f6cf216295b70cd608451422f5db560f2cf0kess * The data in a RBT node has two pairs of bits for policy zones.
0782f6cf216295b70cd608451422f5db560f2cf0kess * One pair is for the corresponding name of the node such as example.com
0782f6cf216295b70cd608451422f5db560f2cf0kess * and the other pair is for a wildcard child such as *.example.com.
0782f6cf216295b70cd608451422f5db560f2cf0kess * Catch a name while debugging.
0782f6cf216295b70cd608451422f5db560f2cf0kessstatic void
0782f6cf216295b70cd608451422f5db560f2cf0kesscatch_name(const dns_name_t *src_name, const char *tgt, const char *str) {
0782f6cf216295b70cd608451422f5db560f2cf0kess dns_name_fromstring(tgt_name, tgt, DNS_NAME_DOWNCASE, NULL);
0782f6cf216295b70cd608451422f5db560f2cf0kessconst char *
0782f6cf216295b70cd608451422f5db560f2cf0kess switch (type) {
0782f6cf216295b70cd608451422f5db560f2cf0kess return ("QNAME");
0782f6cf216295b70cd608451422f5db560f2cf0kess return ("IP");
0782f6cf216295b70cd608451422f5db560f2cf0kess return ("NSIP");
0782f6cf216295b70cd608451422f5db560f2cf0kess return ("NSDNAME");
0782f6cf216295b70cd608451422f5db560f2cf0kess FATAL_ERROR(__FILE__, __LINE__, "impossible rpz type %d", type);
0782f6cf216295b70cd608451422f5db560f2cf0kess return ("impossible");
0782f6cf216295b70cd608451422f5db560f2cf0kess * Obsolete
0782f6cf216295b70cd608451422f5db560f2cf0kessconst char *
0782f6cf216295b70cd608451422f5db560f2cf0kess const char *str;
0782f6cf216295b70cd608451422f5db560f2cf0kessstatic inline void
0782f6cf216295b70cd608451422f5db560f2cf0kessmake_pair(dns_rpz_pair_zbits_t *pair, dns_rpz_zbits_t zbits,
0782f6cf216295b70cd608451422f5db560f2cf0kess switch (type) {
0782f6cf216295b70cd608451422f5db560f2cf0kess * Mark a node and all of its parents as having IP or NSIP data
0782f6cf216295b70cd608451422f5db560f2cf0kessstatic void
0782f6cf216295b70cd608451422f5db560f2cf0kessstatic void
0782f6cf216295b70cd608451422f5db560f2cf0kess * Get a mask covering all policy zones that are not subordinate to
0782f6cf216295b70cd608451422f5db560f2cf0kess * other policy zones containing triggers that require that the
d1348237b33bc1755b9f1165eea52317465a7671nd * qname be resolved before they can be checked.
0782f6cf216295b70cd608451422f5db560f2cf0kess if (zbits == 0) {
0782f6cf216295b70cd608451422f5db560f2cf0kess rpzs->have.nsip = rpzs->have.nsipv4 | rpzs->have.nsipv6;
0782f6cf216295b70cd608451422f5db560f2cf0kessstatic void
0782f6cf216295b70cd608451422f5db560f2cf0kessadj_trigger_cnt(dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num,
0782f6cf216295b70cd608451422f5db560f2cf0kess const dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t tgt_prefix,
0782f6cf216295b70cd608451422f5db560f2cf0kess if (--*cnt == 0) {
0782f6cf216295b70cd608451422f5db560f2cf0kess while (i < words) {
0782f6cf216295b70cd608451422f5db560f2cf0kess if (wlen != 0) {
0782f6cf216295b70cd608451422f5db560f2cf0kessstatic void
0782f6cf216295b70cd608451422f5db560f2cf0kessbadname(int level, dns_name_t *name, const char *str1, const char *str2) {
0782f6cf216295b70cd608451422f5db560f2cf0kess * bin/tests/system/rpz/tests.sh looks for "invalid rpz".
0782f6cf216295b70cd608451422f5db560f2cf0kess "invalid rpz IP address \"%s\"%s%s",
0782f6cf216295b70cd608451422f5db560f2cf0kess * Convert an IP address from radix tree binary (host byte order) to
0782f6cf216295b70cd608451422f5db560f2cf0kess * to its canonical response policy domain name without the origin of the
0782f6cf216295b70cd608451422f5db560f2cf0kess * policy zone.
0782f6cf216295b70cd608451422f5db560f2cf0kessip2name(const dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t tgt_prefix,
0782f6cf216295b70cd608451422f5db560f2cf0kess int i, n, len;
0782f6cf216295b70cd608451422f5db560f2cf0kess for (i = 0; i < DNS_RPZ_CIDR_WORDS; i++) {
0782f6cf216295b70cd608451422f5db560f2cf0kess & 0xffff);
0782f6cf216295b70cd608451422f5db560f2cf0kess if (w[i] != 0 || zeros
0782f6cf216295b70cd608451422f5db560f2cf0kess || w[i+1] != 0) {
0782f6cf216295b70cd608451422f5db560f2cf0kess ".%x", w[i++]);
0782f6cf216295b70cd608451422f5db560f2cf0kess if (n < 0)
0782f6cf216295b70cd608451422f5db560f2cf0kess if (n < 0)
0782f6cf216295b70cd608451422f5db560f2cf0kess result = dns_name_fromtext(ip_name, &buffer, base_name, 0, NULL);
d1348237b33bc1755b9f1165eea52317465a7671nd * Determine the type a of a name in a response policy zone.
0782f6cf216295b70cd608451422f5db560f2cf0kess * Require `./configure --enable-rpz-nsip` and nsdname
0782f6cf216295b70cd608451422f5db560f2cf0kess * until consistency problems are resolved.
af84459fbf938e508fd10b01cb8d699c79083813takashi * Convert an IP address from canonical response policy domain name form
4b3a8afbfcea8b265d179a122bf40dfedd1ce280takashi * to radix tree binary (host byte order) for adding or deleting IP or NSIP
727872d18412fc021f03969b8641810d8896820bhumbedooh const dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num,
0d0ba3a410038e179b695446bb149cce6264e0abnd dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t *tgt_prefix,
0d0ba3a410038e179b695446bb149cce6264e0abnd unsigned long prefix_num, l;
return (ISC_R_FAILURE);
return (ISC_R_FAILURE);
return (ISC_R_FAILURE);
return (ISC_R_FAILURE);
tgt_ip->w[0] = 0;
return (ISC_R_FAILURE);
ip_labels--) {
return (ISC_R_FAILURE);
return (ISC_R_FAILURE);
return (ISC_R_FAILURE);
prefix -= i;
return (ISC_R_FAILURE);
return (ISC_R_SUCCESS);
unsigned int prefix_len, n;
prefix_len = 0;
n -= prefix_len;
int bit;
--bit;
return (bit);
for (i = 0, bit = 0;
if (delta != 0) {
static inline dns_rpz_zbits_t
return (zbits &= x);
static isc_result_t
cur_num = 0;
if (!create)
return (find_result);
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
if (!create)
return (find_result);
if (create) {
} else if (create) {
return (find_result);
if (!create)
return (find_result);
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
if (!create)
return (find_result);
return (ISC_R_NOMEMORY);
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
static isc_result_t
return (ISC_R_SUCCESS);
return (result);
return (result);
static isc_result_t
switch (result) {
case ISC_R_SUCCESS:
case ISC_R_EXISTS:
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
return (result);
return (ISC_R_EXISTS);
return (ISC_R_SUCCESS);
static isc_result_t
return (result);
return (ISC_R_NOMEMORY);
return (result);
return (result);
return (result);
return (result);
return (ISC_R_SUCCESS);
unsigned int refs;
if (refs != 0)
unsigned int refs;
if (refs == 0) {
return (result);
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
&found);
return (result);
&nmnode);
load_pair.d);
load_pair.d);
&new_data);
return (result);
return (result);
return (ISC_R_SUCCESS);
switch (rpz_type) {
case DNS_RPZ_TYPE_QNAME:
case DNS_RPZ_TYPE_NSDNAME:
case DNS_RPZ_TYPE_IP:
case DNS_RPZ_TYPE_NSIP:
case DNS_RPZ_TYPE_BAD:
return (result);
switch (rpz_type) {
case DNS_RPZ_TYPE_QNAME:
case DNS_RPZ_TYPE_NSDNAME:
case DNS_RPZ_TYPE_IP:
case DNS_RPZ_TYPE_NSIP:
case DNS_RPZ_TYPE_BAD:
tgt_ip.w[0] = 0;
return (DNS_RPZ_INVALID_NUM);
if (zbits == 0)
return (DNS_RPZ_INVALID_NUM);
return (DNS_RPZ_INVALID_NUM);
return (DNS_RPZ_INVALID_NUM);
return (rpz_num);
if (zbits == 0)
found_zbits = 0;
switch (result) {
case ISC_R_SUCCESS:
case DNS_R_PARTIALMATCH:
case ISC_R_NOTFOUND:
return (DNS_RPZ_POLICY_NXDOMAIN);
return (DNS_RPZ_POLICY_NODATA);
* A qname of www.evil.com and a policy of
* *.evil.com CNAME *.garden.net
return (DNS_RPZ_POLICY_WILDCNAME);
return (DNS_RPZ_POLICY_PASSTHRU);
return (DNS_RPZ_POLICY_PASSTHRU);
return (DNS_RPZ_POLICY_RECORD);