File: api.h

package info (click to toggle)
knot-resolver 6.0.17-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 16,376 kB
  • sloc: javascript: 42,732; ansic: 40,311; python: 12,580; cpp: 2,121; sh: 1,988; xml: 193; makefile: 181
file content (287 lines) | stat: -rw-r--r-- 10,191 bytes parent folder | download
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
/*  Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
 *  SPDX-License-Identifier: GPL-3.0-or-later
 */
#pragma once

#include "lib/defines.h"
#include "lib/proto.h"
struct kr_query;
struct kr_request;
struct knot_pkt;
struct sockaddr;
#include <syslog.h>
#include <lib/utils.h>
#include <libknot/db/db.h>

/// Storage for a tag-set.  It's a bitmap, so 64 tags are supported now.
typedef uint64_t kr_rule_tags_t;
#define KR_RULE_TAGS_ALL ((kr_rule_tags_t)0)
/// Tags "capacity", i.e. numbered from 0 to _CAP - 1.
#define KR_RULE_TAGS_CAP (sizeof(kr_rule_tags_t) * 8)

/// Extra options for a rule (not for forwarding)
struct kr_rule_opts {
	/// Degree of severity for the rule;  FIXME: granularity, defaults, etc.
	uint8_t score : 4;

	bool log_ip : 1, log_name : 1;
	// +maybe log rule/QNAME/something
	/// Log level: 0 = debug, 1 = info, ...
	uint8_t log_level : 2;

	/** Maybe 2 bits: (unset), blocked, censored, filtered
	    https://www.rfc-editor.org/rfc/rfc8914.html#name-extended-dns-error-code-15-
	*/
	uint8_t ede_code : 2;
	/** Maybe 3 bits: (unset), Malware, Phishing, ... from
	    https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-structured-dns-error#name-new-registry-for-dns-sub-er
	*/
	uint8_t ede_sub : 3;
};
typedef struct kr_rule_opts kr_rule_opts_t;
static_assert(sizeof(kr_rule_opts_t) == 2, "kr_rule_opts_t size changed unexpectedly");
/// Default opts; in particular used for the RFC-mandated special-use names
KR_EXPORT extern const kr_rule_opts_t KR_RULE_OPTS_DEFAULT;
enum { // Default minimal score of a rule to log/apply it.
	KR_RULE_SCORE_LOG     =  3,
	KR_RULE_SCORE_APPLY   =  6,
	KR_RULE_SCORE_DEFAULT = 10,
};

static inline int map_log_level(uint8_t ll)
{
	switch (ll) {
	case 0: return LOG_DEBUG;
	case 1: return LOG_INFO;
	case 2: return LOG_NOTICE;
	case 3: return LOG_WARNING;
	}
	return LOG_DEBUG; // shouldn't happen
}

/** Open the rule DB.
 *
 * You can call this to override the path or size (NULL/0 -> default)
 * or choose not to overwrite the DB with just the defaults.
 *
 * \return error code.  Not allowed if already open (EINVAL),
 * so this optional call has to come before writing anything into the DB. */
KR_EXPORT
int kr_rules_init(const char *path, size_t maxsize, bool overwrite);
/** kr_rules_init() but OK if already open, and not allowing to override defaults. */
KR_EXPORT
int kr_rules_init_ensure(void);

KR_EXPORT
void kr_rules_deinit(void);

/** Commit or abort changes done to the rule DB so far.
 *
 * Normally commit happens only on successfully loading a config file.
 * However, an advanced user may get in trouble e.g. if calling resolve() from there,
 * causing even an assertion failure.  In that case they might want to commit explicitly.
 *
 * If only read-only transaction is open, this will NOT reset it to the newest data.
 */
KR_EXPORT
int kr_rules_commit(bool accept);

/** Reset to the latest version of rules committed in the DB.
 *
 * Note that this is not always a good idea.  For example, the `forward` rules
 * now use data from both the DB and lua config, so reloading only the DB
 * may lead to weird behavior in some cases.
 * (Modifications will also do this, as you can only modify the latest DB.)
 */
