From 3b9b6d0b8e7f798023c9d109c490449d528fde80 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 17:59:48 +0200 Subject: Adding upstream version 1:9.18.19. Signed-off-by: Daniel Baumann --- lib/dns/include/dns/rpz.h | 441 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 lib/dns/include/dns/rpz.h (limited to 'lib/dns/include/dns/rpz.h') diff --git a/lib/dns/include/dns/rpz.h b/lib/dns/include/dns/rpz.h new file mode 100644 index 0000000..364ad92 --- /dev/null +++ b/lib/dns/include/dns/rpz.h @@ -0,0 +1,441 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +/* + * Define this for reference count tracing in the unit + */ +#undef DNS_RPZ_TRACE + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +ISC_LANG_BEGINDECLS + +#define DNS_RPZ_PREFIX "rpz-" +/* + * Sub-zones of various trigger types. + */ +#define DNS_RPZ_CLIENT_IP_ZONE DNS_RPZ_PREFIX "client-ip" +#define DNS_RPZ_IP_ZONE DNS_RPZ_PREFIX "ip" +#define DNS_RPZ_NSIP_ZONE DNS_RPZ_PREFIX "nsip" +#define DNS_RPZ_NSDNAME_ZONE DNS_RPZ_PREFIX "nsdname" +/* + * Special policies. + */ +#define DNS_RPZ_PASSTHRU_NAME DNS_RPZ_PREFIX "passthru" +#define DNS_RPZ_DROP_NAME DNS_RPZ_PREFIX "drop" +#define DNS_RPZ_TCP_ONLY_NAME DNS_RPZ_PREFIX "tcp-only" + +typedef uint8_t dns_rpz_prefix_t; + +typedef enum { + DNS_RPZ_TYPE_BAD, + DNS_RPZ_TYPE_CLIENT_IP, + DNS_RPZ_TYPE_QNAME, + DNS_RPZ_TYPE_IP, + DNS_RPZ_TYPE_NSDNAME, + DNS_RPZ_TYPE_NSIP +} dns_rpz_type_t; + +/* + * Require DNS_RPZ_POLICY_PASSTHRU < DNS_RPZ_POLICY_DROP + * < DNS_RPZ_POLICY_TCP_ONLY DNS_RPZ_POLICY_NXDOMAIN < DNS_RPZ_POLICY_NODATA + * < DNS_RPZ_POLICY_CNAME to choose among competing policies. + */ +typedef enum { + DNS_RPZ_POLICY_GIVEN = 0, /* 'given': what policy record says */ + DNS_RPZ_POLICY_DISABLED = 1, /* log what would have happened */ + DNS_RPZ_POLICY_PASSTHRU = 2, /* 'passthru': do not rewrite */ + DNS_RPZ_POLICY_DROP = 3, /* 'drop': do not respond */ + DNS_RPZ_POLICY_TCP_ONLY = 4, /* 'tcp-only': answer UDP with TC=1 */ + DNS_RPZ_POLICY_NXDOMAIN = 5, /* 'nxdomain': answer with NXDOMAIN */ + DNS_RPZ_POLICY_NODATA = 6, /* 'nodata': answer with ANCOUNT=0 */ + DNS_RPZ_POLICY_CNAME = 7, /* 'cname x': answer with x's rrsets */ + DNS_RPZ_POLICY_DNS64, /* Apply DN64 to the A rewrite */ + DNS_RPZ_POLICY_RECORD, + DNS_RPZ_POLICY_WILDCNAME, + DNS_RPZ_POLICY_MISS, + DNS_RPZ_POLICY_ERROR +} dns_rpz_policy_t; + +typedef uint8_t dns_rpz_num_t; + +#define DNS_RPZ_MAX_ZONES 64 +/* + * Type dns_rpz_zbits_t must be an unsigned int wide enough to contain + * at least DNS_RPZ_MAX_ZONES bits. + */ +typedef uint64_t dns_rpz_zbits_t; + +#define DNS_RPZ_ALL_ZBITS ((dns_rpz_zbits_t)-1) + +#define DNS_RPZ_INVALID_NUM DNS_RPZ_MAX_ZONES + +#define DNS_RPZ_ZBIT(n) (((dns_rpz_zbits_t)1) << (dns_rpz_num_t)(n)) + +/* + * Mask of the specified and higher numbered policy zones + * Avoid hassles with (1<<33) or (1<<65) + */ +#define DNS_RPZ_ZMASK(n) \ + ((dns_rpz_zbits_t)((((n) >= DNS_RPZ_MAX_ZONES - 1) \ + ? 0 \ + : (1ULL << ((n) + 1))) - \ + 1)) + +/* + * The trigger counter type. + */ +typedef size_t dns_rpz_trigger_counter_t; + +/* + * The number of triggers of each type in a response policy zone. + */ +typedef struct dns_rpz_triggers dns_rpz_triggers_t; +struct dns_rpz_triggers { + dns_rpz_trigger_counter_t client_ipv4; + dns_rpz_trigger_counter_t client_ipv6; + dns_rpz_trigger_counter_t qname; + dns_rpz_trigger_counter_t ipv4; + dns_rpz_trigger_counter_t ipv6; + dns_rpz_trigger_counter_t nsdname; + dns_rpz_trigger_counter_t nsipv4; + dns_rpz_trigger_counter_t nsipv6; +}; + +/* + * A single response policy zone. + */ +typedef struct dns_rpz_zone dns_rpz_zone_t; +typedef struct dns_rpz_zones dns_rpz_zones_t; + +struct dns_rpz_zone { + unsigned int magic; + + dns_rpz_num_t num; /* ordinal in list of policy zones */ + dns_name_t origin; /* Policy zone name */ + dns_name_t client_ip; /* DNS_RPZ_CLIENT_IP_ZONE.origin. */ + dns_name_t ip; /* DNS_RPZ_IP_ZONE.origin. */ + dns_name_t nsdname; /* DNS_RPZ_NSDNAME_ZONE.origin */ + dns_name_t nsip; /* DNS_RPZ_NSIP_ZONE.origin. */ + dns_name_t passthru; /* DNS_RPZ_PASSTHRU_NAME. */ + dns_name_t drop; /* DNS_RPZ_DROP_NAME. */ + dns_name_t tcp_only; /* DNS_RPZ_TCP_ONLY_NAME. */ + dns_name_t cname; /* override value for ..._CNAME */ + dns_ttl_t max_policy_ttl; + dns_rpz_policy_t policy; /* DNS_RPZ_POLICY_GIVEN or override */ + + uint32_t min_update_interval; /* minimal interval between updates */ + isc_ht_t *nodes; /* entries in zone */ + dns_rpz_zones_t *rpzs; /* owner */ + isc_time_t lastupdated; /* last time the zone was processed */ + bool updatepending; /* there is an update pending */ + bool updaterunning; /* there is an update running */ + isc_result_t updateresult; /* result from the offloaded work */ + dns_db_t *db; /* zones database */ + dns_dbversion_t *dbversion; /* version we will be updating to */ + dns_db_t *updb; /* zones database we're working on */ + dns_dbversion_t *updbversion; /* version we're working on */ + bool addsoa; /* add soa to the additional section */ + isc_timer_t *updatetimer; + isc_event_t updateevent; +}; + +/* + * Radix tree node for response policy IP addresses + */ +typedef struct dns_rpz_cidr_node dns_rpz_cidr_node_t; + +/* + * Bitfields indicating which policy zones have policies of + * which type. + */ +typedef struct dns_rpz_have dns_rpz_have_t; +struct dns_rpz_have { + dns_rpz_zbits_t client_ipv4; + dns_rpz_zbits_t client_ipv6; + dns_rpz_zbits_t client_ip; + dns_rpz_zbits_t qname; + dns_rpz_zbits_t ipv4; + dns_rpz_zbits_t ipv6; + dns_rpz_zbits_t ip; + dns_rpz_zbits_t nsdname; + dns_rpz_zbits_t nsipv4; + dns_rpz_zbits_t nsipv6; + dns_rpz_zbits_t nsip; + dns_rpz_zbits_t qname_skip_recurse; +}; + +/* + * Policy options + */ +typedef struct dns_rpz_popt dns_rpz_popt_t; +struct dns_rpz_popt { + dns_rpz_zbits_t no_rd_ok; + dns_rpz_zbits_t no_log; + dns_rpz_zbits_t nsip_on; + dns_rpz_zbits_t nsdname_on; + bool dnsrps_enabled; + bool break_dnssec; + bool qname_wait_recurse; + bool nsip_wait_recurse; + bool nsdname_wait_recurse; + unsigned int min_ns_labels; + dns_rpz_num_t num_zones; +}; + +/* + * Response policy zones known to a view. + */ +struct dns_rpz_zones { + unsigned int magic; + isc_refcount_t references; + isc_mem_t *mctx; + isc_taskmgr_t *taskmgr; + isc_timermgr_t *timermgr; + isc_task_t *updater; + + dns_rpz_popt_t p; + dns_rpz_zone_t *zones[DNS_RPZ_MAX_ZONES]; + dns_rpz_triggers_t triggers[DNS_RPZ_MAX_ZONES]; + + /* + * RPZ policy version number. + * It is initially 0 and it increases whenever the server is + * reconfigured with new zones or policy. + */ + int rpz_ver; + + dns_rpz_zbits_t defined; + + /* + * The set of records for a policy zone are in one of these states: + * never loaded load_begun=0 have=0 + * during initial loading load_begun=1 have=0 + * and rbtdb->rpzsp == rbtdb->load_rpzsp + * after good load load_begun=1 have!=0 + * after failed initial load load_begun=1 have=0 + * and rbtdb->load_rpzsp == NULL + * reloading after failure load_begun=1 have=0 + * reloading after success + * main rpzs load_begun=1 have!=0 + * load rpzs load_begun=1 have=0 + */ + dns_rpz_zbits_t load_begun; + dns_rpz_have_t have; + + /* + * total_triggers maintains the total number of triggers in all + * policy zones in the view. It is only used to print summary + * statistics after a zone load of how the trigger counts + * changed. + */ + dns_rpz_triggers_t total_triggers; + + /* + * One lock for short term read-only search that guarantees the + * consistency of the pointers. + * A second lock for maintenance that guarantees no other thread + * is adding or deleting nodes. + */ + isc_rwlock_t search_lock; + isc_mutex_t maint_lock; + + bool shuttingdown; + + dns_rpz_cidr_node_t *cidr; + dns_rbt_t *rbt; + + /* + * DNSRPZ librpz configuration string and handle on librpz connection + */ + char *rps_cstr; + size_t rps_cstr_size; + struct librpz_client *rps_client; +}; + +/* + * context for finding the best policy + */ +typedef struct { + unsigned int state; +#define DNS_RPZ_REWRITTEN 0x0001 +#define DNS_RPZ_DONE_CLIENT_IP 0x0002 /* client IP address checked */ +#define DNS_RPZ_DONE_QNAME 0x0004 /* qname checked */ +#define DNS_RPZ_DONE_QNAME_IP 0x0008 /* IP addresses of qname checked */ +#define DNS_RPZ_DONE_NSDNAME 0x0010 /* NS name missed; checking addresses */ +#define DNS_RPZ_DONE_IPv4 0x0020 +#define DNS_RPZ_RECURSING 0x0040 +#define DNS_RPZ_ACTIVE 0x0080 + /* + * Best match so far. + */ + struct { + dns_rpz_type_t type; + dns_rpz_zone_t *rpz; + dns_rpz_prefix_t prefix; + dns_rpz_policy_t policy; + dns_ttl_t ttl; + isc_result_t result; + dns_zone_t *zone; + dns_db_t *db; + dns_dbversion_t *version; + dns_dbnode_t *node; + dns_rdataset_t *rdataset; + } m; + /* + * State for chasing IP addresses and NS names including recursion. + */ + struct { + unsigned int label; + dns_db_t *db; + dns_rdataset_t *ns_rdataset; + dns_rdatatype_t r_type; + isc_result_t r_result; + dns_rdataset_t *r_rdataset; + } r; + + /* + * State of real query while recursing for NSIP or NSDNAME. + */ + struct { + isc_result_t result; + bool is_zone; + bool authoritative; + dns_zone_t *zone; + dns_db_t *db; + dns_dbnode_t *node; + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; + dns_rdatatype_t qtype; + } q; + + /* + * A copy of the 'have' and 'p' structures and the RPZ + * policy version as of the beginning of RPZ processing, + * used to avoid problems when policy is updated while + * RPZ recursion is ongoing. + */ + dns_rpz_have_t have; + dns_rpz_popt_t popt; + int rpz_ver; + + /* + * Shim db between BIND and DNRPS librpz. + */ + dns_db_t *rpsdb; + + /* + * p_name: current policy owner name + * r_name: recursing for this name to possible policy triggers + * f_name: saved found name from before recursion + */ + dns_name_t *p_name; + dns_name_t *r_name; + dns_name_t *fname; + dns_fixedname_t _p_namef; + dns_fixedname_t _r_namef; + dns_fixedname_t _fnamef; +} dns_rpz_st_t; + +#define DNS_RPZ_TTL_DEFAULT 5 +#define DNS_RPZ_MAX_TTL_DEFAULT DNS_RPZ_TTL_DEFAULT +#define DNS_RPZ_MINUPDATEINTERVAL_DEFAULT 60 + +/* + * So various response policy zone messages can be turned up or down. + */ +#define DNS_RPZ_ERROR_LEVEL ISC_LOG_WARNING +#define DNS_RPZ_INFO_LEVEL ISC_LOG_INFO +#define DNS_RPZ_DEBUG_LEVEL1 ISC_LOG_DEBUG(1) +#define DNS_RPZ_DEBUG_LEVEL2 ISC_LOG_DEBUG(2) +#define DNS_RPZ_DEBUG_LEVEL3 ISC_LOG_DEBUG(3) +#define DNS_RPZ_DEBUG_QUIET (DNS_RPZ_DEBUG_LEVEL3 + 1) + +const char * +dns_rpz_type2str(dns_rpz_type_t type); + +dns_rpz_policy_t +dns_rpz_str2policy(const char *str); + +const char * +dns_rpz_policy2str(dns_rpz_policy_t policy); + +dns_rpz_policy_t +dns_rpz_decode_cname(dns_rpz_zone_t *rpz, dns_rdataset_t *rdataset, + dns_name_t *selfname); + +isc_result_t +dns_rpz_new_zones(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr, char *rps_cstr, + size_t rps_cstr_size, dns_rpz_zones_t **rpzsp); + +isc_result_t +dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp); + +isc_result_t +dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg); + +void +dns_rpz_zones_shutdown(dns_rpz_zones_t *rpzs); + +#ifdef DNS_RPZ_TRACE +/* Compatibility macros */ +#define dns_rpz_detach_rpzs(rpzsp) \ + dns_rpz_zones__detach(rpzsp, __func__, __FILE__, __LINE__) +#define dns_rpz_attach_rpzs(rpzs, rpzsp) \ + dns_rpz_zones__attach(rpzs, rpzsp, __func__, __FILE__, __LINE__) +#define dns_rpz_ref_rpzs(ptr) \ + dns_rpz_zones__ref(ptr, __func__, __FILE__, __LINE__) +#define dns_rpz_unref_rpzs(ptr) \ + dns_rpz_zones__unref(ptr, __func__, __FILE__, __LINE__) +#define dns_rpz_shutdown_rpzs(rpzs) \ + dns_rpz_zones_shutdown(rpzs, __func__, __FILE__, __LINE__) + +ISC_REFCOUNT_TRACE_DECL(dns_rpz_zones); +#else +/* Compatibility macros */ +#define dns_rpz_detach_rpzs(rpzsp) dns_rpz_zones_detach(rpzsp) +#define dns_rpz_attach_rpzs(rpzs, rpzsp) dns_rpz_zones_attach(rpzs, rpzsp) +#define dns_rpz_shutdown_rpzs(rpzsp) dns_rpz_zones_shutdown(rpzsp) +#define dns_rpz_ref_rpzs(ptr) dns_rpz_zones_ref(ptr) +#define dns_rpz_unref_rpzs(ptr) dns_rpz_zones_unref(ptr) + +ISC_REFCOUNT_DECL(dns_rpz_zones); +#endif + +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); + +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_LANG_ENDDECLS -- cgit v1.2.3