summaryrefslogtreecommitdiffstats
path: root/lib/dns/include/dns/rpz.h
blob: 364ad925f5db2b4566a455c5f7d0b904941a5784 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
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 <inttypes.h>
#include <stdbool.h>

#include <isc/deprecated.h>
#include <isc/event.h>
#include <isc/ht.h>
#include <isc/lang.h>
#include <isc/refcount.h>
#include <isc/rwlock.h>
#include <isc/time.h>
#include <isc/timer.h>

#include <dns/fixedname.h>
#include <dns/rdata.h>
#include <dns/types.h>

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