KR_EXPORT
int kr_rules_reset(void);

/** Try answering the query from local data; WIP: otherwise determine data source overrides.
 *
 * \return kr_error() on errors, >0 if answered, 0 otherwise (also when forwarding)
 *
 * FIXME: we probably want to ensure AA flags in answer as appropriate.
 *   Perhaps approach it like AD?  Tweak flags in ranked_rr_array_entry
 *   and at the end decide whether to set AA=1?
 */
int kr_rule_local_data_answer(struct kr_query *qry, struct knot_pkt *pkt);

/** Set up nameserver+cut if overridden by policy.  \return kr_error() */
int kr_rule_data_src_check(struct kr_query *qry, struct knot_pkt *pkt);

/** Select the view action to perform.
 *
 * \param selected The action string from kr_view_insert_action()
 * \return 0 or negative error code, in particular kr_error(ENOENT)
 */
KR_EXPORT
int kr_view_select_action(const struct kr_request *req, knot_db_val_t *selected);


/** Default TTL for answers from local data rules.
 *
 * This applies to rules defined by the user, not the default rules.
 * Some types of rules save space when using this default.
 * This definition exists mainly for usage from lua.
 */
KR_EXPORT extern
const uint32_t KR_RULE_TTL_DEFAULT;

/* APIs to modify the rule DB.
 *
 * FIXME:
 *  - overwriting semantics; often even the API docs is wrong here ATM
 *  - a way to read/modify a rule?
 */

/** Add a local data rule.
 *
 * Into the default rule-set ATM.
 * Special NODATA case: use a type with zero records (TTL matters).
 *   You can do that either for particular types or for CNAME
 *   (meaning all types unspecified by other exact rule matches).
 */
KR_EXPORT
int kr_rule_local_data_ins(const knot_rrset_t *rrs, const knot_rdataset_t *sig_rds,
				kr_rule_tags_t tags, kr_rule_opts_t opts);
/** Merge RRs into a local data rule.
 *
 * - FIXME: with multiple tags variants for the same name-type pair,
 *     you typically end up with a single RR per RRset
 * - RRSIGs get dropped, if any were attached.
 * - We assume that this is called with a RW transaction open already,
 *   which is always true in normal usage (long RW txn covering whole config).
 * - TODO: what if opts don't match?
 */
KR_EXPORT
int kr_rule_local_data_merge(const knot_rrset_t *rrs, kr_rule_tags_t tags, kr_rule_opts_t opts);

/** Add a name-address pair into rules.
 *
 * - both forward and reverse mapping is added
 * - merging is used; see kr_rule_local_data_merge()
 * - NODATA is optionally inserted
 */
KR_EXPORT
int kr_rule_local_address(const char *name, const char *addr, bool use_nodata,
				uint32_t ttl, kr_rule_tags_t tags, kr_rule_opts_t opts);

/** For a given name, remove one address  ##or all of them (if == NULL).
 *
 * Also remove the corresponding reverse record and (optionally) NODATA mark.
 * Bug: it removes the whole forward RRset.
 */
KR_EXPORT
int kr_rule_local_address_del(const char *name, const char *addr,
				bool use_nodata, kr_rule_tags_t tags);

/** Load name-address pairs into rules from a hosts-like file.
 *
 * Same as kr_rule_data_address() but from a file.
 */
KR_EXPORT
int kr_rule_local_hosts(const char *path, bool use_nodata, uint32_t ttl,
			kr_rule_tags_t tags, kr_rule_opts_t opts);

/** Remove a local data rule.
 *
 * \return the number of deleted rules or error < 0
 *
 * TODO: some other matching than name+type?  Currently `tags` is unused; match all types?
 * (would be useful in del_pair)
 */
KR_EXPORT
int kr_rule_local_data_del(const knot_rrset_t *rrs, kr_rule_tags_t tags);


