1/*	$NetBSD: rpz.h,v 1.10 2024/02/21 22:52:10 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16#pragma once
17
18/* Add -DDNS_RPZ_TRACE=1 to CFLAGS for detailed reference tracing */
19
20#include <inttypes.h>
21#include <stdbool.h>
22
23#include <isc/deprecated.h>
24#include <isc/event.h>
25#include <isc/ht.h>
26#include <isc/lang.h>
27#include <isc/refcount.h>
28#include <isc/rwlock.h>
29#include <isc/time.h>
30#include <isc/timer.h>
31
32#include <dns/fixedname.h>
33#include <dns/rdata.h>
34#include <dns/types.h>
35
36ISC_LANG_BEGINDECLS
37
38#define DNS_RPZ_PREFIX "rpz-"
39/*
40 * Sub-zones of various trigger types.
41 */
42#define DNS_RPZ_CLIENT_IP_ZONE DNS_RPZ_PREFIX "client-ip"
43#define DNS_RPZ_IP_ZONE	       DNS_RPZ_PREFIX "ip"
44#define DNS_RPZ_NSIP_ZONE      DNS_RPZ_PREFIX "nsip"
45#define DNS_RPZ_NSDNAME_ZONE   DNS_RPZ_PREFIX "nsdname"
46/*
47 * Special policies.
48 */
49#define DNS_RPZ_PASSTHRU_NAME DNS_RPZ_PREFIX "passthru"
50#define DNS_RPZ_DROP_NAME     DNS_RPZ_PREFIX "drop"
51#define DNS_RPZ_TCP_ONLY_NAME DNS_RPZ_PREFIX "tcp-only"
52
53typedef uint8_t dns_rpz_prefix_t;
54
55typedef enum {
56	DNS_RPZ_TYPE_BAD,
57	DNS_RPZ_TYPE_CLIENT_IP,
58	DNS_RPZ_TYPE_QNAME,
59	DNS_RPZ_TYPE_IP,
60	DNS_RPZ_TYPE_NSDNAME,
61	DNS_RPZ_TYPE_NSIP
62} dns_rpz_type_t;
63
64/*
65 * Require DNS_RPZ_POLICY_PASSTHRU < DNS_RPZ_POLICY_DROP
66 * < DNS_RPZ_POLICY_TCP_ONLY DNS_RPZ_POLICY_NXDOMAIN < DNS_RPZ_POLICY_NODATA
67 * < DNS_RPZ_POLICY_CNAME to choose among competing policies.
68 */
69typedef enum {
70	DNS_RPZ_POLICY_GIVEN = 0,    /* 'given': what policy record says */
71	DNS_RPZ_POLICY_DISABLED = 1, /* log what would have happened */
72	DNS_RPZ_POLICY_PASSTHRU = 2, /* 'passthru': do not rewrite */
73	DNS_RPZ_POLICY_DROP = 3,     /* 'drop': do not respond */
74	DNS_RPZ_POLICY_TCP_ONLY = 4, /* 'tcp-only': answer UDP with TC=1 */
75	DNS_RPZ_POLICY_NXDOMAIN = 5, /* 'nxdomain': answer with NXDOMAIN */
76	DNS_RPZ_POLICY_NODATA = 6,   /* 'nodata': answer with ANCOUNT=0 */
77	DNS_RPZ_POLICY_CNAME = 7,    /* 'cname x': answer with x's rrsets */
78	DNS_RPZ_POLICY_DNS64,	     /* Apply DN64 to the A rewrite */
79	DNS_RPZ_POLICY_RECORD,
80	DNS_RPZ_POLICY_WILDCNAME,
81	DNS_RPZ_POLICY_MISS,
82	DNS_RPZ_POLICY_ERROR
83} dns_rpz_policy_t;
84
85typedef uint8_t dns_rpz_num_t;
86
87#define DNS_RPZ_MAX_ZONES 64
88/*
89 * Type dns_rpz_zbits_t must be an unsigned int wide enough to contain
90 * at least DNS_RPZ_MAX_ZONES bits.
91 */
92typedef uint64_t dns_rpz_zbits_t;
93
94#define DNS_RPZ_ALL_ZBITS ((dns_rpz_zbits_t)-1)
95
96#define DNS_RPZ_INVALID_NUM DNS_RPZ_MAX_ZONES
97
98#define DNS_RPZ_ZBIT(n) (((dns_rpz_zbits_t)1) << (dns_rpz_num_t)(n))
99
100/*
101 * Mask of the specified and higher numbered policy zones
102 * Avoid hassles with (1<<33) or (1<<65)
103 */
104#define DNS_RPZ_ZMASK(n)                                     \
105	((dns_rpz_zbits_t)((((n) >= DNS_RPZ_MAX_ZONES - 1)   \
106				    ? 0                      \
107				    : (1ULL << ((n) + 1))) - \
108			   1))
109
110/*
111 * The trigger counter type.
112 */
113typedef size_t dns_rpz_trigger_counter_t;
114
115/*
116 * The number of triggers of each type in a response policy zone.
117 */
118typedef struct dns_rpz_triggers dns_rpz_triggers_t;
119struct dns_rpz_triggers {
120	dns_rpz_trigger_counter_t client_ipv4;
121	dns_rpz_trigger_counter_t client_ipv6;
122	dns_rpz_trigger_counter_t qname;
123	dns_rpz_trigger_counter_t ipv4;
124	dns_rpz_trigger_counter_t ipv6;
125	dns_rpz_trigger_counter_t nsdname;
126	dns_rpz_trigger_counter_t nsipv4;
127	dns_rpz_trigger_counter_t nsipv6;
128};
129
130/*
131 * A single response policy zone.
132 */
133typedef struct dns_rpz_zone  dns_rpz_zone_t;
134typedef struct dns_rpz_zones dns_rpz_zones_t;
135
136struct dns_rpz_zone {
137	unsigned int magic;
138
139	dns_rpz_num_t	 num;	    /* ordinal in list of policy zones */
140	dns_name_t	 origin;    /* Policy zone name */
141	dns_name_t	 client_ip; /* DNS_RPZ_CLIENT_IP_ZONE.origin. */
142	dns_name_t	 ip;	    /* DNS_RPZ_IP_ZONE.origin. */
143	dns_name_t	 nsdname;   /* DNS_RPZ_NSDNAME_ZONE.origin */
144	dns_name_t	 nsip;	    /* DNS_RPZ_NSIP_ZONE.origin. */
145	dns_name_t	 passthru;  /* DNS_RPZ_PASSTHRU_NAME. */
146	dns_name_t	 drop;	    /* DNS_RPZ_DROP_NAME. */
147	dns_name_t	 tcp_only;  /* DNS_RPZ_TCP_ONLY_NAME. */
148	dns_name_t	 cname;	    /* override value for ..._CNAME */
149	dns_ttl_t	 max_policy_ttl;
150	dns_rpz_policy_t policy; /* DNS_RPZ_POLICY_GIVEN or override */
151
152	uint32_t  min_update_interval;	/* minimal interval between updates */
153	isc_ht_t *nodes;		/* entries in zone */
154	dns_rpz_zones_t *rpzs;		/* owner */
155	isc_time_t	 lastupdated;	/* last time the zone was processed */
156	bool		 updatepending; /* there is an update pending */
157	bool		 updaterunning; /* there is an update running */
158	isc_result_t	 updateresult;	/* result from the offloaded work */
159	dns_db_t	*db;		/* zones database */
160	dns_dbversion_t *dbversion;	/* version we will be updating to */
161	dns_db_t	*updb;		/* zones database we're working on */
162	dns_dbversion_t *updbversion;	/* version we're working on */
163	bool		 addsoa;	/* add soa to the additional section */
164	isc_timer_t	*updatetimer;
165	isc_event_t	 updateevent;
166};
167
168/*
169 * Radix tree node for response policy IP addresses
170 */
171typedef struct dns_rpz_cidr_node dns_rpz_cidr_node_t;
172
173/*
174 * Bitfields indicating which policy zones have policies of
175 * which type.
176 */
177typedef struct dns_rpz_have dns_rpz_have_t;
178struct dns_rpz_have {
179	dns_rpz_zbits_t client_ipv4;
180	dns_rpz_zbits_t client_ipv6;
181	dns_rpz_zbits_t client_ip;
182	dns_rpz_zbits_t qname;
183	dns_rpz_zbits_t ipv4;
184	dns_rpz_zbits_t ipv6;
185	dns_rpz_zbits_t ip;
186	dns_rpz_zbits_t nsdname;
187	dns_rpz_zbits_t nsipv4;
188	dns_rpz_zbits_t nsipv6;
189	dns_rpz_zbits_t nsip;
190	dns_rpz_zbits_t qname_skip_recurse;
191};
192
193/*
194 * Policy options
195 */
196typedef struct dns_rpz_popt dns_rpz_popt_t;
197struct dns_rpz_popt {
198	dns_rpz_zbits_t no_rd_ok;
199	dns_rpz_zbits_t no_log;
200	dns_rpz_zbits_t nsip_on;
201	dns_rpz_zbits_t nsdname_on;
202	bool		dnsrps_enabled;
203	bool		break_dnssec;
204	bool		qname_wait_recurse;
205	bool		nsip_wait_recurse;
206	bool		nsdname_wait_recurse;
207	unsigned int	min_ns_labels;
208	dns_rpz_num_t	num_zones;
209};
210
211/*
212 * Response policy zones known to a view.
213 */
214struct dns_rpz_zones {
215	unsigned int	magic;
216	isc_refcount_t	references;
217	isc_mem_t      *mctx;
218	isc_taskmgr_t  *taskmgr;
219	isc_timermgr_t *timermgr;
220	isc_task_t     *updater;
221
222	dns_rpz_popt_t	   p;
223	dns_rpz_zone_t	  *zones[DNS_RPZ_MAX_ZONES];
224	dns_rpz_triggers_t triggers[DNS_RPZ_MAX_ZONES];
225
226	/*
227	 * RPZ policy version number.
228	 * It is initially 0 and it increases whenever the server is
229	 * reconfigured with new zones or policy.
230	 */
231	int rpz_ver;
232
233	dns_rpz_zbits_t defined;
234
235	/*
236	 * The set of records for a policy zone are in one of these states:
237	 *	never loaded		    load_begun=0  have=0
238	 *	during initial loading	    load_begun=1  have=0
239	 *				and rbtdb->rpzsp == rbtdb->load_rpzsp
240	 *	after good load		    load_begun=1  have!=0
241	 *	after failed initial load   load_begun=1  have=0
242	 *				and rbtdb->load_rpzsp == NULL
243	 *	reloading after failure	    load_begun=1  have=0
244	 *	reloading after success
245	 *		main rpzs	    load_begun=1  have!=0
246	 *		load rpzs	    load_begun=1  have=0
247	 */
248	dns_rpz_zbits_t load_begun;
249	dns_rpz_have_t	have;
250
251	/*
252	 * total_triggers maintains the total number of triggers in all
253	 * policy zones in the view. It is only used to print summary
254	 * statistics after a zone load of how the trigger counts
255	 * changed.
256	 */
257	dns_rpz_triggers_t total_triggers;
258
259	/*
260	 * One lock for short term read-only search that guarantees the
261	 * consistency of the pointers.
262	 * A second lock for maintenance that guarantees no other thread
263	 * is adding or deleting nodes.
264	 */
265	isc_rwlock_t search_lock;
266	isc_mutex_t  maint_lock;
267
268	bool shuttingdown;
269
270	dns_rpz_cidr_node_t *cidr;
271	dns_rbt_t	    *rbt;
272
273	/*
274	 * DNSRPZ librpz configuration string and handle on librpz connection
275	 */
276	char		     *rps_cstr;
277	size_t		      rps_cstr_size;
278	struct librpz_client *rps_client;
279};
280
281/*
282 * context for finding the best policy
283 */
284typedef struct {
285	unsigned int state;
286#define DNS_RPZ_REWRITTEN      0x0001
287#define DNS_RPZ_DONE_CLIENT_IP 0x0002 /* client IP address checked */
288#define DNS_RPZ_DONE_QNAME     0x0004 /* qname checked */
289#define DNS_RPZ_DONE_QNAME_IP  0x0008 /* IP addresses of qname checked */
290#define DNS_RPZ_DONE_NSDNAME   0x0010 /* NS name missed; checking addresses */
291#define DNS_RPZ_DONE_IPv4      0x0020
292#define DNS_RPZ_RECURSING      0x0040
293#define DNS_RPZ_ACTIVE	       0x0080
294	/*
295	 * Best match so far.
296	 */
297	struct {
298		dns_rpz_type_t	 type;
299		dns_rpz_zone_t	*rpz;
300		dns_rpz_prefix_t prefix;
301		dns_rpz_policy_t policy;
302		dns_ttl_t	 ttl;
303		isc_result_t	 result;
304		dns_zone_t	*zone;
305		dns_db_t	*db;
306		dns_dbversion_t *version;
307		dns_dbnode_t	*node;
308		dns_rdataset_t	*rdataset;
309	} m;
310	/*
311	 * State for chasing IP addresses and NS names including recursion.
312	 */
313	struct {
314		unsigned int	label;
315		dns_db_t       *db;
316		dns_rdataset_t *ns_rdataset;
317		dns_rdatatype_t r_type;
318		isc_result_t	r_result;
319		dns_rdataset_t *r_rdataset;
320	} r;
321
322	/*
323	 * State of real query while recursing for NSIP or NSDNAME.
324	 */
325	struct {
326		isc_result_t	result;
327		bool		is_zone;
328		bool		authoritative;
329		dns_zone_t     *zone;
330		dns_db_t       *db;
331		dns_dbnode_t   *node;
332		dns_rdataset_t *rdataset;
333		dns_rdataset_t *sigrdataset;
334		dns_rdatatype_t qtype;
335	} q;
336
337	/*
338	 * A copy of the 'have' and 'p' structures and the RPZ
339	 * policy version as of the beginning of RPZ processing,
340	 * used to avoid problems when policy is updated while
341	 * RPZ recursion is ongoing.
342	 */
343	dns_rpz_have_t have;
344	dns_rpz_popt_t popt;
345	int	       rpz_ver;
346
347	/*
348	 * Shim db between BIND and DNRPS librpz.
349	 */
350	dns_db_t *rpsdb;
351
352	/*
353	 * p_name: current policy owner name
354	 * r_name: recursing for this name to possible policy triggers
355	 * f_name: saved found name from before recursion
356	 */
357	dns_name_t     *p_name;
358	dns_name_t     *r_name;
359	dns_name_t     *fname;
360	dns_fixedname_t _p_namef;
361	dns_fixedname_t _r_namef;
362	dns_fixedname_t _fnamef;
363} dns_rpz_st_t;
364
365#define DNS_RPZ_TTL_DEFAULT		  5
366#define DNS_RPZ_MAX_TTL_DEFAULT		  DNS_RPZ_TTL_DEFAULT
367#define DNS_RPZ_MINUPDATEINTERVAL_DEFAULT 60
368
369/*
370 * So various response policy zone messages can be turned up or down.
371 */
372#define DNS_RPZ_ERROR_LEVEL  ISC_LOG_WARNING
373#define DNS_RPZ_INFO_LEVEL   ISC_LOG_INFO
374#define DNS_RPZ_DEBUG_LEVEL1 ISC_LOG_DEBUG(1)
375#define DNS_RPZ_DEBUG_LEVEL2 ISC_LOG_DEBUG(2)
376#define DNS_RPZ_DEBUG_LEVEL3 ISC_LOG_DEBUG(3)
377#define DNS_RPZ_DEBUG_QUIET  (DNS_RPZ_DEBUG_LEVEL3 + 1)
378
379const char *
380dns_rpz_type2str(dns_rpz_type_t type);
381
382dns_rpz_policy_t
383dns_rpz_str2policy(const char *str);
384
385const char *
386dns_rpz_policy2str(dns_rpz_policy_t policy);
387
388dns_rpz_policy_t
389dns_rpz_decode_cname(dns_rpz_zone_t *rpz, dns_rdataset_t *rdataset,
390		     dns_name_t *selfname);
391
392isc_result_t
393dns_rpz_new_zones(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
394		  isc_timermgr_t *timermgr, char *rps_cstr,
395		  size_t rps_cstr_size, dns_rpz_zones_t **rpzsp);
396
397isc_result_t
398dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp);
399
400isc_result_t
401dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg);
402
403void
404dns_rpz_zones_shutdown(dns_rpz_zones_t *rpzs);
405
406#ifdef DNS_RPZ_TRACE
407/* Compatibility macros */
408#define dns_rpz_detach_rpzs(rpzsp) \
409	dns_rpz_zones__detach(rpzsp, __func__, __FILE__, __LINE__)
410#define dns_rpz_attach_rpzs(rpzs, rpzsp) \
411	dns_rpz_zones__attach(rpzs, rpzsp, __func__, __FILE__, __LINE__)
412#define dns_rpz_ref_rpzs(ptr) \
413	dns_rpz_zones__ref(ptr, __func__, __FILE__, __LINE__)
414#define dns_rpz_unref_rpzs(ptr) \
415	dns_rpz_zones__unref(ptr, __func__, __FILE__, __LINE__)
416#define dns_rpz_shutdown_rpzs(rpzs) \
417	dns_rpz_zones_shutdown(rpzs, __func__, __FILE__, __LINE__)
418
419ISC_REFCOUNT_TRACE_DECL(dns_rpz_zones);
420#else
421/* Compatibility macros */
422#define dns_rpz_detach_rpzs(rpzsp)	 dns_rpz_zones_detach(rpzsp)
423#define dns_rpz_attach_rpzs(rpzs, rpzsp) dns_rpz_zones_attach(rpzs, rpzsp)
424#define dns_rpz_shutdown_rpzs(rpzsp)	 dns_rpz_zones_shutdown(rpzsp)
425#define dns_rpz_ref_rpzs(ptr)		 dns_rpz_zones_ref(ptr)
426#define dns_rpz_unref_rpzs(ptr)		 dns_rpz_zones_unref(ptr)
427
428ISC_REFCOUNT_DECL(dns_rpz_zones);
429#endif
430
431dns_rpz_num_t
432dns_rpz_find_ip(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type,
433		dns_rpz_zbits_t zbits, const isc_netaddr_t *netaddr,
434		dns_name_t *ip_name, dns_rpz_prefix_t *prefixp);
435
436dns_rpz_zbits_t
437dns_rpz_find_name(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type,
438		  dns_rpz_zbits_t zbits, dns_name_t *trig_name);
439
440ISC_LANG_ENDDECLS
441