xref: /freebsd/contrib/unbound/respip/respip.h (revision 865f46b255599c4a645e84a4cbb5ea7abdc0e207)
165b390aaSDag-Erling Smørgrav /*
265b390aaSDag-Erling Smørgrav  * respip/respip.h - IP-based response modification module
365b390aaSDag-Erling Smørgrav  */
465b390aaSDag-Erling Smørgrav 
565b390aaSDag-Erling Smørgrav /**
665b390aaSDag-Erling Smørgrav  * \file
765b390aaSDag-Erling Smørgrav  *
865b390aaSDag-Erling Smørgrav  * This file contains a module that selectively modifies query responses
965b390aaSDag-Erling Smørgrav  * based on their AAAA/A IP addresses.
1065b390aaSDag-Erling Smørgrav  */
1165b390aaSDag-Erling Smørgrav 
1265b390aaSDag-Erling Smørgrav #ifndef RESPIP_RESPIP_H
1365b390aaSDag-Erling Smørgrav #define RESPIP_RESPIP_H
1465b390aaSDag-Erling Smørgrav 
1565b390aaSDag-Erling Smørgrav #include "util/module.h"
1665b390aaSDag-Erling Smørgrav #include "services/localzone.h"
17091e9e46SCy Schubert #include "util/locks.h"
1865b390aaSDag-Erling Smørgrav 
1965b390aaSDag-Erling Smørgrav /**
20091e9e46SCy Schubert  * Conceptual set of IP addresses for response AAAA or A records that should
21091e9e46SCy Schubert  * trigger special actions.
2265b390aaSDag-Erling Smørgrav  */
23091e9e46SCy Schubert struct respip_set {
24091e9e46SCy Schubert 	struct regional* region;
25091e9e46SCy Schubert 	struct rbtree_type ip_tree;
26091e9e46SCy Schubert 	lock_rw_type lock;	/* lock on the respip tree */
27091e9e46SCy Schubert 	char* const* tagname;	/* shallow copy of tag names, for logging */
28091e9e46SCy Schubert 	int num_tags;		/* number of tagname entries */
29091e9e46SCy Schubert };
3065b390aaSDag-Erling Smørgrav 
31091e9e46SCy Schubert 
32091e9e46SCy Schubert /** An address span with response control information */
33091e9e46SCy Schubert struct resp_addr {
34091e9e46SCy Schubert 	/** node in address tree */
35091e9e46SCy Schubert 	struct addr_tree_node node;
36091e9e46SCy Schubert 	/** lock on the node item */
37091e9e46SCy Schubert 	lock_rw_type lock;
38091e9e46SCy Schubert 	/** tag bitlist */
39091e9e46SCy Schubert 	uint8_t* taglist;
40091e9e46SCy Schubert 	/** length of the taglist (in bytes) */
41091e9e46SCy Schubert 	size_t taglen;
42091e9e46SCy Schubert 	/** action for this address span */
43091e9e46SCy Schubert 	enum respip_action action;
44091e9e46SCy Schubert         /** "local data" for this node */
45091e9e46SCy Schubert 	struct ub_packed_rrset_key* data;
46091e9e46SCy Schubert };
47091e9e46SCy Schubert 
4865b390aaSDag-Erling Smørgrav 
4965b390aaSDag-Erling Smørgrav /**
5065b390aaSDag-Erling Smørgrav  * Forward declaration for the structure that represents a tree of view data.
5165b390aaSDag-Erling Smørgrav  */
52091e9e46SCy Schubert 
5365b390aaSDag-Erling Smørgrav struct views;
5465b390aaSDag-Erling Smørgrav 
5565b390aaSDag-Erling Smørgrav struct respip_addr_info;
5665b390aaSDag-Erling Smørgrav 
5765b390aaSDag-Erling Smørgrav /**
5865b390aaSDag-Erling Smørgrav  * Client-specific attributes that can affect IP-based actions.
5965b390aaSDag-Erling Smørgrav  * This is essentially a subset of acl_addr (except for respip_set) but
6065b390aaSDag-Erling Smørgrav  * defined as a separate structure to avoid dependency on the daemon-specific
6165b390aaSDag-Erling Smørgrav  * structure.
6265b390aaSDag-Erling Smørgrav  * respip_set is supposed to refer to the response-ip set for the global view.
6365b390aaSDag-Erling Smørgrav  */
6465b390aaSDag-Erling Smørgrav struct respip_client_info {
6565b390aaSDag-Erling Smørgrav 	uint8_t* taglist;
6665b390aaSDag-Erling Smørgrav 	size_t taglen;
6765b390aaSDag-Erling Smørgrav 	uint8_t* tag_actions;
6865b390aaSDag-Erling Smørgrav 	size_t tag_actions_size;
6965b390aaSDag-Erling Smørgrav 	struct config_strlist** tag_datas;
7065b390aaSDag-Erling Smørgrav 	size_t tag_datas_size;
7165b390aaSDag-Erling Smørgrav 	struct view* view;
7265b390aaSDag-Erling Smørgrav 	struct respip_set* respip_set;
7365b390aaSDag-Erling Smørgrav };
7465b390aaSDag-Erling Smørgrav 
7565b390aaSDag-Erling Smørgrav /**
7665b390aaSDag-Erling Smørgrav  * Data items representing the result of response-ip processing.
7765b390aaSDag-Erling Smørgrav  * Note: this structure currently only define a few members, but exists
7865b390aaSDag-Erling Smørgrav  * as a separate struct mainly for the convenience of custom extensions.
7965b390aaSDag-Erling Smørgrav  */
8065b390aaSDag-Erling Smørgrav struct respip_action_info {
8165b390aaSDag-Erling Smørgrav 	enum respip_action action;
82091e9e46SCy Schubert 	int rpz_used;
83091e9e46SCy Schubert 	int rpz_log;
84091e9e46SCy Schubert 	int rpz_disabled;
85091e9e46SCy Schubert 	char* log_name;
86091e9e46SCy Schubert 	int rpz_cname_override;
8765b390aaSDag-Erling Smørgrav 	struct respip_addr_info* addrinfo; /* set only for inform variants */
8865b390aaSDag-Erling Smørgrav };
8965b390aaSDag-Erling Smørgrav 
9065b390aaSDag-Erling Smørgrav /**
9165b390aaSDag-Erling Smørgrav   * Forward declaration for the structure that represents a node in the
9265b390aaSDag-Erling Smørgrav   * respip_set address tree
9365b390aaSDag-Erling Smørgrav   */
9465b390aaSDag-Erling Smørgrav struct resp_addr;
9565b390aaSDag-Erling Smørgrav 
9665b390aaSDag-Erling Smørgrav /**
9765b390aaSDag-Erling Smørgrav  * Create response IP set.
9865b390aaSDag-Erling Smørgrav  * @return new struct or NULL on error.
9965b390aaSDag-Erling Smørgrav  */
10065b390aaSDag-Erling Smørgrav struct respip_set* respip_set_create(void);
10165b390aaSDag-Erling Smørgrav 
10265b390aaSDag-Erling Smørgrav /**
10365b390aaSDag-Erling Smørgrav  * Delete response IP set.
10465b390aaSDag-Erling Smørgrav  * @param set: to delete.
10565b390aaSDag-Erling Smørgrav  */
10665b390aaSDag-Erling Smørgrav void respip_set_delete(struct respip_set* set);
10765b390aaSDag-Erling Smørgrav 
10865b390aaSDag-Erling Smørgrav /**
10965b390aaSDag-Erling Smørgrav  * Apply response-ip config settings to the global (default) view.
11065b390aaSDag-Erling Smørgrav  * It assumes exclusive access to set (no internal locks).
11165b390aaSDag-Erling Smørgrav  * @param set: processed global respip config data
11265b390aaSDag-Erling Smørgrav  * @param cfg: config data.
11365b390aaSDag-Erling Smørgrav  * @return 1 on success, 0 on error.
11465b390aaSDag-Erling Smørgrav  */
11565b390aaSDag-Erling Smørgrav int respip_global_apply_cfg(struct respip_set* set, struct config_file* cfg);
11665b390aaSDag-Erling Smørgrav 
11765b390aaSDag-Erling Smørgrav /**
11865b390aaSDag-Erling Smørgrav  * Apply response-ip config settings in named views.
11965b390aaSDag-Erling Smørgrav  * @param vs: view structures with processed config data
12065b390aaSDag-Erling Smørgrav  * @param cfg: config data.
12165b390aaSDag-Erling Smørgrav  * @param have_view_respip_cfg: set to true if any named view has respip
12265b390aaSDag-Erling Smørgrav  * 	configuration; otherwise set to false
12365b390aaSDag-Erling Smørgrav  * @return 1 on success, 0 on error.
12465b390aaSDag-Erling Smørgrav  */
12565b390aaSDag-Erling Smørgrav int respip_views_apply_cfg(struct views* vs, struct config_file* cfg,
12665b390aaSDag-Erling Smørgrav 	int* have_view_respip_cfg);
12765b390aaSDag-Erling Smørgrav 
12865b390aaSDag-Erling Smørgrav /**
12965b390aaSDag-Erling Smørgrav  * Merge two replies to build a complete CNAME chain.
13065b390aaSDag-Erling Smørgrav  * It appends the content of 'tgt_rep' to 'base_rep', assuming (but not
13165b390aaSDag-Erling Smørgrav  * checking) the former ends with a CNAME and the latter resolves its target.
13265b390aaSDag-Erling Smørgrav  * A merged new reply will be built using 'region' and *new_repp will point
13365b390aaSDag-Erling Smørgrav  * to the new one on success.
13465b390aaSDag-Erling Smørgrav  * If the target reply would also be subject to a response-ip action for
13565b390aaSDag-Erling Smørgrav  * 'cinfo', this function uses 'base_rep' as the merged reply, ignoring
13665b390aaSDag-Erling Smørgrav  * 'tgt_rep'.  This is for avoiding cases like a CNAME loop or failure of
13765b390aaSDag-Erling Smørgrav  * applying an action to an address.
13865b390aaSDag-Erling Smørgrav  * RRSIGs in 'tgt_rep' will be excluded in the merged reply, as the resulting
13965b390aaSDag-Erling Smørgrav  * reply is assumed to be faked due to a response-ip action and can't be
14065b390aaSDag-Erling Smørgrav  * considered secure in terms of DNSSEC.
14165b390aaSDag-Erling Smørgrav  * The caller must ensure that neither 'base_rep' nor 'tgt_rep' can be modified
14265b390aaSDag-Erling Smørgrav  * until this function returns.
14365b390aaSDag-Erling Smørgrav  * @param base_rep: the reply info containing an incomplete CNAME.
14465b390aaSDag-Erling Smørgrav  * @param qinfo: query info corresponding to 'base_rep'.
14565b390aaSDag-Erling Smørgrav  * @param tgt_rep: the reply info that completes the CNAME chain.
14665b390aaSDag-Erling Smørgrav  * @param cinfo: client info corresponding to 'base_rep'.
14765b390aaSDag-Erling Smørgrav  * @param must_validate: whether 'tgt_rep' must be DNSSEC-validated.
14865b390aaSDag-Erling Smørgrav  * @param new_repp: pointer placeholder for the merged reply.  will be intact
14965b390aaSDag-Erling Smørgrav  *   on error.
15065b390aaSDag-Erling Smørgrav  * @param region: allocator to build *new_repp.
151091e9e46SCy Schubert  * @param az: auth zones containing RPZ information.
15265b390aaSDag-Erling Smørgrav  * @return 1 on success, 0 on error.
15365b390aaSDag-Erling Smørgrav  */
15465b390aaSDag-Erling Smørgrav int respip_merge_cname(struct reply_info* base_rep,
15565b390aaSDag-Erling Smørgrav 	const struct query_info* qinfo, const struct reply_info* tgt_rep,
15665b390aaSDag-Erling Smørgrav 	const struct respip_client_info* cinfo, int must_validate,
157091e9e46SCy Schubert 	struct reply_info** new_repp, struct regional* region,
158091e9e46SCy Schubert 	struct auth_zones* az);
15965b390aaSDag-Erling Smørgrav 
16065b390aaSDag-Erling Smørgrav /**
16165b390aaSDag-Erling Smørgrav  * See if any IP-based action should apply to any IP address of AAAA/A answer
16265b390aaSDag-Erling Smørgrav  * record in the reply.  If so, apply the action.  In some cases it rewrites
16365b390aaSDag-Erling Smørgrav  * the reply rrsets, in which case *new_repp will point to the updated reply
16465b390aaSDag-Erling Smørgrav  * info.  Depending on the action, some of the rrsets in 'rep' will be
16565b390aaSDag-Erling Smørgrav  * shallow-copied into '*new_repp'; the caller must ensure that the rrsets
16665b390aaSDag-Erling Smørgrav  * in 'rep' are valid throughout the lifetime of *new_repp, and it must
16765b390aaSDag-Erling Smørgrav  * provide appropriate mutex if the rrsets can be shared by multiple threads.
16865b390aaSDag-Erling Smørgrav  * @param qinfo: query info corresponding to the reply.
16965b390aaSDag-Erling Smørgrav  * @param cinfo: client-specific info to identify the best matching action.
17065b390aaSDag-Erling Smørgrav  *   can be NULL.
17165b390aaSDag-Erling Smørgrav  * @param rep: original reply info.  must not be NULL.
17265b390aaSDag-Erling Smørgrav  * @param new_repp: can be set to the rewritten reply info (intact on failure).
17365b390aaSDag-Erling Smørgrav  * @param actinfo: result of response-ip processing
17465b390aaSDag-Erling Smørgrav  * @param alias_rrset: must not be NULL.
17565b390aaSDag-Erling Smørgrav  * @param search_only: if true, only check if an action would apply.  actionp
17665b390aaSDag-Erling Smørgrav  *   will be set (or intact) accordingly but the modified reply won't be built.
177091e9e46SCy Schubert  * @param az: auth zones containing RPZ information.
17865b390aaSDag-Erling Smørgrav  * @param region: allocator to build *new_repp.
179a39a5a69SCy Schubert  * @param rpz_passthru: keeps track of query state can have passthru that
180a39a5a69SCy Schubert  *   stops further rpz processing. Or NULL for cached answer processing.
18165b390aaSDag-Erling Smørgrav  * @return 1 on success, 0 on error.
18265b390aaSDag-Erling Smørgrav  */
18365b390aaSDag-Erling Smørgrav int respip_rewrite_reply(const struct query_info* qinfo,
18465b390aaSDag-Erling Smørgrav 	const struct respip_client_info* cinfo,
18565b390aaSDag-Erling Smørgrav 	const struct reply_info *rep, struct reply_info** new_repp,
18665b390aaSDag-Erling Smørgrav 	struct respip_action_info* actinfo,
18765b390aaSDag-Erling Smørgrav 	struct ub_packed_rrset_key** alias_rrset,
188a39a5a69SCy Schubert 	int search_only, struct regional* region, struct auth_zones* az,
189a39a5a69SCy Schubert 	int* rpz_passthru);
19065b390aaSDag-Erling Smørgrav 
19165b390aaSDag-Erling Smørgrav /**
19265b390aaSDag-Erling Smørgrav  * Get the response-ip function block.
19365b390aaSDag-Erling Smørgrav  * @return: function block with function pointers to response-ip methods.
19465b390aaSDag-Erling Smørgrav  */
19565b390aaSDag-Erling Smørgrav struct module_func_block* respip_get_funcblock(void);
19665b390aaSDag-Erling Smørgrav 
19765b390aaSDag-Erling Smørgrav /** response-ip init */
19865b390aaSDag-Erling Smørgrav int respip_init(struct module_env* env, int id);
19965b390aaSDag-Erling Smørgrav 
20065b390aaSDag-Erling Smørgrav /** response-ip deinit */
20165b390aaSDag-Erling Smørgrav void respip_deinit(struct module_env* env, int id);
20265b390aaSDag-Erling Smørgrav 
20365b390aaSDag-Erling Smørgrav /** response-ip operate on a query */
20465b390aaSDag-Erling Smørgrav void respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
20565b390aaSDag-Erling Smørgrav 	struct outbound_entry* outbound);
20665b390aaSDag-Erling Smørgrav 
20765b390aaSDag-Erling Smørgrav /** inform response-ip super */
20865b390aaSDag-Erling Smørgrav void respip_inform_super(struct module_qstate* qstate, int id,
20965b390aaSDag-Erling Smørgrav 	struct module_qstate* super);
21065b390aaSDag-Erling Smørgrav 
21165b390aaSDag-Erling Smørgrav /** response-ip cleanup query state */
21265b390aaSDag-Erling Smørgrav void respip_clear(struct module_qstate* qstate, int id);
21365b390aaSDag-Erling Smørgrav 
21465b390aaSDag-Erling Smørgrav /**
21565b390aaSDag-Erling Smørgrav  * returns address of the IP address tree of the specified respip set;
21665b390aaSDag-Erling Smørgrav  * returns NULL for NULL input; exists for test purposes only
21765b390aaSDag-Erling Smørgrav  */
21865b390aaSDag-Erling Smørgrav struct rbtree_type* respip_set_get_tree(struct respip_set* set);
21965b390aaSDag-Erling Smørgrav 
22065b390aaSDag-Erling Smørgrav /**
22165b390aaSDag-Erling Smørgrav  * returns respip action for the specified node in the respip address
22265b390aaSDag-Erling Smørgrav  * returns respip_none for NULL input; exists for test purposes only
22365b390aaSDag-Erling Smørgrav  */
22465b390aaSDag-Erling Smørgrav enum respip_action resp_addr_get_action(const struct resp_addr* addr);
22565b390aaSDag-Erling Smørgrav 
22665b390aaSDag-Erling Smørgrav /**
22765b390aaSDag-Erling Smørgrav  * returns rrset portion of the specified node in the respip address
22865b390aaSDag-Erling Smørgrav  * tree; returns NULL for NULL input; exists for test purposes only
22965b390aaSDag-Erling Smørgrav  */
23065b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* resp_addr_get_rrset(struct resp_addr* addr);
23165b390aaSDag-Erling Smørgrav 
23265b390aaSDag-Erling Smørgrav /** response-ip alloc size routine */
23365b390aaSDag-Erling Smørgrav size_t respip_get_mem(struct module_env* env, int id);
23465b390aaSDag-Erling Smørgrav 
23565b390aaSDag-Erling Smørgrav /**
23665b390aaSDag-Erling Smørgrav  * respip set emptiness test
23765b390aaSDag-Erling Smørgrav  * @param set respip set to test
23865b390aaSDag-Erling Smørgrav  * @return 0 if the specified set exists (non-NULL) and is non-empty;
23965b390aaSDag-Erling Smørgrav  *	otherwise returns 1
24065b390aaSDag-Erling Smørgrav  */
24165b390aaSDag-Erling Smørgrav int respip_set_is_empty(const struct respip_set* set);
24265b390aaSDag-Erling Smørgrav 
24365b390aaSDag-Erling Smørgrav /**
24465b390aaSDag-Erling Smørgrav  * print log information for a query subject to an inform or inform-deny
24565b390aaSDag-Erling Smørgrav  * response-ip action.
246091e9e46SCy Schubert  * @param respip_actinfo: response-ip information that causes the action
24765b390aaSDag-Erling Smørgrav  * @param qname: query name in the context, will be ignored if local_alias is
24865b390aaSDag-Erling Smørgrav  *   non-NULL.
24965b390aaSDag-Erling Smørgrav  * @param qtype: query type, in host byte order.
25065b390aaSDag-Erling Smørgrav  * @param qclass: query class, in host byte order.
25165b390aaSDag-Erling Smørgrav  * @param local_alias: set to a local alias if the query matches an alias in
25265b390aaSDag-Erling Smørgrav  *  a local zone.  In this case its owner name will be considered the actual
25365b390aaSDag-Erling Smørgrav  *  query name.
254*865f46b2SCy Schubert  * @param addr: the client's source address and port.
255*865f46b2SCy Schubert  * @param addrlen: the client's source address length.
25665b390aaSDag-Erling Smørgrav  */
257091e9e46SCy Schubert void respip_inform_print(struct respip_action_info* respip_actinfo,
258091e9e46SCy Schubert 	uint8_t* qname, uint16_t qtype, uint16_t qclass,
259*865f46b2SCy Schubert 	struct local_rrset* local_alias, struct sockaddr_storage* addr,
260*865f46b2SCy Schubert 	socklen_t addrlen);
26165b390aaSDag-Erling Smørgrav 
262091e9e46SCy Schubert /**
263091e9e46SCy Schubert  * Find resp_addr in tree, create and add to tree if it does not exist.
264091e9e46SCy Schubert  * @param set: struct containing the tree and region to alloc new node on.
265091e9e46SCy Schubert  * 	should hold write lock.
266091e9e46SCy Schubert  * @param addr: address to look up.
267091e9e46SCy Schubert  * @param addrlen: length of addr.
268091e9e46SCy Schubert  * @param net: netblock to lookup.
269091e9e46SCy Schubert  * @param create: create node if it does not exist when 1.
270091e9e46SCy Schubert  * @param ipstr: human redable ip string, for logging.
271091e9e46SCy Schubert  * @return newly created of found node, not holding lock.
272091e9e46SCy Schubert  */
273091e9e46SCy Schubert struct resp_addr*
274091e9e46SCy Schubert respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage* addr,
275091e9e46SCy Schubert 		socklen_t addrlen, int net, int create, const char* ipstr);
276091e9e46SCy Schubert 
277091e9e46SCy Schubert /**
278091e9e46SCy Schubert  * Add RR to resp_addr's RRset. Create RRset if not existing.
279091e9e46SCy Schubert  * @param region: region to alloc RR(set).
280091e9e46SCy Schubert  * @param raddr: resp_addr containing RRset. Must hold write lock.
281091e9e46SCy Schubert  * @param rrtype: RR type.
282091e9e46SCy Schubert  * @param rrclass: RR class.
283091e9e46SCy Schubert  * @param ttl: TTL.
284091e9e46SCy Schubert  * @param rdata: RDATA.
285091e9e46SCy Schubert  * @param rdata_len: length of rdata.
286091e9e46SCy Schubert  * @param rrstr: RR as string, for logging
287091e9e46SCy Schubert  * @param netblockstr: netblock as string, for logging
288091e9e46SCy Schubert  * @return 0 on error
289091e9e46SCy Schubert  */
290091e9e46SCy Schubert int
291091e9e46SCy Schubert respip_enter_rr(struct regional* region, struct resp_addr* raddr,
292091e9e46SCy Schubert 	uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata,
293091e9e46SCy Schubert 	size_t rdata_len, const char* rrstr, const char* netblockstr);
294091e9e46SCy Schubert 
295091e9e46SCy Schubert /**
296091e9e46SCy Schubert  * Delete resp_addr node from tree.
297091e9e46SCy Schubert  * @param set: struct containing tree. Must hold write lock.
298091e9e46SCy Schubert  * @param node: node to delete. Not locked.
299091e9e46SCy Schubert  */
300091e9e46SCy Schubert void
301091e9e46SCy Schubert respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node);
30224e36522SCy Schubert 
30324e36522SCy Schubert struct ub_packed_rrset_key*
30424e36522SCy Schubert respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region);
30565b390aaSDag-Erling Smørgrav #endif	/* RESPIP_RESPIP_H */
306