enum kr_rule_sub_t {
	/// Empty zone, i.e. with SOA and NS
	KR_RULE_SUB_EMPTY = 1,
	/// NXDOMAIN for everything; TODO: SOA owner is hard.
	KR_RULE_SUB_NXDOMAIN,
	/// NODATA answers but not on exact name (e.g. it's similar to DNAME)
	KR_RULE_SUB_NODATA,
	/// Redirect: anything beneath has the same data as apex (except NS+SOA).
	KR_RULE_SUB_REDIRECT,
	/// Act similar to DNAME: rebase everything underneath by generated CNAMEs.
	KR_RULE_SUB_DNAME,
};
/** Insert a simple sub-tree rule.
 *
 * - into the default rule-set
 * - SOA and NS for generated answers aren't overridable.
 * - type: you can't use _DNAME via this function; insert it by kr_rule_local_data_ins()
 */
KR_EXPORT
int kr_rule_local_subtree(const knot_dname_t *apex, enum kr_rule_sub_t type,
			  uint32_t ttl, kr_rule_tags_t tags, kr_rule_opts_t opts);

/** Insert a view action into the default ruleset.
 *
 * \param subnet String specifying a subnet, e.g. "192.168.0.0/16".
 * \param dst_subnet String specifying a subnet to be matched by the destination address. (or empty/NULL)
 * \param protos Set of transport protocols. (or 0 to always match)
 * \param action Currently a string to execute, like in old policies, e.g. `policy.REFUSE`
 *
 * TODO: improve? (return code, warning, ...)  Internal queries never get matched.
 *
 * The concept of chain actions isn't respected; at most one action is chosen.
 * The winner needs to fulfill all conditions.  Closer subnet match is preferred,
 * but otherwise the priority is unspecified (it is deterministic, though).
 *
 * There's no detection of action rules that clash in this way,
 * even if all conditions match exactly.
 * TODO we might consider some overwriting semantics,
 *   but the additional conditions make that harder.
 */
KR_EXPORT
int kr_view_insert_action(const char *subnet, const char *dst_subnet,
			kr_proto_set protos, const char *action);

/** Add a tag by name into a tag-set variable.
 *
 * It also ensures allocation of tag names in the DB, etc.
 */
KR_EXPORT
int kr_rule_tag_add(const char *tag, kr_rule_tags_t *tagset);


struct kr_rule_zonefile_config {
	const char *filename; /// NULL if specifying input_str instead
	const char *input_str; /// NULL if specifying filename instead
	size_t input_len; /// 0 for strlen(input_str)

	bool is_rpz; /// interpret either as RPZ or as plain RRsets
	bool nodata; /// TODO: implement
	kr_rule_tags_t tags; /// tag-set for the generated rule
	const char *origin; /// NULL or zone origin if known
	uint32_t ttl; /// default TTL
	kr_rule_opts_t opts; /// options for these rules
};
/** Load rules from some zonefile format, e.g. RPZ.  Code in ./zonefile.c */
KR_EXPORT
int kr_rule_zonefile(const struct kr_rule_zonefile_config *c);

/** Flatten an array of pointers to an array of union kr_sockaddr. (Lua helper) */
KR_EXPORT
void kr_rule_coalesce_targets(const struct sockaddr * targets[], void *data);

struct kr_rule_fwd_flags {
	/// Beware of ABI: this struct is memcpy'd to/from rule DB.
	bool
		is_auth : 1,
		is_tcp  : 1, /// forced TCP; unused, not needed for DoT
		is_nods : 1; /// disable local DNSSEC validation
};
typedef struct kr_rule_fwd_flags kr_rule_fwd_flags_t;
/** Insert/overwrite a forwarding rule.
 *
 * Into the default rule-set ATM.
 * \param targets NULL-terminated array.
 *
 * For is_auth == true we only support address, e.g. not specifying port or %interface.
 */
KR_EXPORT
int kr_rule_forward(const knot_dname_t *apex, kr_rule_fwd_flags_t flags,
			const struct sockaddr * targets[]);