2011-01-13 01:59:28 +00:00
|
|
|
/*
|
2018-02-15 12:38:22 +11:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2011-01-13 01:59:28 +00:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
2021-06-03 08:37:05 +02:00
|
|
|
*
|
2011-01-13 01:59:28 +00:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
2011-01-13 01:59:28 +00:00
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
2013-02-25 12:46:51 -08:00
|
|
|
* information regarding copyright ownership.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2013-02-25 23:46:03 +00:00
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
/*! \file */
|
|
|
|
|
2018-03-28 14:56:40 +02:00
|
|
|
#include <inttypes.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2022-08-26 14:11:47 +00:00
|
|
|
#include <stdint.h>
|
2018-10-29 23:03:51 +01:00
|
|
|
#include <stdlib.h>
|
2018-03-28 14:56:40 +02:00
|
|
|
|
2022-09-12 16:36:24 +02:00
|
|
|
#include <isc/async.h>
|
2011-01-13 01:59:28 +00:00
|
|
|
#include <isc/buffer.h>
|
2024-08-14 13:25:50 +02:00
|
|
|
#include <isc/log.h>
|
2022-07-26 13:03:40 +02:00
|
|
|
#include <isc/loop.h>
|
2022-10-05 11:21:28 +02:00
|
|
|
#include <isc/magic.h>
|
2011-01-13 01:59:28 +00:00
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/net.h>
|
|
|
|
#include <isc/netaddr.h>
|
2023-09-29 21:40:29 -07:00
|
|
|
#include <isc/refcount.h>
|
2021-10-04 17:14:53 +02:00
|
|
|
#include <isc/result.h>
|
2015-06-03 18:18:55 -07:00
|
|
|
#include <isc/rwlock.h>
|
2011-01-13 01:59:28 +00:00
|
|
|
#include <isc/string.h>
|
|
|
|
#include <isc/util.h>
|
2022-07-26 13:03:40 +02:00
|
|
|
#include <isc/work.h>
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
#include <dns/db.h>
|
2017-02-20 11:57:28 +01:00
|
|
|
#include <dns/dbiterator.h>
|
2017-09-11 11:53:42 -07:00
|
|
|
#include <dns/dnsrps.h>
|
2011-01-13 01:59:28 +00:00
|
|
|
#include <dns/fixedname.h>
|
2023-09-29 21:40:29 -07:00
|
|
|
#include <dns/qp.h>
|
2011-01-13 01:59:28 +00:00
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdataset.h>
|
2017-02-20 11:57:28 +01:00
|
|
|
#include <dns/rdatasetiter.h>
|
2011-01-13 01:59:28 +00:00
|
|
|
#include <dns/rdatastruct.h>
|
|
|
|
#include <dns/rpz.h>
|
|
|
|
#include <dns/view.h>
|
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
#define DNS_RPZ_ZONE_MAGIC ISC_MAGIC('r', 'p', 'z', ' ')
|
|
|
|
#define DNS_RPZ_ZONES_MAGIC ISC_MAGIC('r', 'p', 'z', 's')
|
|
|
|
|
|
|
|
#define DNS_RPZ_ZONE_VALID(rpz) ISC_MAGIC_VALID(rpz, DNS_RPZ_ZONE_MAGIC)
|
|
|
|
#define DNS_RPZ_ZONES_VALID(rpzs) ISC_MAGIC_VALID(rpzs, DNS_RPZ_ZONES_MAGIC)
|
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
|
|
|
* Parallel radix trees for databases of response policy IP addresses
|
|
|
|
*
|
2013-02-25 12:46:51 -08:00
|
|
|
* The radix or patricia trees are somewhat specialized to handle response
|
|
|
|
* policy addresses by representing the two sets of IP addresses and name
|
|
|
|
* server IP addresses in a single tree. One set of IP addresses is
|
|
|
|
* for rpz-ip policies or policies triggered by addresses in A or
|
|
|
|
* AAAA records in responses.
|
|
|
|
* The second set is for rpz-nsip policies or policies triggered by addresses
|
|
|
|
* in A or AAAA records for NS records that are authorities for responses.
|
2011-01-13 01:59:28 +00:00
|
|
|
*
|
|
|
|
* Each leaf indicates that an IP address is listed in the IP address or the
|
|
|
|
* name server IP address policy sub-zone (or both) of the corresponding
|
2015-05-07 08:26:27 +05:30
|
|
|
* response policy zone. The policy data such as a CNAME or an A record
|
2011-01-13 01:59:28 +00:00
|
|
|
* is kept in the policy zone. After an IP address has been found in a radix
|
|
|
|
* tree, the node in the policy zone's database is found by converting
|
|
|
|
* the IP address to a domain name in a canonical form.
|
|
|
|
*
|
2013-02-25 12:46:51 -08:00
|
|
|
*
|
|
|
|
* The response policy zone canonical form of an IPv6 address is one of:
|
2011-01-13 01:59:28 +00:00
|
|
|
* prefix.W.W.W.W.W.W.W.W
|
|
|
|
* prefix.WORDS.zz
|
|
|
|
* prefix.WORDS.zz.WORDS
|
|
|
|
* prefix.zz.WORDS
|
|
|
|
* where
|
|
|
|
* prefix is the prefix length of the IPv6 address between 1 and 128
|
|
|
|
* W is a number between 0 and 65535
|
|
|
|
* WORDS is one or more numbers W separated with "."
|
|
|
|
* zz corresponds to :: in the standard IPv6 text representation
|
|
|
|
*
|
|
|
|
* The canonical form of IPv4 addresses is:
|
|
|
|
* prefix.B.B.B.B
|
|
|
|
* where
|
|
|
|
* prefix is the prefix length of the address between 1 and 32
|
|
|
|
* B is a number between 0 and 255
|
|
|
|
*
|
2013-02-25 12:46:51 -08:00
|
|
|
* Names for IPv4 addresses are distinguished from IPv6 addresses by having
|
2011-01-13 01:59:28 +00:00
|
|
|
* 5 labels all of which are numbers, and a prefix between 1 and 32.
|
|
|
|
*/
|
|
|
|
|
2017-02-20 11:57:28 +01:00
|
|
|
/*
|
|
|
|
* Nodes hashtable calculation parameters
|
|
|
|
*/
|
|
|
|
#define DNS_RPZ_HTSIZE_MAX 24
|
|
|
|
#define DNS_RPZ_HTSIZE_DIV 3
|
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
static isc_result_t
|
|
|
|
dns__rpz_shuttingdown(dns_rpz_zones_t *rpzs);
|
2017-02-20 11:57:28 +01:00
|
|
|
static void
|
2022-10-05 11:21:28 +02:00
|
|
|
dns__rpz_timer_cb(void *);
|
2022-09-12 16:36:24 +02:00
|
|
|
static void
|
2022-10-05 11:21:28 +02:00
|
|
|
dns__rpz_timer_start(dns_rpz_zone_t *rpz);
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Use a private definition of IPv6 addresses because s6_addr32 is not
|
|
|
|
* always defined and our IPv6 addresses are in non-standard byte order
|
|
|
|
*/
|
2018-03-28 14:19:37 +02:00
|
|
|
typedef uint32_t dns_rpz_cidr_word_t;
|
2011-01-13 01:59:28 +00:00
|
|
|
#define DNS_RPZ_CIDR_WORD_BITS ((int)sizeof(dns_rpz_cidr_word_t) * 8)
|
|
|
|
#define DNS_RPZ_CIDR_KEY_BITS ((int)sizeof(dns_rpz_cidr_key_t) * 8)
|
|
|
|
#define DNS_RPZ_CIDR_WORDS (128 / DNS_RPZ_CIDR_WORD_BITS)
|
|
|
|
typedef struct {
|
|
|
|
dns_rpz_cidr_word_t w[DNS_RPZ_CIDR_WORDS];
|
|
|
|
} dns_rpz_cidr_key_t;
|
|
|
|
|
|
|
|
#define ADDR_V4MAPPED 0xffff
|
2013-02-25 12:46:51 -08:00
|
|
|
#define KEY_IS_IPV4(prefix, ip) \
|
|
|
|
((prefix) >= 96 && (ip)->w[0] == 0 && (ip)->w[1] == 0 && \
|
|
|
|
(ip)->w[2] == ADDR_V4MAPPED)
|
|
|
|
|
|
|
|
#define DNS_RPZ_WORD_MASK(b) \
|
|
|
|
((b) == 0 ? (dns_rpz_cidr_word_t)(-1) \
|
|
|
|
: ((dns_rpz_cidr_word_t)(-1) \
|
|
|
|
<< (DNS_RPZ_CIDR_WORD_BITS - (b))))
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* Get bit #n from the array of words of an IP address.
|
|
|
|
*/
|
|
|
|
#define DNS_RPZ_IP_BIT(ip, n) \
|
|
|
|
(1 & ((ip)->w[(n) / DNS_RPZ_CIDR_WORD_BITS] >> \
|
|
|
|
(DNS_RPZ_CIDR_WORD_BITS - 1 - ((n) % DNS_RPZ_CIDR_WORD_BITS))))
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
2013-07-12 14:46:47 -07:00
|
|
|
* A triplet of arrays of bits flagging the existence of
|
|
|
|
* client-IP, IP, and NSIP policy triggers.
|
2013-02-25 12:46:51 -08:00
|
|
|
*/
|
2013-07-12 14:46:47 -07:00
|
|
|
typedef struct dns_rpz_addr_zbits dns_rpz_addr_zbits_t;
|
|
|
|
struct dns_rpz_addr_zbits {
|
|
|
|
dns_rpz_zbits_t client_ip;
|
|
|
|
dns_rpz_zbits_t ip;
|
|
|
|
dns_rpz_zbits_t nsip;
|
2013-02-25 12:46:51 -08:00
|
|
|
};
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* A CIDR or radix tree node.
|
|
|
|
*/
|
2011-01-13 01:59:28 +00:00
|
|
|
struct dns_rpz_cidr_node {
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_rpz_cidr_node_t *parent;
|
|
|
|
dns_rpz_cidr_node_t *child[2];
|
|
|
|
dns_rpz_cidr_key_t ip;
|
|
|
|
dns_rpz_prefix_t prefix;
|
2013-07-12 14:46:47 -07:00
|
|
|
dns_rpz_addr_zbits_t set;
|
|
|
|
dns_rpz_addr_zbits_t sum;
|
2011-01-13 01:59:28 +00:00
|
|
|
};
|
|
|
|
|
2013-07-12 14:46:47 -07:00
|
|
|
/*
|
|
|
|
* A pair of arrays of bits flagging the existence of
|
|
|
|
* QNAME and NSDNAME policy triggers.
|
|
|
|
*/
|
|
|
|
typedef struct dns_rpz_nm_zbits dns_rpz_nm_zbits_t;
|
|
|
|
struct dns_rpz_nm_zbits {
|
|
|
|
dns_rpz_zbits_t qname;
|
|
|
|
dns_rpz_zbits_t ns;
|
|
|
|
};
|
|
|
|
|
2015-05-07 08:26:27 +05:30
|
|
|
/*
|
2023-09-29 21:40:29 -07:00
|
|
|
* The data for a name in the summary database. This has two pairs of bits
|
|
|
|
* for policy zones: one pair is for the exact name of the node, such as
|
|
|
|
* example.com, and the other pair is for a wildcard child such as
|
|
|
|
* *.example.com.
|
2015-05-07 08:26:27 +05:30
|
|
|
*/
|
2023-09-29 21:40:29 -07:00
|
|
|
typedef struct nmdata nmdata_t;
|
|
|
|
struct nmdata {
|
2024-03-11 22:10:41 -07:00
|
|
|
dns_name_t name;
|
2023-09-29 21:40:29 -07:00
|
|
|
isc_mem_t *mctx;
|
|
|
|
isc_refcount_t references;
|
2013-07-12 14:46:47 -07:00
|
|
|
dns_rpz_nm_zbits_t set;
|
|
|
|
dns_rpz_nm_zbits_t wild;
|
2011-01-13 01:59:28 +00:00
|
|
|
};
|
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
#ifdef DNS_RPZ_TRACE
|
|
|
|
#define nmdata_ref(ptr) nmdata__ref(ptr, __func__, __FILE__, __LINE__)
|
|
|
|
#define nmdata_unref(ptr) nmdata__unref(ptr, __func__, __FILE__, __LINE__)
|
|
|
|
#define nmdata_attach(ptr, ptrp) \
|
|
|
|
nmdata__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
|
|
|
|
#define nmdata_detach(ptrp) nmdata__detach(ptrp, __func__, __FILE__, __LINE__)
|
|
|
|
ISC_REFCOUNT_TRACE_DECL(nmdata);
|
|
|
|
#else
|
|
|
|
ISC_REFCOUNT_DECL(nmdata);
|
|
|
|
#endif
|
|
|
|
|
2022-03-08 17:13:26 +01:00
|
|
|
static isc_result_t
|
|
|
|
rpz_add(dns_rpz_zone_t *rpz, const dns_name_t *src_name);
|
|
|
|
static void
|
|
|
|
rpz_del(dns_rpz_zone_t *rpz, const dns_name_t *src_name);
|
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
static nmdata_t *
|
|
|
|
new_nmdata(isc_mem_t *mctx, const dns_name_t *name, const nmdata_t *data);
|
|
|
|
|
|
|
|
/* QP trie methods */
|
|
|
|
static void
|
|
|
|
qp_attach(void *uctx, void *pval, uint32_t ival);
|
|
|
|
static void
|
|
|
|
qp_detach(void *uctx, void *pval, uint32_t ival);
|
|
|
|
static size_t
|
|
|
|
qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
|
|
|
|
static void
|
|
|
|
qp_triename(void *uctx, char *buf, size_t size);
|
|
|
|
|
|
|
|
static dns_qpmethods_t qpmethods = {
|
|
|
|
qp_attach,
|
|
|
|
qp_detach,
|
|
|
|
qp_makekey,
|
|
|
|
qp_triename,
|
|
|
|
};
|
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
const char *
|
2011-10-13 01:32:34 +00:00
|
|
|
dns_rpz_type2str(dns_rpz_type_t type) {
|
2011-01-13 01:59:28 +00:00
|
|
|
switch (type) {
|
2013-07-12 14:46:47 -07:00
|
|
|
case DNS_RPZ_TYPE_CLIENT_IP:
|
|
|
|
return ("CLIENT-IP");
|
2011-01-13 01:59:28 +00:00
|
|
|
case DNS_RPZ_TYPE_QNAME:
|
|
|
|
return ("QNAME");
|
|
|
|
case DNS_RPZ_TYPE_IP:
|
|
|
|
return ("IP");
|
|
|
|
case DNS_RPZ_TYPE_NSIP:
|
|
|
|
return ("NSIP");
|
|
|
|
case DNS_RPZ_TYPE_NSDNAME:
|
|
|
|
return ("NSDNAME");
|
|
|
|
case DNS_RPZ_TYPE_BAD:
|
|
|
|
break;
|
|
|
|
}
|
2022-10-14 16:07:07 +01:00
|
|
|
FATAL_ERROR("impossible rpz type %d", type);
|
2011-01-13 01:59:28 +00:00
|
|
|
return ("impossible");
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_rpz_policy_t
|
2011-10-13 01:32:34 +00:00
|
|
|
dns_rpz_str2policy(const char *str) {
|
2013-07-12 14:46:47 -07:00
|
|
|
static struct {
|
|
|
|
const char *str;
|
|
|
|
dns_rpz_policy_t policy;
|
|
|
|
} tbl[] = {
|
|
|
|
{ "given", DNS_RPZ_POLICY_GIVEN },
|
|
|
|
{ "disabled", DNS_RPZ_POLICY_DISABLED },
|
|
|
|
{ "passthru", DNS_RPZ_POLICY_PASSTHRU },
|
|
|
|
{ "drop", DNS_RPZ_POLICY_DROP },
|
|
|
|
{ "tcp-only", DNS_RPZ_POLICY_TCP_ONLY },
|
|
|
|
{ "nxdomain", DNS_RPZ_POLICY_NXDOMAIN },
|
|
|
|
{ "nodata", DNS_RPZ_POLICY_NODATA },
|
|
|
|
{ "cname", DNS_RPZ_POLICY_CNAME },
|
|
|
|
{ "no-op", DNS_RPZ_POLICY_PASSTHRU }, /* old passthru */
|
|
|
|
};
|
|
|
|
unsigned int n;
|
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
if (str == NULL) {
|
|
|
|
return (DNS_RPZ_POLICY_ERROR);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-07-12 14:46:47 -07:00
|
|
|
for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); ++n) {
|
|
|
|
if (!strcasecmp(tbl[n].str, str)) {
|
|
|
|
return (tbl[n].policy);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-07-12 14:46:47 -07:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
return (DNS_RPZ_POLICY_ERROR);
|
|
|
|
}
|
|
|
|
|
2011-10-13 01:32:34 +00:00
|
|
|
const char *
|
|
|
|
dns_rpz_policy2str(dns_rpz_policy_t policy) {
|
2022-03-08 17:13:26 +01:00
|
|
|
const char *str = NULL;
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2011-10-13 01:32:34 +00:00
|
|
|
switch (policy) {
|
|
|
|
case DNS_RPZ_POLICY_PASSTHRU:
|
|
|
|
str = "PASSTHRU";
|
|
|
|
break;
|
2013-07-12 14:46:47 -07:00
|
|
|
case DNS_RPZ_POLICY_DROP:
|
|
|
|
str = "DROP";
|
|
|
|
break;
|
|
|
|
case DNS_RPZ_POLICY_TCP_ONLY:
|
|
|
|
str = "TCP-ONLY";
|
|
|
|
break;
|
2011-10-13 01:32:34 +00:00
|
|
|
case DNS_RPZ_POLICY_NXDOMAIN:
|
|
|
|
str = "NXDOMAIN";
|
|
|
|
break;
|
|
|
|
case DNS_RPZ_POLICY_NODATA:
|
|
|
|
str = "NODATA";
|
|
|
|
break;
|
|
|
|
case DNS_RPZ_POLICY_RECORD:
|
2012-05-31 02:03:34 +00:00
|
|
|
str = "Local-Data";
|
2011-10-13 01:32:34 +00:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_POLICY_CNAME:
|
|
|
|
case DNS_RPZ_POLICY_WILDCNAME:
|
|
|
|
str = "CNAME";
|
|
|
|
break;
|
2014-07-22 10:57:58 +10:00
|
|
|
case DNS_RPZ_POLICY_MISS:
|
|
|
|
str = "MISS";
|
|
|
|
break;
|
2019-07-01 13:44:30 +10:00
|
|
|
case DNS_RPZ_POLICY_DNS64:
|
|
|
|
str = "DNS64";
|
|
|
|
break;
|
2022-05-04 17:03:15 +10:00
|
|
|
case DNS_RPZ_POLICY_ERROR:
|
|
|
|
str = "ERROR";
|
|
|
|
break;
|
2011-10-13 01:32:34 +00:00
|
|
|
default:
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2011-10-13 01:32:34 +00:00
|
|
|
}
|
|
|
|
return (str);
|
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2022-08-26 14:11:47 +00:00
|
|
|
uint16_t
|
|
|
|
dns_rpz_str2ede(const char *str) {
|
|
|
|
static struct {
|
|
|
|
const char *str;
|
|
|
|
uint16_t ede;
|
|
|
|
} tbl[] = {
|
|
|
|
{ "none", 0 },
|
|
|
|
{ "forged", DNS_EDE_FORGEDANSWER },
|
|
|
|
{ "blocked", DNS_EDE_BLOCKED },
|
|
|
|
{ "censored", DNS_EDE_CENSORED },
|
|
|
|
{ "filtered", DNS_EDE_FILTERED },
|
|
|
|
{ "prohibited", DNS_EDE_PROHIBITED },
|
|
|
|
};
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
if (str == NULL) {
|
|
|
|
return (UINT16_MAX);
|
|
|
|
}
|
|
|
|
for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); ++n) {
|
|
|
|
if (!strcasecmp(tbl[n].str, str)) {
|
|
|
|
return (tbl[n].ede);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (UINT16_MAX);
|
|
|
|
}
|
|
|
|
|
2015-05-07 08:26:27 +05:30
|
|
|
/*
|
|
|
|
* Return the bit number of the highest set bit in 'zbit'.
|
|
|
|
* (for example, 0x01 returns 0, 0xFF returns 7, etc.)
|
|
|
|
*/
|
2013-02-25 12:46:51 -08:00
|
|
|
static int
|
|
|
|
zbit_to_num(dns_rpz_zbits_t zbit) {
|
|
|
|
dns_rpz_num_t rpz_num;
|
|
|
|
|
2015-05-07 08:26:27 +05:30
|
|
|
REQUIRE(zbit != 0);
|
2013-02-25 12:46:51 -08:00
|
|
|
rpz_num = 0;
|
2018-03-01 22:02:59 +05:30
|
|
|
if ((zbit & 0xffffffff00000000ULL) != 0) {
|
2013-02-25 12:46:51 -08:00
|
|
|
zbit >>= 32;
|
|
|
|
rpz_num += 32;
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
if ((zbit & 0xffff0000) != 0) {
|
|
|
|
zbit >>= 16;
|
|
|
|
rpz_num += 16;
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
if ((zbit & 0xff00) != 0) {
|
|
|
|
zbit >>= 8;
|
|
|
|
rpz_num += 8;
|
|
|
|
}
|
|
|
|
if ((zbit & 0xf0) != 0) {
|
|
|
|
zbit >>= 4;
|
|
|
|
rpz_num += 4;
|
|
|
|
}
|
|
|
|
if ((zbit & 0xc) != 0) {
|
|
|
|
zbit >>= 2;
|
|
|
|
rpz_num += 2;
|
|
|
|
}
|
|
|
|
if ((zbit & 2) != 0) {
|
|
|
|
++rpz_num;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
return (rpz_num);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
2013-07-12 14:46:47 -07:00
|
|
|
/*
|
|
|
|
* Make a set of bit masks given one or more bits and their type.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
make_addr_set(dns_rpz_addr_zbits_t *tgt_set, dns_rpz_zbits_t zbits,
|
|
|
|
dns_rpz_type_t type) {
|
2013-02-25 12:46:51 -08:00
|
|
|
switch (type) {
|
2013-07-12 14:46:47 -07:00
|
|
|
case DNS_RPZ_TYPE_CLIENT_IP:
|
|
|
|
tgt_set->client_ip = zbits;
|
|
|
|
tgt_set->ip = 0;
|
|
|
|
tgt_set->nsip = 0;
|
|
|
|
break;
|
2013-02-25 12:46:51 -08:00
|
|
|
case DNS_RPZ_TYPE_IP:
|
2013-07-12 14:46:47 -07:00
|
|
|
tgt_set->client_ip = 0;
|
|
|
|
tgt_set->ip = zbits;
|
|
|
|
tgt_set->nsip = 0;
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_NSIP:
|
2013-07-12 14:46:47 -07:00
|
|
|
tgt_set->client_ip = 0;
|
|
|
|
tgt_set->ip = 0;
|
|
|
|
tgt_set->nsip = zbits;
|
|
|
|
break;
|
|
|
|
default:
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2013-07-12 14:46:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
make_nm_set(dns_rpz_nm_zbits_t *tgt_set, dns_rpz_num_t rpz_num,
|
|
|
|
dns_rpz_type_t type) {
|
|
|
|
switch (type) {
|
|
|
|
case DNS_RPZ_TYPE_QNAME:
|
|
|
|
tgt_set->qname = DNS_RPZ_ZBIT(rpz_num);
|
|
|
|
tgt_set->ns = 0;
|
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_NSDNAME:
|
|
|
|
tgt_set->qname = 0;
|
|
|
|
tgt_set->ns = DNS_RPZ_ZBIT(rpz_num);
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
|
|
|
default:
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-07-12 14:46:47 -07:00
|
|
|
* Mark a node and all of its parents as having client-IP, IP, or NSIP data
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2013-02-25 12:46:51 -08:00
|
|
|
static void
|
|
|
|
set_sum_pair(dns_rpz_cidr_node_t *cnode) {
|
2013-07-12 14:46:47 -07:00
|
|
|
dns_rpz_addr_zbits_t sum;
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
do {
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_rpz_cidr_node_t *child = cnode->child[0];
|
2013-07-12 14:46:47 -07:00
|
|
|
sum = cnode->set;
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
if (child != NULL) {
|
2013-07-12 14:46:47 -07:00
|
|
|
sum.client_ip |= child->sum.client_ip;
|
|
|
|
sum.ip |= child->sum.ip;
|
|
|
|
sum.nsip |= child->sum.nsip;
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
child = cnode->child[1];
|
|
|
|
if (child != NULL) {
|
2013-07-12 14:46:47 -07:00
|
|
|
sum.client_ip |= child->sum.client_ip;
|
|
|
|
sum.ip |= child->sum.ip;
|
|
|
|
sum.nsip |= child->sum.nsip;
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-07-12 14:46:47 -07:00
|
|
|
if (cnode->sum.client_ip == sum.client_ip &&
|
|
|
|
cnode->sum.ip == sum.ip && cnode->sum.nsip == sum.nsip)
|
|
|
|
{
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
cnode->sum = sum;
|
|
|
|
cnode = cnode->parent;
|
|
|
|
} while (cnode != NULL);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
2015-05-19 15:47:42 -07:00
|
|
|
/* Caller must hold rpzs->maint_lock */
|
2013-02-25 12:46:51 -08:00
|
|
|
static void
|
|
|
|
fix_qname_skip_recurse(dns_rpz_zones_t *rpzs) {
|
2015-05-07 08:26:27 +05:30
|
|
|
dns_rpz_zbits_t mask;
|
|
|
|
|
2015-05-28 15:04:40 -07:00
|
|
|
/*
|
|
|
|
* qname_wait_recurse and qname_skip_recurse are used to
|
2015-05-07 08:26:27 +05:30
|
|
|
* implement the "qname-wait-recurse" config option.
|
|
|
|
*
|
2017-09-11 11:53:42 -07:00
|
|
|
* When "qname-wait-recurse" is yes, no processing happens without
|
|
|
|
* recursion. In this case, qname_wait_recurse is true, and
|
|
|
|
* qname_skip_recurse (a bit field indicating which policy zones
|
|
|
|
* can be processed without recursion) is set to all 0's by
|
2015-05-07 08:26:27 +05:30
|
|
|
* fix_qname_skip_recurse().
|
|
|
|
*
|
|
|
|
* When "qname-wait-recurse" is no, qname_skip_recurse may be
|
|
|
|
* set to a non-zero value by fix_qname_skip_recurse(). The mask
|
2015-05-28 15:04:40 -07:00
|
|
|
* has to have bits set for the policy zones for which
|
2015-05-07 08:26:27 +05:30
|
|
|
* processing may continue without recursion, and bits cleared
|
|
|
|
* for the rest.
|
|
|
|
*
|
|
|
|
* (1) The ARM says:
|
|
|
|
*
|
|
|
|
* The "qname-wait-recurse no" option overrides that default
|
|
|
|
* behavior when recursion cannot change a non-error
|
|
|
|
* response. The option does not affect QNAME or client-IP
|
|
|
|
* triggers in policy zones listed after other zones
|
|
|
|
* containing IP, NSIP and NSDNAME triggers, because those may
|
|
|
|
* depend on the A, AAAA, and NS records that would be found
|
|
|
|
* during recursive resolution.
|
|
|
|
*
|
|
|
|
* Let's consider the following:
|
|
|
|
*
|
|
|
|
* zbits_req = (rpzs->have.ipv4 | rpzs->have.ipv6 |
|
|
|
|
* rpzs->have.nsdname |
|
|
|
|
* rpzs->have.nsipv4 | rpzs->have.nsipv6);
|
|
|
|
*
|
|
|
|
* zbits_req now contains bits set for zones which require
|
|
|
|
* recursion.
|
|
|
|
*
|
|
|
|
* But going by the description in the ARM, if the first policy
|
|
|
|
* zone requires recursion, then all zones after that (higher
|
|
|
|
* order bits) have to wait as well. If the Nth zone requires
|
|
|
|
* recursion, then (N+1)th zone onwards all need to wait.
|
|
|
|
*
|
|
|
|
* So mapping this, examples:
|
|
|
|
*
|
|
|
|
* zbits_req = 0b000 mask = 0xffffffff (no zones have to wait for
|
|
|
|
* recursion)
|
|
|
|
* zbits_req = 0b001 mask = 0x00000000 (all zones have to wait)
|
|
|
|
* zbits_req = 0b010 mask = 0x00000001 (the first zone doesn't have to
|
|
|
|
* wait, second zone onwards need
|
|
|
|
* to wait)
|
|
|
|
* zbits_req = 0b011 mask = 0x00000000 (all zones have to wait)
|
|
|
|
* zbits_req = 0b100 mask = 0x00000011 (the 1st and 2nd zones don't
|
|
|
|
* have to wait, third zone
|
|
|
|
* onwards need to wait)
|
|
|
|
*
|
|
|
|
* More generally, we have to count the number of trailing 0
|
|
|
|
* bits in zbits_req and only these can be processed without
|
|
|
|
* recursion. All the rest need to wait.
|
|
|
|
*
|
|
|
|
* (2) The ARM says that "qname-wait-recurse no" option
|
|
|
|
* overrides the default behavior when recursion cannot change a
|
|
|
|
* non-error response. So, in the order of listing of policy
|
|
|
|
* zones, within the first policy zone where recursion may be
|
|
|
|
* required, we should first allow CLIENT-IP and QNAME policy
|
|
|
|
* records to be attempted without recursion.
|
|
|
|
*/
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* Get a mask covering all policy zones that are not subordinate to
|
|
|
|
* other policy zones containing triggers that require that the
|
|
|
|
* qname be resolved before they can be checked.
|
|
|
|
*/
|
2015-05-07 08:26:27 +05:30
|
|
|
rpzs->have.client_ip = rpzs->have.client_ipv4 | rpzs->have.client_ipv6;
|
|
|
|
rpzs->have.ip = rpzs->have.ipv4 | rpzs->have.ipv6;
|
|
|
|
rpzs->have.nsip = rpzs->have.nsipv4 | rpzs->have.nsipv6;
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
if (rpzs->p.qname_wait_recurse) {
|
2015-05-07 08:26:27 +05:30
|
|
|
mask = 0;
|
2011-01-13 01:59:28 +00:00
|
|
|
} else {
|
2015-05-07 08:26:27 +05:30
|
|
|
dns_rpz_zbits_t zbits_req;
|
|
|
|
dns_rpz_zbits_t zbits_notreq;
|
|
|
|
dns_rpz_zbits_t mask2;
|
|
|
|
dns_rpz_zbits_t req_mask;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the masks of zones with policies that
|
|
|
|
* do/don't require recursion
|
|
|
|
*/
|
|
|
|
|
|
|
|
zbits_req = (rpzs->have.ipv4 | rpzs->have.ipv6 |
|
|
|
|
rpzs->have.nsdname | rpzs->have.nsipv4 |
|
|
|
|
rpzs->have.nsipv6);
|
|
|
|
zbits_notreq = (rpzs->have.client_ip | rpzs->have.qname);
|
|
|
|
|
|
|
|
if (zbits_req == 0) {
|
|
|
|
mask = DNS_RPZ_ALL_ZBITS;
|
|
|
|
goto set;
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
2015-05-07 08:26:27 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* req_mask is a mask covering used bits in
|
|
|
|
* zbits_req. (For instance, 0b1 => 0b1, 0b101 => 0b111,
|
|
|
|
* 0b11010101 => 0b11111111).
|
|
|
|
*/
|
|
|
|
req_mask = zbits_req;
|
|
|
|
req_mask |= req_mask >> 1;
|
|
|
|
req_mask |= req_mask >> 2;
|
|
|
|
req_mask |= req_mask >> 4;
|
|
|
|
req_mask |= req_mask >> 8;
|
|
|
|
req_mask |= req_mask >> 16;
|
|
|
|
req_mask |= req_mask >> 32;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There's no point in skipping recursion for a later
|
|
|
|
* zone if it is required in a previous zone.
|
|
|
|
*/
|
|
|
|
if ((zbits_notreq & req_mask) == 0) {
|
|
|
|
mask = 0;
|
|
|
|
goto set;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This bit arithmetic creates a mask of zones in which
|
|
|
|
* it is okay to skip recursion. After the first zone
|
|
|
|
* that has to wait for recursion, all the others have
|
|
|
|
* to wait as well, so we want to create a mask in which
|
|
|
|
* all the trailing zeroes in zbits_req are are 1, and
|
|
|
|
* more significant bits are 0. (For instance,
|
|
|
|
* 0x0700 => 0x00ff, 0x0007 => 0x0000)
|
|
|
|
*/
|
2015-08-13 14:58:28 -07:00
|
|
|
mask = ~(zbits_req | ((~zbits_req) + 1));
|
2015-05-07 08:26:27 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* As mentioned in (2) above, the zone corresponding to
|
|
|
|
* the least significant zero could have its CLIENT-IP
|
|
|
|
* and QNAME policies checked before recursion, if it
|
|
|
|
* has any of those policies. So if it does, we
|
|
|
|
* can set its 0 to 1.
|
|
|
|
*
|
|
|
|
* Locate the least significant 0 bit in the mask (for
|
|
|
|
* instance, 0xff => 0x100)...
|
|
|
|
*/
|
|
|
|
mask2 = (mask << 1) & ~mask;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Also set the bit for zone 0, because if it's in
|
|
|
|
* zbits_notreq then it's definitely okay to attempt to
|
|
|
|
* skip recursion for zone 0...
|
|
|
|
*/
|
|
|
|
mask2 |= 1;
|
|
|
|
|
|
|
|
/* Clear any bits *not* in zbits_notreq... */
|
|
|
|
mask2 &= zbits_notreq;
|
|
|
|
|
|
|
|
/* And merge the result into the skip-recursion mask */
|
|
|
|
mask |= mask2;
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2015-05-07 08:26:27 +05:30
|
|
|
set:
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
|
2015-05-07 08:26:27 +05:30
|
|
|
DNS_RPZ_DEBUG_QUIET,
|
2018-03-28 14:56:40 +02:00
|
|
|
"computed RPZ qname_skip_recurse mask=0x%" PRIx64,
|
2018-03-28 14:19:37 +02:00
|
|
|
(uint64_t)mask);
|
2015-05-07 08:26:27 +05:30
|
|
|
rpzs->have.qname_skip_recurse = mask;
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-03-08 17:13:26 +01:00
|
|
|
adj_trigger_cnt(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
|
|
|
|
const dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t tgt_prefix,
|
|
|
|
bool inc) {
|
2018-10-11 11:57:57 +02:00
|
|
|
dns_rpz_trigger_counter_t *cnt = NULL;
|
|
|
|
dns_rpz_zbits_t *have = NULL;
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
switch (rpz_type) {
|
2013-07-12 14:46:47 -07:00
|
|
|
case DNS_RPZ_TYPE_CLIENT_IP:
|
|
|
|
REQUIRE(tgt_ip != NULL);
|
|
|
|
if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) {
|
2022-03-08 17:13:26 +01:00
|
|
|
cnt = &rpz->rpzs->triggers[rpz->num].client_ipv4;
|
|
|
|
have = &rpz->rpzs->have.client_ipv4;
|
2013-07-12 14:46:47 -07:00
|
|
|
} else {
|
2022-03-08 17:13:26 +01:00
|
|
|
cnt = &rpz->rpzs->triggers[rpz->num].client_ipv6;
|
|
|
|
have = &rpz->rpzs->have.client_ipv6;
|
2013-07-12 14:46:47 -07:00
|
|
|
}
|
|
|
|
break;
|
2013-02-25 12:46:51 -08:00
|
|
|
case DNS_RPZ_TYPE_QNAME:
|
2022-03-08 17:13:26 +01:00
|
|
|
cnt = &rpz->rpzs->triggers[rpz->num].qname;
|
|
|
|
have = &rpz->rpzs->have.qname;
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_IP:
|
|
|
|
REQUIRE(tgt_ip != NULL);
|
|
|
|
if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) {
|
2022-03-08 17:13:26 +01:00
|
|
|
cnt = &rpz->rpzs->triggers[rpz->num].ipv4;
|
|
|
|
have = &rpz->rpzs->have.ipv4;
|
2013-02-25 12:46:51 -08:00
|
|
|
} else {
|
2022-03-08 17:13:26 +01:00
|
|
|
cnt = &rpz->rpzs->triggers[rpz->num].ipv6;
|
|
|
|
have = &rpz->rpzs->have.ipv6;
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_NSDNAME:
|
2022-03-08 17:13:26 +01:00
|
|
|
cnt = &rpz->rpzs->triggers[rpz->num].nsdname;
|
|
|
|
have = &rpz->rpzs->have.nsdname;
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_NSIP:
|
|
|
|
REQUIRE(tgt_ip != NULL);
|
|
|
|
if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) {
|
2022-03-08 17:13:26 +01:00
|
|
|
cnt = &rpz->rpzs->triggers[rpz->num].nsipv4;
|
|
|
|
have = &rpz->rpzs->have.nsipv4;
|
2013-02-25 12:46:51 -08:00
|
|
|
} else {
|
2022-03-08 17:13:26 +01:00
|
|
|
cnt = &rpz->rpzs->triggers[rpz->num].nsipv6;
|
|
|
|
have = &rpz->rpzs->have.nsipv6;
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (inc) {
|
2015-05-29 11:26:13 +10:00
|
|
|
if (++*cnt == 1U) {
|
2022-03-08 17:13:26 +01:00
|
|
|
*have |= DNS_RPZ_ZBIT(rpz->num);
|
|
|
|
fix_qname_skip_recurse(rpz->rpzs);
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
} else {
|
2015-05-29 11:26:13 +10:00
|
|
|
REQUIRE(*cnt != 0U);
|
|
|
|
if (--*cnt == 0U) {
|
2022-03-08 17:13:26 +01:00
|
|
|
*have &= ~DNS_RPZ_ZBIT(rpz->num);
|
|
|
|
fix_qname_skip_recurse(rpz->rpzs);
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static dns_rpz_cidr_node_t *
|
2013-02-25 12:46:51 -08:00
|
|
|
new_node(dns_rpz_zones_t *rpzs, const dns_rpz_cidr_key_t *ip,
|
|
|
|
dns_rpz_prefix_t prefix, const dns_rpz_cidr_node_t *child) {
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_cidr_node_t *node = NULL;
|
2011-01-13 01:59:28 +00:00
|
|
|
int i, words, wlen;
|
|
|
|
|
2017-07-21 11:52:24 +10:00
|
|
|
node = isc_mem_get(rpzs->mctx, sizeof(*node));
|
2022-03-07 13:55:03 +01:00
|
|
|
*node = (dns_rpz_cidr_node_t){
|
|
|
|
.prefix = prefix,
|
|
|
|
};
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
if (child != NULL) {
|
2017-07-21 11:52:24 +10:00
|
|
|
node->sum = child->sum;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
words = prefix / DNS_RPZ_CIDR_WORD_BITS;
|
|
|
|
wlen = prefix % DNS_RPZ_CIDR_WORD_BITS;
|
2011-01-13 01:59:28 +00:00
|
|
|
i = 0;
|
|
|
|
while (i < words) {
|
2017-07-21 11:52:24 +10:00
|
|
|
node->ip.w[i] = ip->w[i];
|
2011-01-13 01:59:28 +00:00
|
|
|
++i;
|
|
|
|
}
|
|
|
|
if (wlen != 0) {
|
2017-07-21 11:52:24 +10:00
|
|
|
node->ip.w[i] = ip->w[i] & DNS_RPZ_WORD_MASK(wlen);
|
2011-01-13 01:59:28 +00:00
|
|
|
++i;
|
|
|
|
}
|
|
|
|
while (i < DNS_RPZ_CIDR_WORDS) {
|
2017-07-21 11:52:24 +10:00
|
|
|
node->ip.w[i++] = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2017-07-21 11:52:24 +10:00
|
|
|
return (node);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-12-30 15:45:08 +11:00
|
|
|
badname(int level, const dns_name_t *name, const char *str1, const char *str2) {
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* bin/tests/system/rpz/tests.sh looks for "invalid rpz".
|
|
|
|
*/
|
2024-08-13 18:20:26 +02:00
|
|
|
if (level < DNS_RPZ_DEBUG_QUIET && isc_log_wouldlog(level)) {
|
2022-03-07 13:55:03 +01:00
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_name_format(name, namebuf, sizeof(namebuf));
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB, level,
|
2012-05-31 02:03:34 +00:00
|
|
|
"invalid rpz IP address \"%s\"%s%s", namebuf,
|
2013-02-25 12:46:51 -08:00
|
|
|
str1, str2);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert an IP address from radix tree binary (host byte order) to
|
2013-02-25 12:46:51 -08:00
|
|
|
* to its canonical response policy domain name without the origin of the
|
2011-01-13 01:59:28 +00:00
|
|
|
* policy zone.
|
2017-09-11 11:53:42 -07:00
|
|
|
*
|
|
|
|
* Generate a name for an IPv6 address that fits RFC 5952, except that our
|
|
|
|
* reversed format requires that when the length of the consecutive 16-bit
|
|
|
|
* 0 fields are equal (e.g., 1.0.0.1.0.0.db8.2001 corresponding to
|
|
|
|
* 2001:db8:0:0:1:0:0:1), we shorted the last instead of the first
|
|
|
|
* (e.g., 1.0.0.1.zz.db8.2001 corresponding to 2001:db8::1:0:0:1).
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
|
|
|
static isc_result_t
|
2013-02-25 12:46:51 -08:00
|
|
|
ip2name(const dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t tgt_prefix,
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *base_name, dns_name_t *ip_name) {
|
2011-01-13 01:59:28 +00:00
|
|
|
#ifndef INET6_ADDRSTRLEN
|
|
|
|
#define INET6_ADDRSTRLEN 46
|
|
|
|
#endif /* ifndef INET6_ADDRSTRLEN */
|
|
|
|
char str[1 + 8 + 1 + INET6_ADDRSTRLEN + 1];
|
|
|
|
isc_buffer_t buffer;
|
|
|
|
isc_result_t result;
|
2022-03-07 13:55:03 +01:00
|
|
|
int len;
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) {
|
2018-02-15 12:38:22 +11:00
|
|
|
len = snprintf(str, sizeof(str), "%u.%u.%u.%u.%u",
|
|
|
|
tgt_prefix - 96U, tgt_ip->w[3] & 0xffU,
|
|
|
|
(tgt_ip->w[3] >> 8) & 0xffU,
|
|
|
|
(tgt_ip->w[3] >> 16) & 0xffU,
|
|
|
|
(tgt_ip->w[3] >> 24) & 0xffU);
|
2020-03-09 20:51:21 -07:00
|
|
|
if (len < 0 || (size_t)len >= sizeof(str)) {
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_FAILURE);
|
2017-09-11 11:53:42 -07:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
} else {
|
2022-03-07 13:55:03 +01:00
|
|
|
int w[DNS_RPZ_CIDR_WORDS * 2];
|
|
|
|
int best_first, best_len, cur_first, cur_len;
|
|
|
|
|
2017-09-11 11:53:42 -07:00
|
|
|
len = snprintf(str, sizeof(str), "%d", tgt_prefix);
|
2020-03-09 20:51:21 -07:00
|
|
|
if (len < 0 || (size_t)len >= sizeof(str)) {
|
2017-09-11 11:53:42 -07:00
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
for (int n = 0; n < DNS_RPZ_CIDR_WORDS; n++) {
|
|
|
|
w[n * 2 + 1] =
|
|
|
|
((tgt_ip->w[DNS_RPZ_CIDR_WORDS - 1 - n] >> 16) &
|
2011-01-13 01:59:28 +00:00
|
|
|
0xffff);
|
2022-03-07 13:55:03 +01:00
|
|
|
w[n * 2] = tgt_ip->w[DNS_RPZ_CIDR_WORDS - 1 - n] &
|
2011-01-13 01:59:28 +00:00
|
|
|
0xffff;
|
|
|
|
}
|
2017-09-11 11:53:42 -07:00
|
|
|
/*
|
|
|
|
* Find the start and length of the first longest sequence
|
|
|
|
* of zeros in the address.
|
|
|
|
*/
|
|
|
|
best_first = -1;
|
|
|
|
best_len = 0;
|
|
|
|
cur_first = -1;
|
|
|
|
cur_len = 0;
|
2022-03-07 13:55:03 +01:00
|
|
|
for (int n = 0; n <= 7; ++n) {
|
2017-09-11 11:53:42 -07:00
|
|
|
if (w[n] != 0) {
|
|
|
|
cur_len = 0;
|
|
|
|
cur_first = -1;
|
2011-01-13 01:59:28 +00:00
|
|
|
} else {
|
2017-09-11 11:53:42 -07:00
|
|
|
++cur_len;
|
|
|
|
if (cur_first < 0) {
|
|
|
|
cur_first = n;
|
|
|
|
} else if (cur_len >= best_len) {
|
|
|
|
best_first = cur_first;
|
|
|
|
best_len = cur_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
for (int n = 0; n <= 7; ++n) {
|
|
|
|
int i;
|
|
|
|
|
2020-03-09 20:51:21 -07:00
|
|
|
INSIST(len > 0 && (size_t)len < sizeof(str));
|
2017-09-11 11:53:42 -07:00
|
|
|
if (n == best_first) {
|
2020-03-09 20:51:21 -07:00
|
|
|
i = snprintf(str + len, sizeof(str) - len,
|
|
|
|
".zz");
|
2017-09-11 11:53:42 -07:00
|
|
|
n += best_len - 1;
|
|
|
|
} else {
|
2020-03-09 20:51:21 -07:00
|
|
|
i = snprintf(str + len, sizeof(str) - len,
|
|
|
|
".%x", w[n]);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
2020-03-09 20:51:21 -07:00
|
|
|
if (i < 0 || (size_t)i >= (size_t)(sizeof(str) - len)) {
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
len += i;
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-06 17:21:19 -08:00
|
|
|
isc_buffer_init(&buffer, str, sizeof(str));
|
|
|
|
isc_buffer_add(&buffer, len);
|
2013-02-25 12:46:51 -08:00
|
|
|
result = dns_name_fromtext(ip_name, &buffer, base_name, 0, NULL);
|
|
|
|
return (result);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-09-11 11:53:42 -07:00
|
|
|
* Determine the type of a name in a response policy zone.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
|
|
|
static dns_rpz_type_t
|
2017-09-11 11:53:42 -07:00
|
|
|
type_from_name(const dns_rpz_zones_t *rpzs, dns_rpz_zone_t *rpz,
|
|
|
|
const dns_name_t *name) {
|
|
|
|
if (dns_name_issubdomain(name, &rpz->ip)) {
|
2011-01-13 01:59:28 +00:00
|
|
|
return (DNS_RPZ_TYPE_IP);
|
2017-09-11 11:53:42 -07:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2017-09-11 11:53:42 -07:00
|
|
|
if (dns_name_issubdomain(name, &rpz->client_ip)) {
|
2013-07-12 14:46:47 -07:00
|
|
|
return (DNS_RPZ_TYPE_CLIENT_IP);
|
2017-09-11 11:53:42 -07:00
|
|
|
}
|
2013-07-12 14:46:47 -07:00
|
|
|
|
2017-09-11 11:53:42 -07:00
|
|
|
if ((rpzs->p.nsip_on & DNS_RPZ_ZBIT(rpz->num)) != 0 &&
|
|
|
|
dns_name_issubdomain(name, &rpz->nsip))
|
|
|
|
{
|
2011-01-13 01:59:28 +00:00
|
|
|
return (DNS_RPZ_TYPE_NSIP);
|
2017-09-11 11:53:42 -07:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2017-09-11 11:53:42 -07:00
|
|
|
if ((rpzs->p.nsdname_on & DNS_RPZ_ZBIT(rpz->num)) != 0 &&
|
|
|
|
dns_name_issubdomain(name, &rpz->nsdname))
|
|
|
|
{
|
2011-01-13 01:59:28 +00:00
|
|
|
return (DNS_RPZ_TYPE_NSDNAME);
|
2017-09-11 11:53:42 -07:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
return (DNS_RPZ_TYPE_QNAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert an IP address from canonical response policy domain name form
|
2013-02-25 12:46:51 -08:00
|
|
|
* to radix tree binary (host byte order) for adding or deleting IP or NSIP
|
|
|
|
* data.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
|
|
|
static isc_result_t
|
2022-03-08 17:13:26 +01:00
|
|
|
name2ipkey(int log_level, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
|
|
|
|
const dns_name_t *src_name, dns_rpz_cidr_key_t *tgt_ip,
|
|
|
|
dns_rpz_prefix_t *tgt_prefix, dns_rpz_addr_zbits_t *new_set) {
|
2022-03-07 13:55:03 +01:00
|
|
|
char ip_str[DNS_NAME_FORMATSIZE];
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_offsets_t ip_name_offsets;
|
|
|
|
dns_fixedname_t ip_name2f;
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_name_t ip_name;
|
2022-03-08 17:13:26 +01:00
|
|
|
const char *prefix_str = NULL, *cp = NULL, *end = NULL;
|
2011-01-13 01:59:28 +00:00
|
|
|
char *cp2;
|
|
|
|
int ip_labels;
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_rpz_prefix_t prefix;
|
|
|
|
unsigned long prefix_num, l;
|
|
|
|
isc_result_t result;
|
2011-01-13 01:59:28 +00:00
|
|
|
int i;
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
REQUIRE(rpz != NULL);
|
2022-03-08 17:13:26 +01:00
|
|
|
REQUIRE(rpz->rpzs != NULL && rpz->num < rpz->rpzs->p.num_zones);
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2022-03-08 17:13:26 +01:00
|
|
|
make_addr_set(new_set, DNS_RPZ_ZBIT(rpz->num), rpz_type);
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
ip_labels = dns_name_countlabels(src_name);
|
2013-02-25 12:46:51 -08:00
|
|
|
if (rpz_type == DNS_RPZ_TYPE_QNAME) {
|
|
|
|
ip_labels -= dns_name_countlabels(&rpz->origin);
|
|
|
|
} else {
|
|
|
|
ip_labels -= dns_name_countlabels(&rpz->nsdname);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
if (ip_labels < 2) {
|
|
|
|
badname(log_level, src_name, "; too short", "");
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_name_init(&ip_name, ip_name_offsets);
|
|
|
|
dns_name_getlabelsequence(src_name, 0, ip_labels, &ip_name);
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
/*
|
2012-05-31 02:03:34 +00:00
|
|
|
* Get text for the IP address
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_name_format(&ip_name, ip_str, sizeof(ip_str));
|
|
|
|
end = &ip_str[strlen(ip_str) + 1];
|
|
|
|
prefix_str = ip_str;
|
|
|
|
|
|
|
|
prefix_num = strtoul(prefix_str, &cp2, 10);
|
2012-05-31 02:03:34 +00:00
|
|
|
if (*cp2 != '.') {
|
|
|
|
badname(log_level, src_name, "; invalid leading prefix length",
|
|
|
|
"");
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
2018-05-12 08:20:57 +05:30
|
|
|
/*
|
|
|
|
* Patch in trailing nul character to print just the length
|
|
|
|
* label (for various cases below).
|
|
|
|
*/
|
|
|
|
*cp2 = '\0';
|
2013-02-25 12:46:51 -08:00
|
|
|
if (prefix_num < 1U || prefix_num > 128U) {
|
2012-05-31 02:03:34 +00:00
|
|
|
badname(log_level, src_name, "; invalid prefix length of ",
|
|
|
|
prefix_str);
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
cp = cp2 + 1;
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
if (--ip_labels == 4 && !strchr(cp, 'z')) {
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
|
|
|
* Convert an IPv4 address
|
2015-05-21 11:09:29 +05:30
|
|
|
* from the form "prefix.z.y.x.w"
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2013-02-25 12:46:51 -08:00
|
|
|
if (prefix_num > 32U) {
|
|
|
|
badname(log_level, src_name,
|
2012-05-31 02:03:34 +00:00
|
|
|
"; invalid IPv4 prefix length of ", prefix_str);
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
prefix_num += 96;
|
|
|
|
*tgt_prefix = (dns_rpz_prefix_t)prefix_num;
|
2011-01-13 01:59:28 +00:00
|
|
|
tgt_ip->w[0] = 0;
|
|
|
|
tgt_ip->w[1] = 0;
|
|
|
|
tgt_ip->w[2] = ADDR_V4MAPPED;
|
|
|
|
tgt_ip->w[3] = 0;
|
|
|
|
for (i = 0; i < 32; i += 8) {
|
|
|
|
l = strtoul(cp, &cp2, 10);
|
2011-01-13 04:20:03 +00:00
|
|
|
if (l > 255U || (*cp2 != '.' && *cp2 != '\0')) {
|
2012-05-31 02:03:34 +00:00
|
|
|
if (*cp2 == '.') {
|
|
|
|
*cp2 = '\0';
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
badname(log_level, src_name,
|
2012-05-31 02:03:34 +00:00
|
|
|
"; invalid IPv4 octet ", cp);
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
tgt_ip->w[3] |= l << i;
|
|
|
|
cp = cp2 + 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Convert a text IPv6 address.
|
|
|
|
*/
|
2013-02-25 12:46:51 -08:00
|
|
|
*tgt_prefix = (dns_rpz_prefix_t)prefix_num;
|
2011-01-13 01:59:28 +00:00
|
|
|
for (i = 0; ip_labels > 0 && i < DNS_RPZ_CIDR_WORDS * 2;
|
2022-11-02 19:33:14 +01:00
|
|
|
ip_labels--)
|
|
|
|
{
|
2011-01-13 01:59:28 +00:00
|
|
|
if (cp[0] == 'z' && cp[1] == 'z' &&
|
2022-11-02 19:33:14 +01:00
|
|
|
(cp[2] == '.' || cp[2] == '\0') && i <= 6)
|
|
|
|
{
|
2011-01-13 01:59:28 +00:00
|
|
|
do {
|
|
|
|
if ((i & 1) == 0) {
|
|
|
|
tgt_ip->w[3 - i / 2] = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
++i;
|
|
|
|
} while (ip_labels + i <= 8);
|
|
|
|
cp += 3;
|
|
|
|
} else {
|
|
|
|
l = strtoul(cp, &cp2, 16);
|
2011-01-13 04:20:03 +00:00
|
|
|
if (l > 0xffffu ||
|
2022-11-02 19:33:14 +01:00
|
|
|
(*cp2 != '.' && *cp2 != '\0'))
|
|
|
|
{
|
2012-05-31 02:03:34 +00:00
|
|
|
if (*cp2 == '.') {
|
|
|
|
*cp2 = '\0';
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
badname(log_level, src_name,
|
2012-05-31 02:03:34 +00:00
|
|
|
"; invalid IPv6 word ", cp);
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
if ((i & 1) == 0) {
|
|
|
|
tgt_ip->w[3 - i / 2] = l;
|
|
|
|
} else {
|
|
|
|
tgt_ip->w[3 - i / 2] |= l << 16;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
i++;
|
|
|
|
cp = cp2 + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cp != end) {
|
2013-02-25 12:46:51 -08:00
|
|
|
badname(log_level, src_name, "", "");
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for 1s after the prefix length.
|
|
|
|
*/
|
2013-02-25 12:46:51 -08:00
|
|
|
prefix = (dns_rpz_prefix_t)prefix_num;
|
|
|
|
while (prefix < DNS_RPZ_CIDR_KEY_BITS) {
|
2011-01-13 01:59:28 +00:00
|
|
|
dns_rpz_cidr_word_t aword;
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
i = prefix % DNS_RPZ_CIDR_WORD_BITS;
|
|
|
|
aword = tgt_ip->w[prefix / DNS_RPZ_CIDR_WORD_BITS];
|
2011-01-13 01:59:28 +00:00
|
|
|
if ((aword & ~DNS_RPZ_WORD_MASK(i)) != 0) {
|
2013-02-25 12:46:51 -08:00
|
|
|
badname(log_level, src_name,
|
2012-05-31 02:03:34 +00:00
|
|
|
"; too small prefix length of ", prefix_str);
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
prefix -= i;
|
|
|
|
prefix += DNS_RPZ_CIDR_WORD_BITS;
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
2015-05-21 11:09:29 +05:30
|
|
|
/*
|
2017-09-11 11:53:42 -07:00
|
|
|
* Complain about bad names but be generous and accept them.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2024-08-13 18:20:26 +02:00
|
|
|
if (log_level < DNS_RPZ_DEBUG_QUIET && isc_log_wouldlog(log_level)) {
|
2017-09-11 11:53:42 -07:00
|
|
|
/*
|
|
|
|
* Convert the address back to a canonical domain name
|
|
|
|
* to ensure that the original name is in canonical form.
|
|
|
|
*/
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_name_t *ip_name2 = dns_fixedname_initname(&ip_name2f);
|
2017-09-11 11:53:42 -07:00
|
|
|
result = ip2name(tgt_ip, (dns_rpz_prefix_t)prefix_num, NULL,
|
|
|
|
ip_name2);
|
|
|
|
if (result != ISC_R_SUCCESS ||
|
2022-11-02 19:33:14 +01:00
|
|
|
!dns_name_equal(&ip_name, ip_name2))
|
|
|
|
{
|
2022-03-07 13:55:03 +01:00
|
|
|
char ip2_str[DNS_NAME_FORMATSIZE];
|
2017-09-11 11:53:42 -07:00
|
|
|
dns_name_format(ip_name2, ip2_str, sizeof(ip2_str));
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
|
|
|
|
log_level,
|
2017-09-11 11:53:42 -07:00
|
|
|
"rpz IP address \"%s\""
|
|
|
|
" is not the canonical \"%s\"",
|
|
|
|
ip_str, ip2_str);
|
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* Get trigger name and data bits for adding or deleting summary NSDNAME
|
|
|
|
* or QNAME data.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2013-02-25 12:46:51 -08:00
|
|
|
static void
|
2022-03-08 17:13:26 +01:00
|
|
|
name2data(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
|
2013-02-25 12:46:51 -08:00
|
|
|
const dns_name_t *src_name, dns_name_t *trig_name,
|
2023-09-29 21:40:29 -07:00
|
|
|
nmdata_t *new_data) {
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_offsets_t tmp_name_offsets;
|
|
|
|
dns_name_t tmp_name;
|
|
|
|
unsigned int prefix_len, n;
|
|
|
|
|
|
|
|
REQUIRE(rpz != NULL);
|
2022-03-08 17:13:26 +01:00
|
|
|
REQUIRE(rpz->rpzs != NULL && rpz->num < rpz->rpzs->p.num_zones);
|
2013-02-25 12:46:51 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle wildcards by putting only the parent into the
|
2023-09-29 21:40:29 -07:00
|
|
|
* summary database. The database only causes a check of the
|
2013-02-25 12:46:51 -08:00
|
|
|
* real policy zone where wildcards will be handled.
|
|
|
|
*/
|
|
|
|
if (dns_name_iswildcard(src_name)) {
|
|
|
|
prefix_len = 1;
|
2013-07-12 14:46:47 -07:00
|
|
|
memset(&new_data->set, 0, sizeof(new_data->set));
|
2022-03-08 17:13:26 +01:00
|
|
|
make_nm_set(&new_data->wild, rpz->num, rpz_type);
|
2013-02-25 12:46:51 -08:00
|
|
|
} else {
|
|
|
|
prefix_len = 0;
|
2022-03-08 17:13:26 +01:00
|
|
|
make_nm_set(&new_data->set, rpz->num, rpz_type);
|
2013-07-12 14:46:47 -07:00
|
|
|
memset(&new_data->wild, 0, sizeof(new_data->wild));
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
dns_name_init(&tmp_name, tmp_name_offsets);
|
|
|
|
n = dns_name_countlabels(src_name);
|
|
|
|
n -= prefix_len;
|
|
|
|
if (rpz_type == DNS_RPZ_TYPE_QNAME) {
|
|
|
|
n -= dns_name_countlabels(&rpz->origin);
|
|
|
|
} else {
|
|
|
|
n -= dns_name_countlabels(&rpz->nsdname);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_name_getlabelsequence(src_name, prefix_len, n, &tmp_name);
|
|
|
|
(void)dns_name_concatenate(&tmp_name, dns_rootname, trig_name, NULL);
|
|
|
|
}
|
|
|
|
|
2016-07-10 19:46:17 +05:30
|
|
|
#ifndef HAVE_BUILTIN_CLZ
|
|
|
|
/**
|
|
|
|
* \brief Count Leading Zeros: Find the location of the left-most set
|
|
|
|
* bit.
|
2013-02-25 12:46:51 -08:00
|
|
|
*/
|
2021-10-11 13:43:12 +02:00
|
|
|
static unsigned int
|
2016-07-10 19:46:17 +05:30
|
|
|
clz(dns_rpz_cidr_word_t w) {
|
|
|
|
unsigned int bit;
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2011-10-13 01:32:34 +00:00
|
|
|
bit = DNS_RPZ_CIDR_WORD_BITS - 1;
|
2016-07-10 19:46:17 +05:30
|
|
|
|
2011-10-13 01:32:34 +00:00
|
|
|
if ((w & 0xffff0000) != 0) {
|
|
|
|
w >>= 16;
|
|
|
|
bit -= 16;
|
|
|
|
}
|
2016-07-10 19:46:17 +05:30
|
|
|
|
2011-10-13 01:32:34 +00:00
|
|
|
if ((w & 0xff00) != 0) {
|
|
|
|
w >>= 8;
|
|
|
|
bit -= 8;
|
|
|
|
}
|
2016-07-10 19:46:17 +05:30
|
|
|
|
2011-10-13 01:32:34 +00:00
|
|
|
if ((w & 0xf0) != 0) {
|
|
|
|
w >>= 4;
|
|
|
|
bit -= 4;
|
|
|
|
}
|
2016-07-10 19:46:17 +05:30
|
|
|
|
2011-10-13 01:32:34 +00:00
|
|
|
if ((w & 0xc) != 0) {
|
|
|
|
w >>= 2;
|
|
|
|
bit -= 2;
|
|
|
|
}
|
2016-07-10 19:46:17 +05:30
|
|
|
|
2011-10-13 01:32:34 +00:00
|
|
|
if ((w & 2) != 0) {
|
|
|
|
--bit;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-07-10 19:46:17 +05:30
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
return (bit);
|
|
|
|
}
|
2016-07-10 19:46:17 +05:30
|
|
|
#endif /* ifndef HAVE_BUILTIN_CLZ */
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* Find the first differing bit in two keys (IP addresses).
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
|
|
|
static int
|
2013-02-25 12:46:51 -08:00
|
|
|
diff_keys(const dns_rpz_cidr_key_t *key1, dns_rpz_prefix_t prefix1,
|
|
|
|
const dns_rpz_cidr_key_t *key2, dns_rpz_prefix_t prefix2) {
|
2011-01-13 01:59:28 +00:00
|
|
|
dns_rpz_cidr_word_t delta;
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_rpz_prefix_t maxbit, bit;
|
2011-01-13 01:59:28 +00:00
|
|
|
int i;
|
|
|
|
|
2015-02-16 12:09:30 +05:30
|
|
|
bit = 0;
|
2013-02-25 12:46:51 -08:00
|
|
|
maxbit = ISC_MIN(prefix1, prefix2);
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* find the first differing words
|
|
|
|
*/
|
2016-07-10 19:46:17 +05:30
|
|
|
for (i = 0; bit < maxbit; i++, bit += DNS_RPZ_CIDR_WORD_BITS) {
|
2011-01-13 01:59:28 +00:00
|
|
|
delta = key1->w[i] ^ key2->w[i];
|
2021-10-14 10:33:24 +02:00
|
|
|
if (delta != 0) {
|
2016-07-10 19:46:17 +05:30
|
|
|
#ifdef HAVE_BUILTIN_CLZ
|
|
|
|
bit += __builtin_clz(delta);
|
|
|
|
#else /* ifdef HAVE_BUILTIN_CLZ */
|
|
|
|
bit += clz(delta);
|
|
|
|
#endif /* ifdef HAVE_BUILTIN_CLZ */
|
2011-01-13 01:59:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (ISC_MIN(bit, maxbit));
|
|
|
|
}
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* Given a hit while searching the radix trees,
|
|
|
|
* clear all bits for higher numbered zones.
|
|
|
|
*/
|
2021-10-11 13:43:12 +02:00
|
|
|
static dns_rpz_zbits_t
|
2013-02-25 12:46:51 -08:00
|
|
|
trim_zbits(dns_rpz_zbits_t zbits, dns_rpz_zbits_t found) {
|
|
|
|
dns_rpz_zbits_t x;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Isolate the first or smallest numbered hit bit.
|
|
|
|
* Make a mask of that bit and all smaller numbered bits.
|
|
|
|
*/
|
|
|
|
x = zbits & found;
|
2013-03-28 15:37:47 -07:00
|
|
|
x &= (~x + 1);
|
2013-02-25 12:46:51 -08:00
|
|
|
x = (x << 1) - 1;
|
2020-03-25 17:00:07 +01:00
|
|
|
zbits &= x;
|
|
|
|
return (zbits);
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
|
|
|
* Search a radix tree for an IP address for ordinary lookup
|
|
|
|
* or for a CIDR block adding or deleting an entry
|
|
|
|
*
|
2013-02-25 12:46:51 -08:00
|
|
|
* Return ISC_R_SUCCESS, DNS_R_PARTIALMATCH, ISC_R_NOTFOUND,
|
|
|
|
* and *found=longest match node
|
2023-09-29 21:40:29 -07:00
|
|
|
* or with create==true, ISC_R_EXISTS
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
|
|
|
static isc_result_t
|
2013-02-25 12:46:51 -08:00
|
|
|
search(dns_rpz_zones_t *rpzs, const dns_rpz_cidr_key_t *tgt_ip,
|
|
|
|
dns_rpz_prefix_t tgt_prefix, const dns_rpz_addr_zbits_t *tgt_set,
|
|
|
|
bool create, dns_rpz_cidr_node_t **found) {
|
2023-09-29 21:40:29 -07:00
|
|
|
dns_rpz_cidr_node_t *cur = rpzs->cidr;
|
|
|
|
dns_rpz_cidr_node_t *parent = NULL, *child = NULL;
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_cidr_node_t *new_parent = NULL, *sibling = NULL;
|
2023-09-29 21:40:29 -07:00
|
|
|
dns_rpz_addr_zbits_t set = *tgt_set;
|
|
|
|
int cur_num = 0, child_num;
|
|
|
|
isc_result_t find_result = ISC_R_NOTFOUND;
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
*found = NULL;
|
2011-01-13 01:59:28 +00:00
|
|
|
for (;;) {
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_rpz_prefix_t dbit;
|
2011-01-13 01:59:28 +00:00
|
|
|
if (cur == NULL) {
|
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* No child so we cannot go down.
|
|
|
|
* Quit with whatever we already found
|
|
|
|
* or add the target as a child of the current parent.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
|
|
|
if (!create) {
|
|
|
|
return (find_result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
child = new_node(rpzs, tgt_ip, tgt_prefix, NULL);
|
2011-01-13 01:59:28 +00:00
|
|
|
if (parent == NULL) {
|
2013-02-25 12:46:51 -08:00
|
|
|
rpzs->cidr = child;
|
2011-01-13 01:59:28 +00:00
|
|
|
} else {
|
|
|
|
parent->child[cur_num] = child;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
child->parent = parent;
|
2013-07-12 14:46:47 -07:00
|
|
|
child->set.client_ip |= tgt_set->client_ip;
|
|
|
|
child->set.ip |= tgt_set->ip;
|
|
|
|
child->set.nsip |= tgt_set->nsip;
|
2013-02-25 12:46:51 -08:00
|
|
|
set_sum_pair(child);
|
2015-05-21 11:09:29 +05:30
|
|
|
*found = child;
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2013-07-12 14:46:47 -07:00
|
|
|
if ((cur->sum.client_ip & set.client_ip) == 0 &&
|
|
|
|
(cur->sum.ip & set.ip) == 0 &&
|
|
|
|
(cur->sum.nsip & set.nsip) == 0)
|
|
|
|
{
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* This node has no relevant data
|
|
|
|
* and is in none of the target trees.
|
|
|
|
* Pretend it does not exist if we are not adding.
|
|
|
|
*
|
|
|
|
* If we are adding, continue down to eventually add
|
|
|
|
* a node and mark/put this node in the correct tree.
|
|
|
|
*/
|
|
|
|
if (!create) {
|
|
|
|
return (find_result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
dbit = diff_keys(tgt_ip, tgt_prefix, &cur->ip, cur->prefix);
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* dbit <= tgt_prefix and dbit <= cur->prefix always.
|
2011-01-13 01:59:28 +00:00
|
|
|
* We are finished searching if we matched all of the target.
|
|
|
|
*/
|
|
|
|
if (dbit == tgt_prefix) {
|
2013-02-25 12:46:51 -08:00
|
|
|
if (tgt_prefix == cur->prefix) {
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* The node's key matches the target exactly.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2013-07-12 14:46:47 -07:00
|
|
|
if ((cur->set.client_ip & set.client_ip) != 0 ||
|
|
|
|
(cur->set.ip & set.ip) != 0 ||
|
|
|
|
(cur->set.nsip & set.nsip) != 0)
|
|
|
|
{
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* It is the answer if it has data.
|
|
|
|
*/
|
|
|
|
*found = cur;
|
|
|
|
if (create) {
|
|
|
|
find_result = ISC_R_EXISTS;
|
|
|
|
} else {
|
|
|
|
find_result = ISC_R_SUCCESS;
|
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
} else if (create) {
|
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* The node lacked relevant data,
|
|
|
|
* but will have it now.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2017-02-20 11:57:28 +01:00
|
|
|
cur->set.client_ip |=
|
|
|
|
tgt_set->client_ip;
|
2013-07-12 14:46:47 -07:00
|
|
|
cur->set.ip |= tgt_set->ip;
|
|
|
|
cur->set.nsip |= tgt_set->nsip;
|
2013-02-25 12:46:51 -08:00
|
|
|
set_sum_pair(cur);
|
|
|
|
*found = cur;
|
|
|
|
find_result = ISC_R_SUCCESS;
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
return (find_result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* We know tgt_prefix < cur->prefix which means that
|
2011-01-13 01:59:28 +00:00
|
|
|
* the target is shorter than the current node.
|
|
|
|
* Add the target as the current node's parent.
|
|
|
|
*/
|
|
|
|
if (!create) {
|
|
|
|
return (find_result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
new_parent = new_node(rpzs, tgt_ip, tgt_prefix, cur);
|
2011-01-13 01:59:28 +00:00
|
|
|
new_parent->parent = parent;
|
|
|
|
if (parent == NULL) {
|
2013-02-25 12:46:51 -08:00
|
|
|
rpzs->cidr = new_parent;
|
2011-01-13 01:59:28 +00:00
|
|
|
} else {
|
|
|
|
parent->child[cur_num] = new_parent;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-08-15 14:17:02 +05:30
|
|
|
child_num = DNS_RPZ_IP_BIT(&cur->ip, tgt_prefix);
|
2011-01-13 01:59:28 +00:00
|
|
|
new_parent->child[child_num] = cur;
|
|
|
|
cur->parent = new_parent;
|
2013-07-12 14:46:47 -07:00
|
|
|
new_parent->set = *tgt_set;
|
2013-02-25 12:46:51 -08:00
|
|
|
set_sum_pair(new_parent);
|
|
|
|
*found = new_parent;
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
if (dbit == cur->prefix) {
|
2013-07-12 14:46:47 -07:00
|
|
|
if ((cur->set.client_ip & set.client_ip) != 0 ||
|
|
|
|
(cur->set.ip & set.ip) != 0 ||
|
|
|
|
(cur->set.nsip & set.nsip) != 0)
|
|
|
|
{
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* We have a partial match between of all of the
|
|
|
|
* current node but only part of the target.
|
|
|
|
* Continue searching for other hits in the
|
|
|
|
* same or lower numbered trees.
|
|
|
|
*/
|
2011-01-13 01:59:28 +00:00
|
|
|
find_result = DNS_R_PARTIALMATCH;
|
2013-02-25 12:46:51 -08:00
|
|
|
*found = cur;
|
2015-05-21 11:09:29 +05:30
|
|
|
set.client_ip = trim_zbits(set.client_ip,
|
|
|
|
cur->set.client_ip);
|
2013-07-12 14:46:47 -07:00
|
|
|
set.ip = trim_zbits(set.ip, cur->set.ip);
|
|
|
|
set.nsip = trim_zbits(set.nsip, cur->set.nsip);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
parent = cur;
|
|
|
|
cur_num = DNS_RPZ_IP_BIT(tgt_ip, dbit);
|
|
|
|
cur = cur->child[cur_num];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* dbit < tgt_prefix and dbit < cur->prefix,
|
2011-01-13 01:59:28 +00:00
|
|
|
* so we failed to match both the target and the current node.
|
|
|
|
* Insert a fork of a parent above the current node and
|
|
|
|
* add the target as a sibling of the current node
|
|
|
|
*/
|
|
|
|
if (!create) {
|
|
|
|
return (find_result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
sibling = new_node(rpzs, tgt_ip, tgt_prefix, NULL);
|
|
|
|
new_parent = new_node(rpzs, tgt_ip, dbit, cur);
|
2011-01-13 01:59:28 +00:00
|
|
|
new_parent->parent = parent;
|
|
|
|
if (parent == NULL) {
|
2013-02-25 12:46:51 -08:00
|
|
|
rpzs->cidr = new_parent;
|
2011-01-13 01:59:28 +00:00
|
|
|
} else {
|
|
|
|
parent->child[cur_num] = new_parent;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
child_num = DNS_RPZ_IP_BIT(tgt_ip, dbit);
|
|
|
|
new_parent->child[child_num] = sibling;
|
|
|
|
new_parent->child[1 - child_num] = cur;
|
|
|
|
cur->parent = new_parent;
|
|
|
|
sibling->parent = new_parent;
|
2013-07-12 14:46:47 -07:00
|
|
|
sibling->set = *tgt_set;
|
2013-02-25 12:46:51 -08:00
|
|
|
set_sum_pair(sibling);
|
|
|
|
*found = sibling;
|
2011-01-13 01:59:28 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* Add an IP address to the radix tree.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2013-02-25 12:46:51 -08:00
|
|
|
static isc_result_t
|
2022-03-08 17:13:26 +01:00
|
|
|
add_cidr(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *src_name) {
|
2011-01-13 01:59:28 +00:00
|
|
|
dns_rpz_cidr_key_t tgt_ip;
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_rpz_prefix_t tgt_prefix;
|
2013-07-12 14:46:47 -07:00
|
|
|
dns_rpz_addr_zbits_t set;
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_cidr_node_t *found = NULL;
|
2013-02-25 12:46:51 -08:00
|
|
|
isc_result_t result;
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2022-03-08 17:13:26 +01:00
|
|
|
result = name2ipkey(DNS_RPZ_ERROR_LEVEL, rpz, rpz_type, src_name,
|
|
|
|
&tgt_ip, &tgt_prefix, &set);
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* Log complaints about bad owner names but let the zone load.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2012-05-31 02:03:34 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2013-02-25 12:46:51 -08:00
|
|
|
return (ISC_R_SUCCESS);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2023-09-30 13:23:51 -07:00
|
|
|
RWLOCK(&rpz->rpzs->search_lock, isc_rwlocktype_write);
|
2022-03-08 17:13:26 +01:00
|
|
|
result = search(rpz->rpzs, &tgt_ip, tgt_prefix, &set, true, &found);
|
2013-02-25 12:46:51 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2014-06-11 20:00:19 -07:00
|
|
|
/*
|
|
|
|
* Do not worry if the radix tree already exists,
|
|
|
|
* because diff_apply() likes to add nodes before deleting.
|
|
|
|
*/
|
|
|
|
if (result == ISC_R_EXISTS) {
|
2023-09-30 13:23:51 -07:00
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
goto done;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-06-11 20:00:19 -07:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* bin/tests/system/rpz/tests.sh looks for "rpz.*failed".
|
|
|
|
*/
|
|
|
|
dns_name_format(src_name, namebuf, sizeof(namebuf));
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
|
|
|
|
DNS_RPZ_ERROR_LEVEL,
|
2013-02-25 12:46:51 -08:00
|
|
|
"rpz add_cidr(%s) failed: %s", namebuf,
|
|
|
|
isc_result_totext(result));
|
2023-09-30 13:23:51 -07:00
|
|
|
goto done;
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2022-03-08 17:13:26 +01:00
|
|
|
adj_trigger_cnt(rpz, rpz_type, &tgt_ip, tgt_prefix, true);
|
2023-09-30 13:23:51 -07:00
|
|
|
done:
|
|
|
|
RWUNLOCK(&rpz->rpzs->search_lock, isc_rwlocktype_write);
|
2013-02-25 12:46:51 -08:00
|
|
|
return (result);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
static nmdata_t *
|
|
|
|
new_nmdata(isc_mem_t *mctx, const dns_name_t *name, const nmdata_t *data) {
|
|
|
|
nmdata_t *newdata = isc_mem_get(mctx, sizeof(*newdata));
|
|
|
|
*newdata = (nmdata_t){
|
|
|
|
.set = data->set,
|
|
|
|
.wild = data->wild,
|
2024-03-11 22:10:41 -07:00
|
|
|
.name = DNS_NAME_INITEMPTY,
|
2023-09-29 21:40:29 -07:00
|
|
|
.references = ISC_REFCOUNT_INITIALIZER(1),
|
|
|
|
};
|
2024-03-11 22:10:41 -07:00
|
|
|
dns_name_dupwithoffsets(name, mctx, &newdata->name);
|
2023-09-29 21:40:29 -07:00
|
|
|
isc_mem_attach(mctx, &newdata->mctx);
|
|
|
|
|
|
|
|
#ifdef DNS_RPZ_TRACE
|
|
|
|
fprintf(stderr, "new_nmdata:%s:%s:%d:%p->references = 1\n", __func__,
|
|
|
|
__FILE__, __LINE__ + 1, name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return (newdata);
|
|
|
|
}
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
static isc_result_t
|
2023-09-29 21:40:29 -07:00
|
|
|
add_nm(dns_rpz_zones_t *rpzs, dns_name_t *trig_name, const nmdata_t *new_data) {
|
2012-05-31 02:03:34 +00:00
|
|
|
isc_result_t result;
|
2023-09-29 21:40:29 -07:00
|
|
|
nmdata_t *data = NULL;
|
|
|
|
dns_qp_t *qp = NULL;
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
dns_qpmulti_write(rpzs->table, &qp);
|
|
|
|
result = dns_qp_getname(qp, trig_name, (void **)&data, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
INSIST(data == NULL);
|
|
|
|
data = new_nmdata(rpzs->mctx, trig_name, new_data);
|
|
|
|
result = dns_qp_insert(qp, data, 0);
|
|
|
|
nmdata_detach(&data);
|
|
|
|
goto done;
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* Do not count bits that are already present
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2023-09-29 21:40:29 -07:00
|
|
|
if ((data->set.qname & new_data->set.qname) != 0 ||
|
|
|
|
(data->set.ns & new_data->set.ns) != 0 ||
|
|
|
|
(data->wild.qname & new_data->wild.qname) != 0 ||
|
|
|
|
(data->wild.ns & new_data->wild.ns) != 0)
|
2014-06-11 20:00:19 -07:00
|
|
|
{
|
2023-09-29 21:40:29 -07:00
|
|
|
result = ISC_R_EXISTS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
/* copy in the bits from the new data */
|
|
|
|
data->set.qname |= new_data->set.qname;
|
|
|
|
data->set.ns |= new_data->set.ns;
|
|
|
|
data->wild.qname |= new_data->wild.qname;
|
|
|
|
data->wild.ns |= new_data->wild.ns;
|
|
|
|
|
|
|
|
done:
|
|
|
|
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
|
|
|
dns_qpmulti_commit(rpzs->table, &qp);
|
|
|
|
|
|
|
|
return (result);
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2022-03-08 17:13:26 +01:00
|
|
|
add_name(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *src_name) {
|
2023-09-29 21:40:29 -07:00
|
|
|
nmdata_t new_data;
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_fixedname_t trig_namef;
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_name_t *trig_name = NULL;
|
2013-02-25 12:46:51 -08:00
|
|
|
isc_result_t result;
|
|
|
|
|
2014-06-11 20:00:19 -07:00
|
|
|
/*
|
2015-08-18 19:39:53 +05:30
|
|
|
* We need a summary database of names even with 1 policy zone,
|
|
|
|
* because wildcard triggers are handled differently.
|
2014-06-11 20:00:19 -07:00
|
|
|
*/
|
|
|
|
|
2018-03-28 14:38:09 +02:00
|
|
|
trig_name = dns_fixedname_initname(&trig_namef);
|
2022-03-08 17:13:26 +01:00
|
|
|
name2data(rpz, rpz_type, src_name, trig_name, &new_data);
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2022-03-08 17:13:26 +01:00
|
|
|
result = add_nm(rpz->rpzs, trig_name, &new_data);
|
2014-06-11 20:00:19 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not worry if the node already exists,
|
|
|
|
* because diff_apply() likes to add nodes before deleting.
|
|
|
|
*/
|
|
|
|
if (result == ISC_R_EXISTS) {
|
|
|
|
return (ISC_R_SUCCESS);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2023-09-30 13:23:51 -07:00
|
|
|
RWLOCK(&rpz->rpzs->search_lock, isc_rwlocktype_write);
|
2022-03-08 17:13:26 +01:00
|
|
|
adj_trigger_cnt(rpz, rpz_type, NULL, 0, true);
|
2023-09-30 13:23:51 -07:00
|
|
|
RWUNLOCK(&rpz->rpzs->search_lock, isc_rwlocktype_write);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-09-11 11:53:42 -07:00
|
|
|
* Get ready for a new set of policy zones for a view.
|
2013-02-25 12:46:51 -08:00
|
|
|
*/
|
|
|
|
isc_result_t
|
2023-09-29 21:40:29 -07:00
|
|
|
dns_rpz_new_zones(dns_view_t *view, isc_loopmgr_t *loopmgr, char *rps_cstr,
|
2022-10-05 11:21:28 +02:00
|
|
|
size_t rps_cstr_size, dns_rpz_zones_t **rpzsp) {
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_zones_t *rpzs = NULL;
|
2023-09-29 21:40:29 -07:00
|
|
|
isc_mem_t *mctx = NULL;
|
|
|
|
#ifdef USE_DNSRPS
|
2021-02-01 15:59:41 +11:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
2023-09-29 21:40:29 -07:00
|
|
|
#endif
|
2013-02-25 12:46:51 -08:00
|
|
|
|
|
|
|
REQUIRE(rpzsp != NULL && *rpzsp == NULL);
|
2023-09-29 21:40:29 -07:00
|
|
|
REQUIRE(view != NULL);
|
|
|
|
|
|
|
|
mctx = view->mctx;
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
rpzs = isc_mem_get(mctx, sizeof(*rpzs));
|
|
|
|
*rpzs = (dns_rpz_zones_t){
|
|
|
|
.rps_cstr = rps_cstr,
|
|
|
|
.rps_cstr_size = rps_cstr_size,
|
2022-07-26 13:03:40 +02:00
|
|
|
.loopmgr = loopmgr,
|
2022-10-05 11:21:28 +02:00
|
|
|
.magic = DNS_RPZ_ZONES_MAGIC,
|
2022-03-07 13:55:03 +01:00
|
|
|
};
|
2013-02-25 12:46:51 -08:00
|
|
|
|
Add the reader-writer synchronization with modified C-RW-WP
This changes the internal isc_rwlock implementation to:
Irina Calciu, Dave Dice, Yossi Lev, Victor Luchangco, Virendra
J. Marathe, and Nir Shavit. 2013. NUMA-aware reader-writer locks.
SIGPLAN Not. 48, 8 (August 2013), 157–166.
DOI:https://doi.org/10.1145/2517327.24425
(The full article available from:
http://mcg.cs.tau.ac.il/papers/ppopp2013-rwlocks.pdf)
The implementation is based on the The Writer-Preference Lock (C-RW-WP)
variant (see the 3.4 section of the paper for the rationale).
The implemented algorithm has been modified for simplicity and for usage
patterns in rbtdb.c.
The changes compared to the original algorithm:
* We haven't implemented the cohort locks because that would require a
knowledge of NUMA nodes, instead a simple atomic_bool is used as
synchronization point for writer lock.
* The per-thread reader counters are not being used - this would
require the internal thread id (isc_tid_v) to be always initialized,
even in the utilities; the change has a slight performance penalty,
so we might revisit this change in the future. However, this change
also saves a lot of memory, because cache-line aligned counters were
used, so on 32-core machine, the rwlock would be 4096+ bytes big.
* The readers use a writer_barrier that will raise after a while when
readers lock can't be acquired to prevent readers starvation.
* Separate ingress and egress readers counters queues to reduce both
inter and intra-thread contention.
2021-03-24 17:52:56 +01:00
|
|
|
isc_rwlock_init(&rpzs->search_lock);
|
2022-03-07 13:55:03 +01:00
|
|
|
isc_mutex_init(&rpzs->maint_lock);
|
2022-10-05 11:21:28 +02:00
|
|
|
isc_refcount_init(&rpzs->references, 1);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2017-09-11 11:53:42 -07:00
|
|
|
#ifdef USE_DNSRPS
|
|
|
|
if (rps_cstr != NULL) {
|
2022-03-07 13:55:03 +01:00
|
|
|
result = dns_dnsrps_view_init(rpzs, rps_cstr);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2023-09-29 21:40:29 -07:00
|
|
|
goto cleanup;
|
2022-03-07 13:55:03 +01:00
|
|
|
}
|
2017-09-11 11:53:42 -07:00
|
|
|
}
|
|
|
|
#else /* ifdef USE_DNSRPS */
|
2022-03-07 13:55:03 +01:00
|
|
|
INSIST(!rpzs->p.dnsrps_enabled);
|
2017-09-11 11:53:42 -07:00
|
|
|
#endif /* ifdef USE_DNSRPS */
|
2022-03-07 13:55:03 +01:00
|
|
|
if (!rpzs->p.dnsrps_enabled) {
|
2023-09-29 21:40:29 -07:00
|
|
|
dns_qpmulti_create(mctx, &qpmethods, view, &rpzs->table);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
isc_mem_attach(mctx, &rpzs->mctx);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
*rpzsp = rpzs;
|
2017-02-20 11:57:28 +01:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
#ifdef USE_DNSRPS
|
|
|
|
/* Only if DNSRPS is in use can this function fail */
|
|
|
|
cleanup:
|
2022-10-05 11:21:28 +02:00
|
|
|
isc_refcount_decrementz(&rpzs->references);
|
|
|
|
isc_refcount_destroy(&rpzs->references);
|
2022-03-07 13:55:03 +01:00
|
|
|
isc_mutex_destroy(&rpzs->maint_lock);
|
|
|
|
isc_rwlock_destroy(&rpzs->search_lock);
|
|
|
|
isc_mem_put(mctx, rpzs, sizeof(*rpzs));
|
2017-02-20 11:57:28 +01:00
|
|
|
|
|
|
|
return (result);
|
2023-09-29 21:40:29 -07:00
|
|
|
#endif /* ifdef USE_DNSRPS */
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) {
|
2022-10-05 11:21:28 +02:00
|
|
|
isc_result_t result;
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_zone_t *rpz = NULL;
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
REQUIRE(DNS_RPZ_ZONES_VALID(rpzs));
|
2017-02-20 11:57:28 +01:00
|
|
|
REQUIRE(rpzp != NULL && *rpzp == NULL);
|
2022-10-05 11:21:28 +02:00
|
|
|
|
2017-02-20 11:57:28 +01:00
|
|
|
if (rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
|
|
|
|
return (ISC_R_NOSPACE);
|
|
|
|
}
|
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
result = dns__rpz_shuttingdown(rpzs);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
rpz = isc_mem_get(rpzs->mctx, sizeof(*rpz));
|
|
|
|
*rpz = (dns_rpz_zone_t){
|
|
|
|
.addsoa = true,
|
2022-10-05 11:21:28 +02:00
|
|
|
.magic = DNS_RPZ_ZONE_MAGIC,
|
|
|
|
.rpzs = rpzs,
|
2022-03-07 13:55:03 +01:00
|
|
|
};
|
2017-02-20 11:57:28 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This will never be used, but costs us nothing and
|
2022-03-07 13:55:03 +01:00
|
|
|
* simplifies update_from_db().
|
2017-02-20 11:57:28 +01:00
|
|
|
*/
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
isc_ht_init(&rpz->nodes, rpzs->mctx, 1, ISC_HT_CASE_SENSITIVE);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_name_init(&rpz->origin, NULL);
|
|
|
|
dns_name_init(&rpz->client_ip, NULL);
|
|
|
|
dns_name_init(&rpz->ip, NULL);
|
|
|
|
dns_name_init(&rpz->nsdname, NULL);
|
|
|
|
dns_name_init(&rpz->nsip, NULL);
|
|
|
|
dns_name_init(&rpz->passthru, NULL);
|
|
|
|
dns_name_init(&rpz->drop, NULL);
|
|
|
|
dns_name_init(&rpz->tcp_only, NULL);
|
|
|
|
dns_name_init(&rpz->cname, NULL);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
isc_time_settoepoch(&rpz->lastupdated);
|
|
|
|
|
|
|
|
rpz->num = rpzs->p.num_zones++;
|
|
|
|
rpzs->zones[rpz->num] = rpz;
|
|
|
|
|
|
|
|
*rpzp = rpz;
|
2017-02-20 11:57:28 +01:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg) {
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)fn_arg;
|
2017-02-20 11:57:28 +01:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
REQUIRE(DNS_DB_VALID(db));
|
2022-10-05 11:21:28 +02:00
|
|
|
REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
LOCK(&rpz->rpzs->maint_lock);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
if (rpz->rpzs->shuttingdown) {
|
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
2017-02-20 11:57:28 +01:00
|
|
|
/* New zone came as AXFR */
|
2022-03-07 13:55:03 +01:00
|
|
|
if (rpz->db != NULL && rpz->db != db) {
|
2017-02-20 11:57:28 +01:00
|
|
|
/* We need to clean up the old DB */
|
2022-03-07 13:55:03 +01:00
|
|
|
if (rpz->dbversion != NULL) {
|
|
|
|
dns_db_closeversion(rpz->db, &rpz->dbversion, false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_db_updatenotify_unregister(rpz->db,
|
|
|
|
dns_rpz_dbupdate_callback, rpz);
|
|
|
|
dns_db_detach(&rpz->db);
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
if (rpz->db == NULL) {
|
|
|
|
RUNTIME_CHECK(rpz->dbversion == NULL);
|
|
|
|
dns_db_attach(db, &rpz->db);
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
if (!rpz->updatepending && !rpz->updaterunning) {
|
|
|
|
rpz->updatepending = true;
|
2022-03-07 13:55:03 +01:00
|
|
|
|
2022-07-26 13:03:40 +02:00
|
|
|
dns_db_currentversion(rpz->db, &rpz->dbversion);
|
2022-10-05 11:21:28 +02:00
|
|
|
dns__rpz_timer_start(rpz);
|
2017-02-20 11:57:28 +01:00
|
|
|
} else {
|
2022-09-12 16:36:24 +02:00
|
|
|
char dname[DNS_NAME_FORMATSIZE];
|
2022-03-07 13:55:03 +01:00
|
|
|
rpz->updatepending = true;
|
2022-09-12 16:36:24 +02:00
|
|
|
|
|
|
|
dns_name_format(&rpz->origin, dname, DNS_NAME_FORMATSIZE);
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
|
|
|
|
ISC_LOG_DEBUG(3),
|
2019-08-28 13:11:35 -07:00
|
|
|
"rpz: %s: update already queued or running",
|
|
|
|
dname);
|
2022-03-07 13:55:03 +01:00
|
|
|
if (rpz->dbversion != NULL) {
|
|
|
|
dns_db_closeversion(rpz->db, &rpz->dbversion, false);
|
2019-08-28 13:11:35 -07:00
|
|
|
}
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_db_currentversion(rpz->db, &rpz->dbversion);
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
2022-10-05 11:21:28 +02:00
|
|
|
|
|
|
|
unlock:
|
2022-03-07 13:55:03 +01:00
|
|
|
UNLOCK(&rpz->rpzs->maint_lock);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2023-07-10 11:36:19 +02:00
|
|
|
void
|
|
|
|
dns_rpz_dbupdate_unregister(dns_db_t *db, dns_rpz_zone_t *rpz) {
|
|
|
|
REQUIRE(DNS_DB_VALID(db));
|
|
|
|
REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
|
|
|
|
|
|
|
|
dns_db_updatenotify_unregister(db, dns_rpz_dbupdate_callback, rpz);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_rpz_dbupdate_register(dns_db_t *db, dns_rpz_zone_t *rpz) {
|
|
|
|
REQUIRE(DNS_DB_VALID(db));
|
|
|
|
REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
|
|
|
|
|
|
|
|
dns_db_updatenotify_register(db, dns_rpz_dbupdate_callback, rpz);
|
|
|
|
}
|
2022-09-12 16:36:24 +02:00
|
|
|
static void
|
2022-10-05 11:21:28 +02:00
|
|
|
dns__rpz_timer_start(dns_rpz_zone_t *rpz) {
|
2022-09-12 16:36:24 +02:00
|
|
|
uint64_t tdiff;
|
|
|
|
isc_interval_t interval;
|
|
|
|
isc_time_t now;
|
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
|
|
|
|
|
2023-03-31 00:12:33 +02:00
|
|
|
now = isc_time_now();
|
2022-09-12 16:36:24 +02:00
|
|
|
tdiff = isc_time_microdiff(&now, &rpz->lastupdated) / 1000000;
|
|
|
|
if (tdiff < rpz->min_update_interval) {
|
|
|
|
uint64_t defer = rpz->min_update_interval - tdiff;
|
|
|
|
char dname[DNS_NAME_FORMATSIZE];
|
|
|
|
|
|
|
|
dns_name_format(&rpz->origin, dname, DNS_NAME_FORMATSIZE);
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
|
|
|
|
ISC_LOG_INFO,
|
2022-09-12 16:36:24 +02:00
|
|
|
"rpz: %s: new zone version came "
|
|
|
|
"too soon, deferring update for "
|
|
|
|
"%" PRIu64 " seconds",
|
|
|
|
dname, defer);
|
|
|
|
isc_interval_set(&interval, (unsigned int)defer, 0);
|
|
|
|
} else {
|
|
|
|
isc_interval_set(&interval, 0, 0);
|
|
|
|
}
|
|
|
|
|
2024-03-26 00:13:45 -07:00
|
|
|
rpz->loop = isc_loop();
|
2022-10-05 11:21:28 +02:00
|
|
|
|
|
|
|
isc_timer_create(rpz->loop, dns__rpz_timer_cb, rpz, &rpz->updatetimer);
|
2022-09-12 16:36:24 +02:00
|
|
|
isc_timer_start(rpz->updatetimer, isc_timertype_once, &interval);
|
|
|
|
}
|
|
|
|
|
2017-02-20 11:57:28 +01:00
|
|
|
static void
|
2022-10-05 11:21:28 +02:00
|
|
|
dns__rpz_timer_stop(void *arg) {
|
|
|
|
dns_rpz_zone_t *rpz = arg;
|
|
|
|
REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
|
2022-03-08 17:13:26 +01:00
|
|
|
|
2022-07-26 13:03:40 +02:00
|
|
|
isc_timer_stop(rpz->updatetimer);
|
2022-09-12 16:36:24 +02:00
|
|
|
isc_timer_destroy(&rpz->updatetimer);
|
2022-10-05 11:21:28 +02:00
|
|
|
rpz->loop = NULL;
|
|
|
|
|
2023-09-29 16:16:49 -07:00
|
|
|
dns_rpz_zones_unref(rpz->rpzs);
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 15:04:20 -07:00
|
|
|
static void
|
2022-07-26 13:03:40 +02:00
|
|
|
update_rpz_done_cb(void *data) {
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)data;
|
|
|
|
char dname[DNS_NAME_FORMATSIZE];
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
|
|
|
|
|
2020-04-21 10:42:23 -07:00
|
|
|
LOCK(&rpz->rpzs->maint_lock);
|
2022-03-07 13:55:03 +01:00
|
|
|
rpz->updaterunning = false;
|
2020-04-21 10:42:23 -07:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_name_format(&rpz->origin, dname, DNS_NAME_FORMATSIZE);
|
2020-04-21 10:42:23 -07:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
if (rpz->updatepending && !rpz->rpzs->shuttingdown) {
|
|
|
|
/* Restart the timer */
|
|
|
|
dns__rpz_timer_start(rpz);
|
2020-03-31 15:04:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
dns_db_closeversion(rpz->updb, &rpz->updbversion, false);
|
|
|
|
dns_db_detach(&rpz->updb);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
UNLOCK(&rpz->rpzs->maint_lock);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
|
2022-03-07 13:55:03 +01:00
|
|
|
ISC_LOG_INFO, "rpz: %s: reload done: %s", dname,
|
2022-07-26 13:03:40 +02:00
|
|
|
isc_result_totext(rpz->updateresult));
|
|
|
|
|
2023-09-29 16:16:49 -07:00
|
|
|
dns_rpz_zones_unref(rpz->rpzs);
|
2022-03-07 13:55:03 +01:00
|
|
|
}
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
static isc_result_t
|
|
|
|
update_nodes(dns_rpz_zone_t *rpz, isc_ht_t *newnodes) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_dbiterator_t *updbit = NULL;
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
dns_fixedname_t fixname;
|
|
|
|
char domain[DNS_NAME_FORMATSIZE];
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_name_format(&rpz->origin, domain, DNS_NAME_FORMATSIZE);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2018-03-28 14:38:09 +02:00
|
|
|
name = dns_fixedname_initname(&fixname);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
result = dns_db_createiterator(rpz->updb, DNS_DB_NONSEC3, &updbit);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
|
|
|
|
ISC_LOG_ERROR,
|
2022-03-07 13:55:03 +01:00
|
|
|
"rpz: %s: failed to create DB iterator - %s",
|
|
|
|
domain, isc_result_totext(result));
|
2023-01-03 13:34:58 +00:00
|
|
|
return (result);
|
2022-03-07 13:55:03 +01:00
|
|
|
}
|
2020-04-21 10:42:23 -07:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
result = dns_dbiterator_first(updbit);
|
|
|
|
if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
|
|
|
|
ISC_LOG_ERROR,
|
2022-03-07 13:55:03 +01:00
|
|
|
"rpz: %s: failed to get db iterator - %s", domain,
|
|
|
|
isc_result_totext(result));
|
2020-04-21 10:42:23 -07:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
while (result == ISC_R_SUCCESS) {
|
2017-02-20 11:57:28 +01:00
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
|
|
dns_rdatasetiter_t *rdsiter = NULL;
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_dbnode_t *node = NULL;
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
result = dns__rpz_shuttingdown(rpz->rpzs);
|
2022-03-07 13:55:03 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = dns_dbiterator_current(updbit, &node, name);
|
2017-02-20 11:57:28 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL,
|
2017-02-20 11:57:28 +01:00
|
|
|
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
|
|
|
|
"rpz: %s: failed to get dbiterator - %s",
|
|
|
|
domain, isc_result_totext(result));
|
2022-03-07 13:55:03 +01:00
|
|
|
goto cleanup;
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
result = dns_dbiterator_pause(updbit);
|
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
|
|
|
|
2017-12-06 21:00:14 +11:00
|
|
|
result = dns_db_allrdatasets(rpz->updb, node, rpz->updbversion,
|
2022-11-16 10:47:40 +11:00
|
|
|
0, 0, &rdsiter);
|
2017-02-20 11:57:28 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL,
|
2017-02-20 11:57:28 +01:00
|
|
|
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
|
|
|
|
"rpz: %s: failed to fetch "
|
|
|
|
"rrdatasets - %s",
|
|
|
|
domain, isc_result_totext(result));
|
|
|
|
dns_db_detachnode(rpz->updb, &node);
|
2022-03-07 13:55:03 +01:00
|
|
|
goto cleanup;
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
result = dns_rdatasetiter_first(rdsiter);
|
2022-03-07 13:55:03 +01:00
|
|
|
|
2017-02-20 11:57:28 +01:00
|
|
|
dns_rdatasetiter_destroy(&rdsiter);
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_db_detachnode(rpz->updb, &node);
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS) { /* skip empty non-terminal */
|
2017-02-20 11:57:28 +01:00
|
|
|
if (result != ISC_R_NOMORE) {
|
|
|
|
isc_log_write(
|
2024-08-13 18:20:26 +02:00
|
|
|
DNS_LOGCATEGORY_GENERAL,
|
2017-02-20 11:57:28 +01:00
|
|
|
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
|
|
|
|
"rpz: %s: error %s while creating "
|
|
|
|
"rdatasetiter",
|
|
|
|
domain, isc_result_totext(result));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2022-03-07 13:55:03 +01:00
|
|
|
goto next;
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
Fix updating summary RPZ DB for mixed-case RPZs
Each dns_rpz_zone_t structure keeps a hash table of the names this RPZ
database contains. Here is what happens when an RPZ is updated:
- a new hash table is prepared for the new version of the RPZ by
iterating over it; each name found is added to the summary RPZ
database,
- every name added to the new hash table is searched for in the old
hash table; if found, it is removed from the old hash table,
- the old hash table is iterated over; all names found in it are
removed from the summary RPZ database (because at that point the old
hash table should only contain names which are not present in the
new version of the RPZ),
- the new hash table replaces the old hash table.
When the new version of the RPZ is iterated over, if a given name is
spelled using a different letter case than in the old version of the
RPZ, the new variant will hash to a different value than the old
variant, which means it will not be removed from the old hash table.
When the old hash table is subsequently iterated over to remove
seemingly deleted names, the old variant of the name will still be
there, causing the name to be deleted from the summary RPZ database
(which effectively causes a given rule to be ignored).
The issue can be triggered not just by altering the case of existing
names in an RPZ, but also by adding sibling names spelled with a
different letter case. This is because RBT code preserves case when
node splitting occurs. The end result is that when the RPZ is iterated
over, a given name may be using a different case than in the zone file
(or XFR contents).
Fix by downcasing all names found in the RPZ database before adding them
to the summary RPZ database.
2020-09-21 09:28:36 +02:00
|
|
|
dns_name_downcase(name, name, NULL);
|
2022-03-07 13:55:03 +01:00
|
|
|
|
|
|
|
/* Add entry to the new nodes table */
|
|
|
|
result = isc_ht_add(newnodes, name->ndata, name->length, rpz);
|
2017-02-20 11:57:28 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_name_format(name, namebuf, sizeof(namebuf));
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL,
|
2017-02-20 11:57:28 +01:00
|
|
|
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
|
|
|
|
"rpz: %s, adding node %s to HT error %s",
|
|
|
|
domain, namebuf,
|
|
|
|
isc_result_totext(result));
|
2022-03-07 13:55:03 +01:00
|
|
|
goto next;
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
/* Does the entry exist in the old nodes table? */
|
2017-02-20 11:57:28 +01:00
|
|
|
result = isc_ht_find(rpz->nodes, name->ndata, name->length,
|
|
|
|
NULL);
|
2022-03-07 13:55:03 +01:00
|
|
|
if (result == ISC_R_SUCCESS) { /* found */
|
2017-02-20 11:57:28 +01:00
|
|
|
isc_ht_delete(rpz->nodes, name->ndata, name->length);
|
2022-03-07 13:55:03 +01:00
|
|
|
goto next;
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-03-07 13:55:03 +01:00
|
|
|
* Only the single rpz updates are serialized, so we need to
|
|
|
|
* lock here because we can be processing more updates to
|
|
|
|
* different rpz zones at the same time
|
2017-02-20 11:57:28 +01:00
|
|
|
*/
|
2022-03-07 13:55:03 +01:00
|
|
|
LOCK(&rpz->rpzs->maint_lock);
|
|
|
|
result = rpz_add(rpz, name);
|
2020-04-21 10:42:23 -07:00
|
|
|
UNLOCK(&rpz->rpzs->maint_lock);
|
2020-03-31 15:04:20 -07:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_name_format(name, namebuf, sizeof(namebuf));
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL,
|
2022-03-07 13:55:03 +01:00
|
|
|
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
|
|
|
|
"rpz: %s: adding node %s "
|
|
|
|
"to RPZ error %s",
|
|
|
|
domain, namebuf,
|
|
|
|
isc_result_totext(result));
|
2024-08-13 18:20:26 +02:00
|
|
|
} else if (isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_name_format(name, namebuf, sizeof(namebuf));
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL,
|
2022-03-07 13:55:03 +01:00
|
|
|
DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
|
|
|
|
"rpz: %s: adding node %s", domain,
|
|
|
|
namebuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
next:
|
|
|
|
result = dns_dbiterator_next(updbit);
|
|
|
|
}
|
|
|
|
INSIST(result != ISC_R_SUCCESS);
|
|
|
|
if (result == ISC_R_NOMORE) {
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
dns_dbiterator_destroy(&updbit);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
cleanup_nodes(dns_rpz_zone_t *rpz) {
|
|
|
|
isc_result_t result;
|
|
|
|
isc_ht_iter_t *iter = NULL;
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
dns_fixedname_t fixname;
|
|
|
|
|
|
|
|
name = dns_fixedname_initname(&fixname);
|
|
|
|
|
|
|
|
isc_ht_iter_create(rpz->nodes, &iter);
|
|
|
|
|
|
|
|
for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
|
|
|
|
result = isc_ht_iter_delcurrent_next(iter))
|
|
|
|
{
|
|
|
|
isc_region_t region;
|
|
|
|
unsigned char *key = NULL;
|
|
|
|
size_t keysize;
|
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
result = dns__rpz_shuttingdown(rpz->rpzs);
|
2022-03-07 13:55:03 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_ht_iter_currentkey(iter, &key, &keysize);
|
|
|
|
region.base = key;
|
|
|
|
region.length = (unsigned int)keysize;
|
|
|
|
dns_name_fromregion(name, ®ion);
|
|
|
|
|
|
|
|
LOCK(&rpz->rpzs->maint_lock);
|
|
|
|
rpz_del(rpz, name);
|
2020-04-21 10:42:23 -07:00
|
|
|
UNLOCK(&rpz->rpzs->maint_lock);
|
2022-03-07 13:55:03 +01:00
|
|
|
}
|
|
|
|
INSIST(result != ISC_R_SUCCESS);
|
|
|
|
if (result == ISC_R_NOMORE) {
|
|
|
|
result = ISC_R_SUCCESS;
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
isc_ht_iter_destroy(&iter);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2022-10-05 11:21:28 +02:00
|
|
|
dns__rpz_shuttingdown(dns_rpz_zones_t *rpzs) {
|
2022-03-07 13:55:03 +01:00
|
|
|
bool shuttingdown = false;
|
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
LOCK(&rpzs->maint_lock);
|
|
|
|
shuttingdown = rpzs->shuttingdown;
|
|
|
|
UNLOCK(&rpzs->maint_lock);
|
2020-04-21 10:42:23 -07:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
if (shuttingdown) {
|
|
|
|
return (ISC_R_SHUTTINGDOWN);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2022-03-07 13:55:03 +01:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_rpz_cb(void *data) {
|
|
|
|
dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)data;
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
isc_ht_t *newnodes = NULL;
|
|
|
|
|
|
|
|
REQUIRE(rpz->nodes != NULL);
|
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
result = dns__rpz_shuttingdown(rpz->rpzs);
|
2022-03-07 13:55:03 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2023-01-03 13:21:34 +00:00
|
|
|
goto shuttingdown;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2022-03-07 13:55:03 +01:00
|
|
|
|
|
|
|
isc_ht_init(&newnodes, rpz->rpzs->mctx, 1, ISC_HT_CASE_SENSITIVE);
|
|
|
|
|
|
|
|
result = update_nodes(rpz, newnodes);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = cleanup_nodes(rpz);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finalize the update */
|
|
|
|
ISC_SWAP(rpz->nodes, newnodes);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
isc_ht_destroy(&newnodes);
|
|
|
|
|
2023-01-03 13:21:34 +00:00
|
|
|
shuttingdown:
|
2022-03-07 13:55:03 +01:00
|
|
|
rpz->updateresult = result;
|
2017-02-20 11:57:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-10-05 11:21:28 +02:00
|
|
|
dns__rpz_timer_cb(void *arg) {
|
2022-03-07 13:55:03 +01:00
|
|
|
char domain[DNS_NAME_FORMATSIZE];
|
2022-10-05 11:21:28 +02:00
|
|
|
dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)arg;
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
|
2017-02-20 11:57:28 +01:00
|
|
|
REQUIRE(DNS_DB_VALID(rpz->db));
|
|
|
|
REQUIRE(rpz->updb == NULL);
|
|
|
|
REQUIRE(rpz->updbversion == NULL);
|
2022-03-07 13:55:03 +01:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
LOCK(&rpz->rpzs->maint_lock);
|
|
|
|
|
|
|
|
if (rpz->rpzs->shuttingdown) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
rpz->updatepending = false;
|
|
|
|
rpz->updaterunning = true;
|
|
|
|
rpz->updateresult = ISC_R_UNSET;
|
|
|
|
|
2017-02-20 11:57:28 +01:00
|
|
|
dns_db_attach(rpz->db, &rpz->updb);
|
2022-10-05 11:21:28 +02:00
|
|
|
INSIST(rpz->dbversion != NULL);
|
2017-02-20 11:57:28 +01:00
|
|
|
rpz->updbversion = rpz->dbversion;
|
|
|
|
rpz->dbversion = NULL;
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
dns_name_format(&rpz->origin, domain, DNS_NAME_FORMATSIZE);
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
|
2022-03-07 13:55:03 +01:00
|
|
|
ISC_LOG_INFO, "rpz: %s: reload start", domain);
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2023-09-29 16:16:49 -07:00
|
|
|
dns_rpz_zones_ref(rpz->rpzs);
|
2022-10-05 11:21:28 +02:00
|
|
|
isc_work_enqueue(rpz->loop, update_rpz_cb, update_rpz_done_cb, rpz);
|
|
|
|
|
|
|
|
isc_timer_destroy(&rpz->updatetimer);
|
|
|
|
rpz->loop = NULL;
|
|
|
|
|
2023-03-31 00:12:33 +02:00
|
|
|
rpz->lastupdated = isc_time_now();
|
2022-10-05 11:21:28 +02:00
|
|
|
unlock:
|
|
|
|
UNLOCK(&rpz->rpzs->maint_lock);
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free the radix tree of a response policy database.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
cidr_free(dns_rpz_zones_t *rpzs) {
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_cidr_node_t *cur = NULL, *child = NULL, *parent = NULL;
|
2013-02-25 12:46:51 -08:00
|
|
|
|
|
|
|
cur = rpzs->cidr;
|
|
|
|
while (cur != NULL) {
|
|
|
|
/* Depth first. */
|
|
|
|
child = cur->child[0];
|
|
|
|
if (child != NULL) {
|
|
|
|
cur = child;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
child = cur->child[1];
|
|
|
|
if (child != NULL) {
|
|
|
|
cur = child;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete this leaf and go up. */
|
|
|
|
parent = cur->parent;
|
|
|
|
if (parent == NULL) {
|
|
|
|
rpzs->cidr = NULL;
|
|
|
|
} else {
|
|
|
|
parent->child[parent->child[1] == cur] = NULL;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
isc_mem_put(rpzs->mctx, cur, sizeof(*cur));
|
|
|
|
cur = parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
static void
|
2022-10-05 11:21:28 +02:00
|
|
|
dns__rpz_shutdown(dns_rpz_zone_t *rpz) {
|
|
|
|
/* maint_lock must be locked */
|
|
|
|
if (rpz->updatetimer != NULL) {
|
|
|
|
/* Don't wait for timer to trigger for shutdown */
|
|
|
|
INSIST(rpz->loop != NULL);
|
2022-03-07 13:55:03 +01:00
|
|
|
|
2023-09-29 16:16:49 -07:00
|
|
|
dns_rpz_zones_ref(rpz->rpzs);
|
2022-10-05 11:21:28 +02:00
|
|
|
isc_async_run(rpz->loop, dns__rpz_timer_stop, rpz);
|
|
|
|
}
|
2022-03-07 13:55:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-10-05 11:21:28 +02:00
|
|
|
dns_rpz_zone_destroy(dns_rpz_zone_t **rpzp) {
|
|
|
|
dns_rpz_zone_t *rpz = NULL;
|
|
|
|
dns_rpz_zones_t *rpzs;
|
|
|
|
|
|
|
|
rpz = *rpzp;
|
|
|
|
*rpzp = NULL;
|
2022-03-07 13:55:03 +01:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
rpzs = rpz->rpzs;
|
|
|
|
rpz->rpzs = NULL;
|
2022-03-07 13:55:03 +01:00
|
|
|
|
|
|
|
if (dns_name_dynamic(&rpz->origin)) {
|
|
|
|
dns_name_free(&rpz->origin, rpzs->mctx);
|
|
|
|
}
|
|
|
|
if (dns_name_dynamic(&rpz->client_ip)) {
|
|
|
|
dns_name_free(&rpz->client_ip, rpzs->mctx);
|
|
|
|
}
|
|
|
|
if (dns_name_dynamic(&rpz->ip)) {
|
|
|
|
dns_name_free(&rpz->ip, rpzs->mctx);
|
|
|
|
}
|
|
|
|
if (dns_name_dynamic(&rpz->nsdname)) {
|
|
|
|
dns_name_free(&rpz->nsdname, rpzs->mctx);
|
|
|
|
}
|
|
|
|
if (dns_name_dynamic(&rpz->nsip)) {
|
|
|
|
dns_name_free(&rpz->nsip, rpzs->mctx);
|
|
|
|
}
|
|
|
|
if (dns_name_dynamic(&rpz->passthru)) {
|
|
|
|
dns_name_free(&rpz->passthru, rpzs->mctx);
|
|
|
|
}
|
|
|
|
if (dns_name_dynamic(&rpz->drop)) {
|
|
|
|
dns_name_free(&rpz->drop, rpzs->mctx);
|
|
|
|
}
|
|
|
|
if (dns_name_dynamic(&rpz->tcp_only)) {
|
|
|
|
dns_name_free(&rpz->tcp_only, rpzs->mctx);
|
|
|
|
}
|
|
|
|
if (dns_name_dynamic(&rpz->cname)) {
|
|
|
|
dns_name_free(&rpz->cname, rpzs->mctx);
|
|
|
|
}
|
|
|
|
if (rpz->db != NULL) {
|
|
|
|
if (rpz->dbversion != NULL) {
|
|
|
|
dns_db_closeversion(rpz->db, &rpz->dbversion, false);
|
|
|
|
}
|
|
|
|
dns_db_updatenotify_unregister(rpz->db,
|
|
|
|
dns_rpz_dbupdate_callback, rpz);
|
|
|
|
dns_db_detach(&rpz->db);
|
|
|
|
}
|
2022-03-07 13:55:03 +01:00
|
|
|
INSIST(!rpz->updaterunning);
|
2022-03-07 13:55:03 +01:00
|
|
|
|
|
|
|
isc_ht_destroy(&rpz->nodes);
|
|
|
|
|
|
|
|
isc_mem_put(rpzs->mctx, rpz, sizeof(*rpz));
|
|
|
|
}
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
static void
|
2022-10-05 11:21:28 +02:00
|
|
|
dns__rpz_zones_destroy(dns_rpz_zones_t *rpzs) {
|
|
|
|
REQUIRE(rpzs->shuttingdown);
|
2018-08-17 15:16:59 +02:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
for (dns_rpz_num_t rpz_num = 0; rpz_num < DNS_RPZ_MAX_ZONES; ++rpz_num)
|
|
|
|
{
|
|
|
|
if (rpzs->zones[rpz_num] == NULL) {
|
|
|
|
continue;
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
2022-03-07 13:55:03 +01:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
dns_rpz_zone_destroy(&rpzs->zones[rpz_num]);
|
2019-08-01 11:15:05 +10:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
if (rpzs->rps_cstr_size != 0) {
|
|
|
|
#ifdef USE_DNSRPS
|
|
|
|
librpz->client_detach(&rpzs->rps_client);
|
|
|
|
#endif /* ifdef USE_DNSRPS */
|
|
|
|
isc_mem_put(rpzs->mctx, rpzs->rps_cstr, rpzs->rps_cstr_size);
|
|
|
|
}
|
2015-05-20 15:00:50 -07:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
cidr_free(rpzs);
|
2023-09-29 21:40:29 -07:00
|
|
|
if (rpzs->table != NULL) {
|
|
|
|
dns_qpmulti_destroy(&rpzs->table);
|
2022-03-07 13:55:03 +01:00
|
|
|
}
|
2023-09-29 21:40:29 -07:00
|
|
|
|
2022-03-07 13:55:03 +01:00
|
|
|
isc_mutex_destroy(&rpzs->maint_lock);
|
|
|
|
isc_rwlock_destroy(&rpzs->search_lock);
|
|
|
|
isc_mem_putanddetach(&rpzs->mctx, rpzs, sizeof(*rpzs));
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
void
|
|
|
|
dns_rpz_zones_shutdown(dns_rpz_zones_t *rpzs) {
|
|
|
|
REQUIRE(DNS_RPZ_ZONES_VALID(rpzs));
|
|
|
|
/*
|
|
|
|
* Forget the last of the view's rpz machinery when shutting down.
|
|
|
|
*/
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
LOCK(&rpzs->maint_lock);
|
|
|
|
if (rpzs->shuttingdown) {
|
|
|
|
UNLOCK(&rpzs->maint_lock);
|
|
|
|
return;
|
2022-03-07 13:55:03 +01:00
|
|
|
}
|
2022-10-05 11:21:28 +02:00
|
|
|
|
|
|
|
rpzs->shuttingdown = true;
|
|
|
|
|
|
|
|
for (dns_rpz_num_t rpz_num = 0; rpz_num < DNS_RPZ_MAX_ZONES; ++rpz_num)
|
|
|
|
{
|
|
|
|
if (rpzs->zones[rpz_num] == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
dns__rpz_shutdown(rpzs->zones[rpz_num]);
|
|
|
|
}
|
|
|
|
UNLOCK(&rpzs->maint_lock);
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
|
2022-10-05 11:21:28 +02:00
|
|
|
#ifdef DNS_RPZ_TRACE
|
|
|
|
ISC_REFCOUNT_TRACE_IMPL(dns_rpz_zones, dns__rpz_zones_destroy);
|
|
|
|
#else
|
|
|
|
ISC_REFCOUNT_IMPL(dns_rpz_zones, dns__rpz_zones_destroy);
|
|
|
|
#endif
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* Add an IP address to the radix tree or a name to the summary database.
|
|
|
|
*/
|
2022-03-08 17:13:26 +01:00
|
|
|
static isc_result_t
|
|
|
|
rpz_add(dns_rpz_zone_t *rpz, const dns_name_t *src_name) {
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_rpz_type_t rpz_type;
|
2013-02-25 13:23:42 -08:00
|
|
|
isc_result_t result = ISC_R_FAILURE;
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_zones_t *rpzs = NULL;
|
|
|
|
dns_rpz_num_t rpz_num;
|
2013-02-25 12:46:51 -08:00
|
|
|
|
|
|
|
REQUIRE(rpz != NULL);
|
2022-03-08 17:13:26 +01:00
|
|
|
|
|
|
|
rpzs = rpz->rpzs;
|
|
|
|
rpz_num = rpz->num;
|
|
|
|
|
|
|
|
REQUIRE(rpzs != NULL && rpz_num < rpzs->p.num_zones);
|
|
|
|
|
2017-09-11 11:53:42 -07:00
|
|
|
rpz_type = type_from_name(rpzs, rpz, src_name);
|
2013-02-25 12:46:51 -08:00
|
|
|
switch (rpz_type) {
|
|
|
|
case DNS_RPZ_TYPE_QNAME:
|
|
|
|
case DNS_RPZ_TYPE_NSDNAME:
|
2022-03-08 17:13:26 +01:00
|
|
|
result = add_name(rpz, rpz_type, src_name);
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
2013-07-12 14:46:47 -07:00
|
|
|
case DNS_RPZ_TYPE_CLIENT_IP:
|
2013-02-25 12:46:51 -08:00
|
|
|
case DNS_RPZ_TYPE_IP:
|
|
|
|
case DNS_RPZ_TYPE_NSIP:
|
2022-03-08 17:13:26 +01:00
|
|
|
result = add_cidr(rpz, rpz_type, src_name);
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_BAD:
|
|
|
|
break;
|
|
|
|
}
|
2017-02-20 11:57:28 +01:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove an IP address from the radix tree.
|
|
|
|
*/
|
|
|
|
static void
|
2022-03-08 17:13:26 +01:00
|
|
|
del_cidr(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *src_name) {
|
2013-02-25 12:46:51 -08:00
|
|
|
isc_result_t result;
|
|
|
|
dns_rpz_cidr_key_t tgt_ip;
|
|
|
|
dns_rpz_prefix_t tgt_prefix;
|
2013-07-12 14:46:47 -07:00
|
|
|
dns_rpz_addr_zbits_t tgt_set;
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_cidr_node_t *tgt = NULL, *parent = NULL, *child = NULL;
|
2013-02-25 12:46:51 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not worry about invalid rpz IP address names. If we
|
|
|
|
* are here, then something relevant was added and so was
|
2023-09-29 21:40:29 -07:00
|
|
|
* valid.
|
2013-02-25 12:46:51 -08:00
|
|
|
*/
|
2022-03-08 17:13:26 +01:00
|
|
|
result = name2ipkey(DNS_RPZ_DEBUG_QUIET, rpz, rpz_type, src_name,
|
|
|
|
&tgt_ip, &tgt_prefix, &tgt_set);
|
2013-02-25 12:46:51 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2023-09-30 13:23:51 -07:00
|
|
|
RWLOCK(&rpz->rpzs->search_lock, isc_rwlocktype_write);
|
2022-03-08 17:13:26 +01:00
|
|
|
result = search(rpz->rpzs, &tgt_ip, tgt_prefix, &tgt_set, false, &tgt);
|
2013-02-25 12:46:51 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2023-09-30 13:23:51 -07:00
|
|
|
goto done;
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
|
|
|
* Mark the node and its parents to reflect the deleted IP address.
|
|
|
|
*/
|
2013-07-12 14:46:47 -07:00
|
|
|
tgt_set.client_ip &= tgt->set.client_ip;
|
|
|
|
tgt_set.ip &= tgt->set.ip;
|
|
|
|
tgt_set.nsip &= tgt->set.nsip;
|
|
|
|
tgt->set.client_ip &= ~tgt_set.client_ip;
|
|
|
|
tgt->set.ip &= ~tgt_set.ip;
|
|
|
|
tgt->set.nsip &= ~tgt_set.nsip;
|
2013-02-25 12:46:51 -08:00
|
|
|
set_sum_pair(tgt);
|
|
|
|
|
2022-03-08 17:13:26 +01:00
|
|
|
adj_trigger_cnt(rpz, rpz_type, &tgt_ip, tgt_prefix, false);
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
|
|
|
* We might need to delete 2 nodes.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* The node is now useless if it has no data of its own
|
2022-03-08 17:13:26 +01:00
|
|
|
* and 0 or 1 children. We are finished if it is not
|
|
|
|
* useless.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
|
|
|
if ((child = tgt->child[0]) != NULL) {
|
|
|
|
if (tgt->child[1] != NULL) {
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
} else {
|
|
|
|
child = tgt->child[1];
|
|
|
|
}
|
2013-07-12 14:46:47 -07:00
|
|
|
if (tgt->set.client_ip != 0 || tgt->set.ip != 0 ||
|
2022-11-02 19:33:14 +01:00
|
|
|
tgt->set.nsip != 0)
|
|
|
|
{
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Replace the pointer to this node in the parent with
|
|
|
|
* the remaining child or NULL.
|
|
|
|
*/
|
|
|
|
parent = tgt->parent;
|
|
|
|
if (parent == NULL) {
|
2022-03-08 17:13:26 +01:00
|
|
|
rpz->rpzs->cidr = child;
|
2011-01-13 01:59:28 +00:00
|
|
|
} else {
|
|
|
|
parent->child[parent->child[1] == tgt] = child;
|
|
|
|
}
|
2022-03-08 17:13:26 +01:00
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
|
|
|
* If the child exists fix up its parent pointer.
|
|
|
|
*/
|
|
|
|
if (child != NULL) {
|
|
|
|
child->parent = parent;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2022-03-08 17:13:26 +01:00
|
|
|
isc_mem_put(rpz->rpzs->mctx, tgt, sizeof(*tgt));
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
tgt = parent;
|
|
|
|
} while (tgt != NULL);
|
2023-09-30 13:23:51 -07:00
|
|
|
|
|
|
|
done:
|
|
|
|
RWUNLOCK(&rpz->rpzs->search_lock, isc_rwlocktype_write);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
static void
|
2022-03-08 17:13:26 +01:00
|
|
|
del_name(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *src_name) {
|
2023-09-29 21:40:29 -07:00
|
|
|
isc_result_t result;
|
2013-02-25 12:46:51 -08:00
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
|
|
dns_fixedname_t trig_namef;
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_name_t *trig_name = NULL;
|
2023-09-29 21:40:29 -07:00
|
|
|
dns_rpz_zones_t *rpzs = rpz->rpzs;
|
|
|
|
nmdata_t *data = NULL;
|
|
|
|
nmdata_t del_data;
|
|
|
|
dns_qp_t *qp = NULL;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool exists;
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
dns_qpmulti_write(rpzs->table, &qp);
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
/*
|
2015-08-18 19:39:53 +05:30
|
|
|
* We need a summary database of names even with 1 policy zone,
|
|
|
|
* because wildcard triggers are handled differently.
|
2013-02-25 12:46:51 -08:00
|
|
|
*/
|
|
|
|
|
2018-03-28 14:38:09 +02:00
|
|
|
trig_name = dns_fixedname_initname(&trig_namef);
|
2022-03-08 17:13:26 +01:00
|
|
|
name2data(rpz, rpz_type, src_name, trig_name, &del_data);
|
2014-06-11 20:00:19 -07:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
result = dns_qp_getname(qp, trig_name, (void **)&data, NULL);
|
2013-02-25 12:46:51 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
INSIST(data != NULL);
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
del_data.set.qname &= data->set.qname;
|
|
|
|
del_data.set.ns &= data->set.ns;
|
|
|
|
del_data.wild.qname &= data->wild.qname;
|
|
|
|
del_data.wild.ns &= data->wild.ns;
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
exists = (del_data.set.qname != 0 || del_data.set.ns != 0 ||
|
|
|
|
del_data.wild.qname != 0 || del_data.wild.ns != 0);
|
2016-11-16 12:11:53 +09:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
data->set.qname &= ~del_data.set.qname;
|
|
|
|
data->set.ns &= ~del_data.set.ns;
|
|
|
|
data->wild.qname &= ~del_data.wild.qname;
|
|
|
|
data->wild.ns &= ~del_data.wild.ns;
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
if (data->set.qname == 0 && data->set.ns == 0 &&
|
|
|
|
data->wild.qname == 0 && data->wild.ns == 0)
|
2013-07-12 14:46:47 -07:00
|
|
|
{
|
2023-09-29 21:40:29 -07:00
|
|
|
result = dns_qp_deletename(qp, trig_name, NULL, NULL);
|
2013-02-25 12:46:51 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
/*
|
2017-02-20 11:57:28 +01:00
|
|
|
* bin/tests/system/rpz/tests.sh looks for
|
|
|
|
* "rpz.*failed".
|
2013-02-25 12:46:51 -08:00
|
|
|
*/
|
|
|
|
dns_name_format(src_name, namebuf, sizeof(namebuf));
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
|
|
|
|
DNS_RPZ_ERROR_LEVEL,
|
2022-03-08 17:13:26 +01:00
|
|
|
"rpz del_name(%s) node delete "
|
|
|
|
"failed: %s",
|
2013-02-25 12:46:51 -08:00
|
|
|
namebuf, isc_result_totext(result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-16 12:11:53 +09:00
|
|
|
if (exists) {
|
2023-09-30 13:23:51 -07:00
|
|
|
RWLOCK(&rpz->rpzs->search_lock, isc_rwlocktype_write);
|
2022-03-08 17:13:26 +01:00
|
|
|
adj_trigger_cnt(rpz, rpz_type, NULL, 0, false);
|
2023-09-30 13:23:51 -07:00
|
|
|
RWUNLOCK(&rpz->rpzs->search_lock, isc_rwlocktype_write);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2023-09-29 21:40:29 -07:00
|
|
|
|
|
|
|
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
|
|
|
dns_qpmulti_commit(rpzs->table, &qp);
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
2013-02-25 12:46:51 -08:00
|
|
|
* Remove an IP address from the radix tree or a name from the summary database.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2022-03-08 17:13:26 +01:00
|
|
|
static void
|
|
|
|
rpz_del(dns_rpz_zone_t *rpz, const dns_name_t *src_name) {
|
2013-02-25 12:46:51 -08:00
|
|
|
dns_rpz_type_t rpz_type;
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_zones_t *rpzs = NULL;
|
|
|
|
dns_rpz_num_t rpz_num;
|
2013-02-25 12:46:51 -08:00
|
|
|
|
|
|
|
REQUIRE(rpz != NULL);
|
|
|
|
|
2022-03-08 17:13:26 +01:00
|
|
|
rpzs = rpz->rpzs;
|
|
|
|
rpz_num = rpz->num;
|
|
|
|
|
|
|
|
REQUIRE(rpzs != NULL && rpz_num < rpzs->p.num_zones);
|
|
|
|
|
2017-09-11 11:53:42 -07:00
|
|
|
rpz_type = type_from_name(rpzs, rpz, src_name);
|
2013-02-25 12:46:51 -08:00
|
|
|
switch (rpz_type) {
|
|
|
|
case DNS_RPZ_TYPE_QNAME:
|
|
|
|
case DNS_RPZ_TYPE_NSDNAME:
|
2022-03-08 17:13:26 +01:00
|
|
|
del_name(rpz, rpz_type, src_name);
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
2013-07-12 14:46:47 -07:00
|
|
|
case DNS_RPZ_TYPE_CLIENT_IP:
|
2013-02-25 12:46:51 -08:00
|
|
|
case DNS_RPZ_TYPE_IP:
|
|
|
|
case DNS_RPZ_TYPE_NSIP:
|
2022-03-08 17:13:26 +01:00
|
|
|
del_cidr(rpz, rpz_type, src_name);
|
2013-02-25 12:46:51 -08:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_BAD:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search the summary radix tree to get a relative owner name in a
|
|
|
|
* policy zone relevant to a triggering IP address.
|
|
|
|
* rpz_type and zbits limit the search for IP address netaddr
|
|
|
|
* return the policy zone's number or DNS_RPZ_INVALID_NUM
|
|
|
|
* ip_name is the relative owner name found and
|
|
|
|
* *prefixp is its prefix length.
|
|
|
|
*/
|
|
|
|
dns_rpz_num_t
|
|
|
|
dns_rpz_find_ip(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type,
|
|
|
|
dns_rpz_zbits_t zbits, const isc_netaddr_t *netaddr,
|
|
|
|
dns_name_t *ip_name, dns_rpz_prefix_t *prefixp) {
|
2011-01-13 01:59:28 +00:00
|
|
|
dns_rpz_cidr_key_t tgt_ip;
|
2013-07-12 14:46:47 -07:00
|
|
|
dns_rpz_addr_zbits_t tgt_set;
|
2022-03-08 17:13:26 +01:00
|
|
|
dns_rpz_cidr_node_t *found = NULL;
|
2013-02-25 12:46:51 -08:00
|
|
|
isc_result_t result;
|
2018-06-04 13:41:09 +02:00
|
|
|
dns_rpz_num_t rpz_num = 0;
|
2015-05-19 15:47:42 -07:00
|
|
|
dns_rpz_have_t have;
|
2011-01-13 01:59:28 +00:00
|
|
|
int i;
|
|
|
|
|
2017-02-20 11:57:28 +01:00
|
|
|
RWLOCK(&rpzs->search_lock, isc_rwlocktype_read);
|
2015-05-19 15:47:42 -07:00
|
|
|
have = rpzs->have;
|
2017-02-20 11:57:28 +01:00
|
|
|
RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
|
2015-05-19 15:47:42 -07:00
|
|
|
|
2011-01-13 01:59:28 +00:00
|
|
|
/*
|
|
|
|
* Convert IP address to CIDR tree key.
|
|
|
|
*/
|
|
|
|
if (netaddr->family == AF_INET) {
|
|
|
|
tgt_ip.w[0] = 0;
|
|
|
|
tgt_ip.w[1] = 0;
|
|
|
|
tgt_ip.w[2] = ADDR_V4MAPPED;
|
|
|
|
tgt_ip.w[3] = ntohl(netaddr->type.in.s_addr);
|
2013-07-12 14:46:47 -07:00
|
|
|
switch (rpz_type) {
|
|
|
|
case DNS_RPZ_TYPE_CLIENT_IP:
|
2015-05-19 15:47:42 -07:00
|
|
|
zbits &= have.client_ipv4;
|
2013-07-12 14:46:47 -07:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_IP:
|
2015-05-19 15:47:42 -07:00
|
|
|
zbits &= have.ipv4;
|
2013-07-12 14:46:47 -07:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_NSIP:
|
2015-05-19 15:47:42 -07:00
|
|
|
zbits &= have.nsipv4;
|
2013-07-12 14:46:47 -07:00
|
|
|
break;
|
|
|
|
default:
|
2022-03-28 12:59:43 +02:00
|
|
|
UNREACHABLE();
|
2013-07-12 14:46:47 -07:00
|
|
|
break;
|
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
} else if (netaddr->family == AF_INET6) {
|
|
|
|
dns_rpz_cidr_key_t src_ip6;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Given the int aligned struct in_addr member of netaddr->type
|
|
|
|
* one could cast netaddr->type.in6 to dns_rpz_cidr_key_t *,
|
2013-02-25 12:46:51 -08:00
|
|
|
* but some people object.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(src_ip6.w, &netaddr->type.in6, sizeof(src_ip6.w));
|
2011-01-13 01:59:28 +00:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
tgt_ip.w[i] = ntohl(src_ip6.w[i]);
|
|
|
|
}
|
2013-07-12 14:46:47 -07:00
|
|
|
switch (rpz_type) {
|
|
|
|
case DNS_RPZ_TYPE_CLIENT_IP:
|
2015-05-19 15:47:42 -07:00
|
|
|
zbits &= have.client_ipv6;
|
2013-07-12 14:46:47 -07:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_IP:
|
2015-05-19 15:47:42 -07:00
|
|
|
zbits &= have.ipv6;
|
2013-07-12 14:46:47 -07:00
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_NSIP:
|
2015-05-19 15:47:42 -07:00
|
|
|
zbits &= have.nsipv6;
|
2013-07-12 14:46:47 -07:00
|
|
|
break;
|
|
|
|
default:
|
2022-03-28 12:59:43 +02:00
|
|
|
UNREACHABLE();
|
2013-07-12 14:46:47 -07:00
|
|
|
break;
|
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
} else {
|
2013-02-25 12:46:51 -08:00
|
|
|
return (DNS_RPZ_INVALID_NUM);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
if (zbits == 0) {
|
|
|
|
return (DNS_RPZ_INVALID_NUM);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-07-12 14:46:47 -07:00
|
|
|
make_addr_set(&tgt_set, zbits, rpz_type);
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2015-06-03 18:18:55 -07:00
|
|
|
RWLOCK(&rpzs->search_lock, isc_rwlocktype_read);
|
2018-04-17 08:29:14 -07:00
|
|
|
result = search(rpzs, &tgt_ip, 128, &tgt_set, false, &found);
|
2013-02-25 12:46:51 -08:00
|
|
|
if (result == ISC_R_NOTFOUND) {
|
|
|
|
/*
|
|
|
|
* There are no eligible zones for this IP address.
|
|
|
|
*/
|
2015-06-03 18:18:55 -07:00
|
|
|
RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
|
2013-02-25 12:46:51 -08:00
|
|
|
return (DNS_RPZ_INVALID_NUM);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct the trigger name for the longest matching trigger
|
|
|
|
* in the first eligible zone with a match.
|
|
|
|
*/
|
|
|
|
*prefixp = found->prefix;
|
2013-07-12 14:46:47 -07:00
|
|
|
switch (rpz_type) {
|
|
|
|
case DNS_RPZ_TYPE_CLIENT_IP:
|
|
|
|
rpz_num = zbit_to_num(found->set.client_ip & tgt_set.client_ip);
|
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_IP:
|
|
|
|
rpz_num = zbit_to_num(found->set.ip & tgt_set.ip);
|
|
|
|
break;
|
|
|
|
case DNS_RPZ_TYPE_NSIP:
|
|
|
|
rpz_num = zbit_to_num(found->set.nsip & tgt_set.nsip);
|
|
|
|
break;
|
|
|
|
default:
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
result = ip2name(&found->ip, found->prefix, dns_rootname, ip_name);
|
2015-06-03 18:18:55 -07:00
|
|
|
RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
|
2013-02-25 12:46:51 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* bin/tests/system/rpz/tests.sh looks for "rpz.*failed".
|
|
|
|
*/
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
|
|
|
|
DNS_RPZ_ERROR_LEVEL, "rpz ip2name() failed: %s",
|
2013-02-25 12:46:51 -08:00
|
|
|
isc_result_totext(result));
|
|
|
|
return (DNS_RPZ_INVALID_NUM);
|
|
|
|
}
|
|
|
|
return (rpz_num);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search the summary radix tree for policy zones with triggers matching
|
|
|
|
* a name.
|
|
|
|
*/
|
|
|
|
dns_rpz_zbits_t
|
|
|
|
dns_rpz_find_name(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type,
|
|
|
|
dns_rpz_zbits_t zbits, dns_name_t *trig_name) {
|
|
|
|
isc_result_t result;
|
2023-09-29 21:40:29 -07:00
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
|
|
nmdata_t *data = NULL;
|
|
|
|
dns_rpz_zbits_t found_zbits = 0;
|
|
|
|
dns_qpchain_t chain;
|
|
|
|
dns_qpread_t qpr;
|
2019-08-28 13:11:35 -07:00
|
|
|
int i;
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2019-08-28 13:11:35 -07:00
|
|
|
if (zbits == 0) {
|
2013-02-25 12:46:51 -08:00
|
|
|
return (0);
|
2019-08-28 13:11:35 -07:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
dns_qpmulti_query(rpzs->table, &qpr);
|
|
|
|
dns_qpchain_init(&qpr, &chain);
|
2020-06-09 20:45:21 -03:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
result = dns_qp_lookup(&qpr, trig_name, NULL, NULL, &chain,
|
|
|
|
(void **)&data, NULL);
|
2013-02-25 12:46:51 -08:00
|
|
|
switch (result) {
|
|
|
|
case ISC_R_SUCCESS:
|
2023-09-29 21:40:29 -07:00
|
|
|
INSIST(data != NULL);
|
|
|
|
if (rpz_type == DNS_RPZ_TYPE_QNAME) {
|
|
|
|
found_zbits = data->set.qname;
|
|
|
|
} else {
|
|
|
|
found_zbits = data->set.ns;
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
2021-10-11 12:09:16 +02:00
|
|
|
FALLTHROUGH;
|
2019-08-28 13:11:35 -07:00
|
|
|
|
2013-02-25 12:46:51 -08:00
|
|
|
case DNS_R_PARTIALMATCH:
|
2023-09-29 21:40:29 -07:00
|
|
|
i = dns_qpchain_length(&chain);
|
|
|
|
while (i-- > 0) {
|
|
|
|
dns_qpchain_node(&chain, i, NULL, (void **)&data, NULL);
|
|
|
|
INSIST(data != NULL);
|
|
|
|
if (rpz_type == DNS_RPZ_TYPE_QNAME) {
|
|
|
|
found_zbits |= data->wild.qname;
|
2020-06-09 20:45:21 -03:00
|
|
|
} else {
|
2023-09-29 21:40:29 -07:00
|
|
|
found_zbits |= data->wild.ns;
|
2020-06-09 20:45:21 -03:00
|
|
|
}
|
2013-02-25 12:46:51 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ISC_R_NOTFOUND:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* bin/tests/system/rpz/tests.sh looks for "rpz.*failed".
|
|
|
|
*/
|
|
|
|
dns_name_format(trig_name, namebuf, sizeof(namebuf));
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB,
|
|
|
|
DNS_RPZ_ERROR_LEVEL,
|
2013-02-25 12:46:51 -08:00
|
|
|
"dns_rpz_find_name(%s) failed: %s", namebuf,
|
|
|
|
isc_result_totext(result));
|
|
|
|
break;
|
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2023-09-29 21:40:29 -07:00
|
|
|
dns_qpread_destroy(rpzs->table, &qpr);
|
2013-02-25 12:46:51 -08:00
|
|
|
return (zbits & found_zbits);
|
2011-01-13 01:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Translate CNAME rdata to a QNAME response policy action.
|
|
|
|
*/
|
|
|
|
dns_rpz_policy_t
|
2012-05-31 02:03:34 +00:00
|
|
|
dns_rpz_decode_cname(dns_rpz_zone_t *rpz, dns_rdataset_t *rdataset,
|
|
|
|
dns_name_t *selfname) {
|
2011-01-13 01:59:28 +00:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
dns_rdata_cname_t cname;
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
result = dns_rdataset_first(rdataset);
|
2013-02-25 12:46:51 -08:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2011-01-13 01:59:28 +00:00
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
result = dns_rdata_tostruct(&rdata, &cname, NULL);
|
2013-02-25 12:46:51 -08:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2011-01-13 01:59:28 +00:00
|
|
|
dns_rdata_reset(&rdata);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CNAME . means NXDOMAIN
|
|
|
|
*/
|
|
|
|
if (dns_name_equal(&cname.cname, dns_rootname)) {
|
|
|
|
return (DNS_RPZ_POLICY_NXDOMAIN);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
2011-10-13 01:32:34 +00:00
|
|
|
if (dns_name_iswildcard(&cname.cname)) {
|
|
|
|
/*
|
|
|
|
* CNAME *. means NODATA
|
|
|
|
*/
|
|
|
|
if (dns_name_countlabels(&cname.cname) == 2) {
|
|
|
|
return (DNS_RPZ_POLICY_NODATA);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-10-13 01:32:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-10-13 01:32:34 +00:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
/*
|
2013-07-12 14:46:47 -07:00
|
|
|
* CNAME rpz-tcp-only. means "send truncated UDP responses."
|
|
|
|
*/
|
|
|
|
if (dns_name_equal(&cname.cname, &rpz->tcp_only)) {
|
|
|
|
return (DNS_RPZ_POLICY_TCP_ONLY);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-07-12 14:46:47 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* CNAME rpz-drop. means "do not respond."
|
|
|
|
*/
|
|
|
|
if (dns_name_equal(&cname.cname, &rpz->drop)) {
|
|
|
|
return (DNS_RPZ_POLICY_DROP);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-07-12 14:46:47 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* CNAME rpz-passthru. means "do not rewrite."
|
2012-05-31 02:03:34 +00:00
|
|
|
*/
|
|
|
|
if (dns_name_equal(&cname.cname, &rpz->passthru)) {
|
|
|
|
return (DNS_RPZ_POLICY_PASSTHRU);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-05-31 02:03:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 128.1.0.127.rpz-ip CNAME 128.1.0.0.127. is obsolete PASSTHRU
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
|
|
|
if (selfname != NULL && dns_name_equal(&cname.cname, selfname)) {
|
2011-10-13 01:32:34 +00:00
|
|
|
return (DNS_RPZ_POLICY_PASSTHRU);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-01-13 01:59:28 +00:00
|
|
|
|
|
|
|
/*
|
2011-10-13 01:32:34 +00:00
|
|
|
* Any other rdata gives a response consisting of the rdata.
|
2011-01-13 01:59:28 +00:00
|
|
|
*/
|
|
|
|
return (DNS_RPZ_POLICY_RECORD);
|
|
|
|
}
|
2023-09-29 21:40:29 -07:00
|
|
|
|
|
|
|
static void
|
|
|
|
destroy_nmdata(nmdata_t *data) {
|
2024-03-11 22:10:41 -07:00
|
|
|
dns_name_free(&data->name, data->mctx);
|
2023-09-29 21:40:29 -07:00
|
|
|
isc_mem_putanddetach(&data->mctx, data, sizeof(nmdata_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DNS_RPZ_TRACE
|
|
|
|
ISC_REFCOUNT_TRACE_IMPL(nmdata, destroy_nmdata);
|
|
|
|
#else
|
|
|
|
ISC_REFCOUNT_IMPL(nmdata, destroy_nmdata);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void
|
|
|
|
qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
|
|
|
|
uint32_t ival ISC_ATTR_UNUSED) {
|
|
|
|
nmdata_t *data = pval;
|
|
|
|
nmdata_ref(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
|
|
|
|
uint32_t ival ISC_ATTR_UNUSED) {
|
|
|
|
nmdata_t *data = pval;
|
|
|
|
nmdata_detach(&data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
|
|
|
|
uint32_t ival ISC_ATTR_UNUSED) {
|
|
|
|
nmdata_t *data = pval;
|
2024-03-11 22:10:41 -07:00
|
|
|
return (dns_qpkey_fromname(key, &data->name));
|
2023-09-29 21:40:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qp_triename(void *uctx, char *buf, size_t size) {
|
|
|
|
dns_view_t *view = uctx;
|
|
|
|
snprintf(buf, size, "view %s RPZs", view->name);
|
|
|
|
}
|