1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 /*
13  * Define the interface from a DNS resolver to the Response Policy Zone
14  * library, librpz.
15  *
16  * This file should be included only the interface functions between the
17  * resolver and librpz to avoid name space pollution.
18  *
19  * Copyright (c) 2016-2017 Farsight Security, Inc.
20  *
21  * Licensed under the Apache License, Version 2.0 (the "License");
22  * you may not use this file except in compliance with the License.
23  * You may obtain a copy of the License at
24  *	http://www.apache.org/licenses/LICENSE-2.0
25  *
26  * Unless required by applicable law or agreed to in writing, software
27  * distributed under the License is distributed on an "AS IS" BASIS,
28  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29  * See the License for the specific language governing permissions and
30  * limitations under the License.
31  *
32  * version 1.2.12
33  */
34 
35 #ifndef LIBRPZ_H
36 #define LIBRPZ_H
37 
38 #include <inttypes.h>
39 #include <stdarg.h>
40 #include <stdbool.h>
41 #include <stdio.h>
42 
43 #include <arpa/nameser.h>
44 #include <netinet/in.h>
45 #include <sys/types.h>
46 
47 /*
48  * Allow either ordinary or dlopen() linking.
49  */
50 #ifdef LIBRPZ_INTERNAL
51 #define LIBDEF(t, s) extern t s;
52 #define LIBDEF_F(f)  LIBDEF(librpz_##f##_t, librpz_##f)
53 #else /* ifdef LIBRPZ_INTERNAL */
54 #define LIBDEF(t, s)
55 #define LIBDEF_F(f)
56 #endif /* ifdef LIBRPZ_INTERNAL */
57 
58 /*
59  * Response Policy Zone triggers.
60  *	Comparisons of trigger precedences require
61  *	LIBRPZ_TRIG_CLIENT_IP < LIBRPZ_TRIG_QNAME < LIBRPZ_TRIG_IP
62  *	    < LIBRPZ_TRIG_NSDNAME < LIBRPZ_TRIG_NSIP}
63  */
64 typedef enum {
65 	LIBRPZ_TRIG_BAD = 0,
66 	LIBRPZ_TRIG_CLIENT_IP = 1,
67 	LIBRPZ_TRIG_QNAME = 2,
68 	LIBRPZ_TRIG_IP = 3,
69 	LIBRPZ_TRIG_NSDNAME = 4,
70 	LIBRPZ_TRIG_NSIP = 5
71 } librpz_trig_t;
72 #define LIBRPZ_TRIG_SIZE 3     /* sizeof librpz_trig_t in bits */
73 typedef uint8_t librpz_tbit_t; /* one bit for each of the TRIGS_NUM
74 				* trigger types */
75 
76 /*
77  * Response Policy Zone Actions or policies
78  */
79 typedef enum {
80 	LIBRPZ_POLICY_UNDEFINED = 0, /* an empty entry or no decision yet */
81 	LIBRPZ_POLICY_DELETED = 1,   /* placeholder for a deleted policy */
82 
83 	LIBRPZ_POLICY_PASSTHRU = 2, /* 'passthru': do not rewrite */
84 	LIBRPZ_POLICY_DROP = 3,	    /* 'drop': do not respond */
85 	LIBRPZ_POLICY_TCP_ONLY = 4, /* 'tcp-only': answer UDP with TC=1 */
86 	LIBRPZ_POLICY_NXDOMAIN = 5, /* 'nxdomain': answer with NXDOMAIN */
87 	LIBRPZ_POLICY_NODATA = 6,   /* 'nodata': answer with ANCOUNT=0 */
88 	LIBRPZ_POLICY_RECORD = 7,   /* rewrite with the policy's RR */
89 
90 	/* only in client configurations to override the zone */
91 	LIBRPZ_POLICY_GIVEN,	/* 'given': what policy record says */
92 	LIBRPZ_POLICY_DISABLED, /* at most log */
93 	LIBRPZ_POLICY_CNAME,	/* answer with 'cname x' */
94 } librpz_policy_t;
95 #define LIBRPZ_POLICY_BITS 4
96 
97 /*
98  * Special policies that appear as targets of CNAMEs
99  * NXDOMAIN is signaled by a CNAME with a "." target.
100  * NODATA is signaled by a CNAME with a "*." target.
101  */
102 #define LIBRPZ_RPZ_PREFIX   "rpz-"
103 #define LIBRPZ_RPZ_PASSTHRU LIBRPZ_RPZ_PREFIX "passthru"
104 #define LIBRPZ_RPZ_DROP	    LIBRPZ_RPZ_PREFIX "drop"
105 #define LIBRPZ_RPZ_TCP_ONLY LIBRPZ_RPZ_PREFIX "tcp-only"
106 
107 typedef uint16_t librpz_dznum_t; /* dnsrpzd zone # in [0,DZNUM_MAX] */
108 typedef uint8_t	 librpz_cznum_t; /* client zone # in [0,CZNUM_MAX] */
109 
110 /*
111  * CIDR block
112  */
113 typedef struct librpz_prefix {
114 	union {
115 		struct in_addr	in;
116 		struct in6_addr in6;
117 	} addr;
118 	uint8_t family;
119 	uint8_t len;
120 } librpz_prefix_t;
121 
122 /*
123  * A domain
124  */
125 typedef uint8_t librpz_dsize_t;
126 typedef struct librpz_domain {
127 	librpz_dsize_t size; /* of only .d */
128 	uint8_t	       d[0]; /* variable length wire format */
129 } librpz_domain_t;
130 
131 /*
132  * A maximal domain buffer
133  */
134 typedef struct librpz_domain_buf {
135 	librpz_dsize_t size;
136 	uint8_t	       d[NS_MAXCDNAME];
137 } librpz_domain_buf_t;
138 
139 /*
140  * A resource record without the owner name.
141  * C compilers say that sizeof(librpz_rr_t)=12 instead of 10.
142  */
143 typedef struct {
144 	uint16_t type;	   /* network byte order */
145 	uint16_t class;	   /* network byte order */
146 	uint32_t ttl;	   /* network byte order */
147 	uint16_t rdlength; /* network byte order */
148 	uint8_t	 rdata[0]; /* variable length */
149 } librpz_rr_t;
150 
151 /*
152  * The database file might be mapped with different starting addresses
153  * by concurrent clients (resolvers), and so all pointers are offsets.
154  */
155 typedef uint32_t librpz_idx_t;
156 #define LIBRPZ_IDX_NULL 0
157 #define LIBRPZ_IDX_MIN	1
158 #define LIBRPZ_IDX_BAD	((librpz_idx_t)-1)
159 /**
160  * Partial decoded results of a set of RPZ queries for a single DNS response
161  * or iteration through the mapped file.
162  */
163 typedef int16_t librpz_result_id_t;
164 typedef struct librpz_result {
165 	librpz_idx_t	   next_rr;
166 	librpz_result_id_t hit_id;  /* trigger ID from resolver */
167 	librpz_policy_t	   zpolicy; /* policy from zone */
168 	librpz_policy_t	   policy;  /* adjusted by client configuration */
169 	librpz_dznum_t	   dznum;   /* dnsrpzd zone number */
170 	librpz_cznum_t	   cznum;   /* librpz client zone number */
171 	librpz_trig_t	   trig : LIBRPZ_TRIG_SIZE;
172 	bool		   log : 1; /* log rewrite given librpz_log_level
173 				     * */
174 } librpz_result_t;
175 
176 /**
177  * librpz trace or log levels.
178  */
179 typedef enum {
180 	LIBRPZ_LOG_FATAL = 0,  /* always print fatal errors */
181 	LIBRPZ_LOG_ERROR = 1,  /* errors have this level */
182 	LIBRPZ_LOG_TRACE1 = 2, /* big events such as dnsrpzd starts */
183 	LIBRPZ_LOG_TRACE2 = 3, /* smaller dnsrpzd zone transfers */
184 	LIBRPZ_LOG_TRACE3 = 4, /* librpz hits */
185 	LIBRPZ_LOG_TRACE4 = 5, /* librpz lookups */
186 	LIBRPZ_LOG_INVALID = 999,
187 } librpz_log_level_t;
188 typedef librpz_log_level_t(librpz_log_level_val_t)(librpz_log_level_t level);
189 LIBDEF_F(log_level_val)
190 
191 /**
192  * Logging function that can be supplied by the resolver.
193  * @param level is one of librpz_log_level_t
194  * @param ctx is for use by the resolver's logging system.
195  *	NULL mean a context-free message.
196  */
197 typedef void(librpz_log_fnc_t)(librpz_log_level_t level, void *ctx,
198 			       const char *buf);
199 
200 /**
201  * Point librpz logging functions to the resolver's choice.
202  */
203 typedef void(librpz_set_log_t)(librpz_log_fnc_t *new_log, const char *prog_nm);
204 LIBDEF_F(set_log)
205 
206 /**
207  * librpz error messages are put in these buffers.
208  * Use a structure instead of naked char* to let the compiler check the length.
209  * A function defined with "foo(char buf[120])" can be called with
210  * "char sbuf[2]; foo(sbuf)" and suffer a buffer overrun.
211  */
212 typedef struct {
213 	char c[120];
214 } librpz_emsg_t;
215 
216 #ifdef LIBRPZ_HAVE_ATTR
217 #define LIBRPZ_UNUSED	__attribute__((unused))
218 #define LIBRPZ_PF(f, l) __attribute__((format(printf, f, l)))
219 #define LIBRPZ_NORET	__attribute__((__noreturn__))
220 #else /* ifdef LIBRPZ_HAVE_ATTR */
221 #define LIBRPZ_UNUSED
222 #define LIBRPZ_PF(f, l)
223 #define LIBRPZ_NORET
224 #endif /* ifdef LIBRPZ_HAVE_ATTR */
225 
226 #ifdef HAVE_BUILTIN_EXPECT
227 #define LIBRPZ_LIKELY(c)   __builtin_expect(!!(c), 1)
228 #define LIBRPZ_UNLIKELY(c) __builtin_expect(!!(c), 0)
229 #else /* ifdef HAVE_BUILTIN_EXPECT */
230 #define LIBRPZ_LIKELY(c)   (c)
231 #define LIBRPZ_UNLIKELY(c) (c)
232 #endif /* ifdef HAVE_BUILTIN_EXPECT */
233 
234 typedef bool(librpz_parse_log_opt_t)(librpz_emsg_t *emsg, const char *arg);
235 LIBDEF_F(parse_log_opt)
236 
237 typedef void(librpz_vpemsg_t)(librpz_emsg_t *emsg, const char *p, va_list args);
238 LIBDEF_F(vpemsg)
239 typedef void(librpz_pemsg_t)(librpz_emsg_t *emsg, const char *p, ...)
240 	LIBRPZ_PF(2, 3);
241 LIBDEF_F(pemsg)
242 
243 typedef void(librpz_vlog_t)(librpz_log_level_t level, void *ctx, const char *p,
244 			    va_list args);
245 LIBDEF_F(vlog)
246 typedef void(librpz_log_t)(librpz_log_level_t level, void *ctx, const char *p,
247 			   ...) LIBRPZ_PF(3, 4);
248 LIBDEF_F(log)
249 
250 typedef void(librpz_fatal_t)(int ex_code, const char *p, ...) LIBRPZ_PF(2, 3);
251 extern void
252 librpz_fatal(int ex_code, const char *p, ...) LIBRPZ_PF(2, 3) LIBRPZ_NORET;
253 
254 typedef void(librpz_rpz_assert_t)(const char *file, unsigned line,
255 				  const char *p, ...) LIBRPZ_PF(3, 4);
256 extern void
257 librpz_rpz_assert(const char *file, unsigned line, const char *p, ...)
258 	LIBRPZ_PF(3, 4) LIBRPZ_NORET;
259 
260 typedef void(librpz_rpz_vassert_t)(const char *file, uint line, const char *p,
261 				   va_list args);
262 extern void
263 librpz_rpz_vassert(const char *file, uint line, const char *p,
264 		   va_list args) LIBRPZ_NORET;
265 
266 /*
267  * As far as clients are concerned, all relative pointers or indexes in a
268  * version of the mapped file except trie node parent pointers remain valid
269  * forever.  A client must release a version so that it can be garbage
270  * collected by the file system.  When dnsrpzd needs to expand the file,
271  * it copies the old file to a new, larger file.  Clients can continue
272  * using the old file.
273  *
274  * Versions can also appear in a single file.  Old nodes and trie values
275  * within the file are not destroyed until all clients using the version
276  * that contained the old values release the version.
277  *
278  * A client is marked as using version by connecting to the daemon.  It is
279  * marked as using all subsequent versions.  A client releases all versions
280  * by closing the connection or a range of versions by updating is slot
281  * in the shared memory version table.
282  *
283  * As far as clients are concerned, there are the following possible librpz
284  * failures:
285  *	- malloc() or other fatal internal librpz problems indicated by
286  *	    a failing return from a librpz function
287  *	    All operations will fail until client handle is destroyed and
288  *	    recreated with librpz_client_detach() and librpz_client_create().
289  *	- corrupt database detected by librpz code, corrupt database detected
290  *	    by dnsrpzd, or disconnection from the daemon.
291  *	    Current operations will fail.
292  *
293  * Clients assume that the file has already been unlinked before
294  *	the corrupt flag is set so that they do not race with the server
295  *	over the corruption of a single file.  A client that finds the
296  *	corrupt set knows that dnsrpzd has already crashed with
297  *	abort() and is restarting.  The client can re-connect to dnsrpzd
298  *	and retransmit its configuration, backing off as usual if anything
299  *	goes wrong.
300  *
301  * Searches of the database by a client do not need locks against dnsrpzd or
302  *	other clients, but a lock is used to protect changes to the connection
303  *	by competing threads in the client.  The client provides functions
304  *	to serialize the concurrent use of any single client handle.
305  *	Functions that do nothing are appropriate for applications that are
306  *	not "threaded" or that do not share client handles among threads.
307  *	Otherwise, functions must be provided to librpz_clientcreate().
308  *	Something like the following works with pthreads:
309  *
310  * static void
311  * lock(void *mutex) { assert(pthread_mutex_lock(mutex) == 0); }
312  *
313  * static void
314  * unlock(void *mutex) { assert(pthread_mutex_unlock(mutex) == 0); }
315  *
316  * static void
317  * mutex_destroy(void *mutex) { assert(pthread_mutex_destroy(mutex) == 0); }
318  *
319  *
320  *
321  * At every instant, all of the data and pointers in the mapped file are valid.
322  *	Changes to trie node or other data are always made so that it and
323  *	all pointers in and to it remain valid for a time.  Old versions are
324  *	eventually discarded.
325  *
326  * Dnsrpzd periodically defines a new version by setting aside all changes
327  *	made since the previous version was defined.  Subsequent changes
328  *	made (only!) by dnsrpzd will be part of the next version.
329  *
330  * To discard an old version, dnsrpzd must know that all clients have stopped
331  *	using that version.  Clients do that by using part of the mapped file
332  *	to tell dnsrpzd the oldest version that each client is using.
333  *	Dnsrpzd assigns each connecting client an entry in the cversions array
334  *	in the mapped file.  The client puts version numbers into that entry
335  *	to signal to dnsrpzd which versions that can be discarded.
336  *	Dnsrpzd is free, as far as that client is concerned, to discard all
337  *	numerically smaller versions.  A client can disclaim all versions with
338  *	the version number VERSIONS_ALL or 0.
339  *
340  * The race between a client changing its entry and dnsrpzd discarding a
341  *	version is resolved by allowing dnsrpzd to discard all versions
342  *	smaller or equal to the client's version number.  If dnsrpzd is in
343  *	the midst of discarding or about to discard version N when the
344  *	client asserts N, no harm is done.  The client depends only on
345  *	the consistency of version N+1.
346  *
347  * This version mechanism depends in part on not being exercised too frequently
348  *	Version numbers are 32 bits long and dnsrpzd creates new versions
349  *	at most once every 30 seconds.
350  */
351 
352 /*
353  * Lock functions for concurrent use of a single librpz_client_t client handle.
354  */
355 typedef void(librpz_mutex_t)(void *mutex);
356 
357 /*
358  * List of connections to dnsrpzd daemons.
359  */
360 typedef struct librpz_clist librpz_clist_t;
361 
362 /*
363  * Client's handle on dnsrpzd.
364  */
365 typedef struct librpz_client librpz_client_t;
366 
367 /**
368  * Create the list of connections to the dnsrpzd daemon.
369  * @param[out] emsg: error message
370  * @param lock: start exclusive access to the client handle
371  * @param unlock: end exclusive access to the client handle
372  * @param mutex_destroy: release the lock
373  * @param mutex: pointer to the lock for the client handle
374  * @param log_ctx: NULL or resolver's context log messages
375  */
376 typedef librpz_clist_t *(librpz_clist_create_t)(librpz_emsg_t * emsg,
377 						librpz_mutex_t *lock,
378 						librpz_mutex_t *unlock,
379 						librpz_mutex_t *mutex_destroy,
380 						void *mutex, void *log_ctx);
381 LIBDEF_F(clist_create)
382 
383 /**
384  * Release the list of dnsrpzd connections.
385  */
386 typedef void(librpz_clist_detach_t)(librpz_clist_t **clistp);
387 LIBDEF_F(clist_detach)
388 
389 /**
390  * Create a librpz client handle.
391  * @param[out] emsg: error message
392  * @param clist: of dnsrpzd connections
393  * @param cstr: string of configuration settings separated by ';' or '\n'
394  * @param use_expired: true to not ignore expired zones
395  * @return client handle or NULL if the handle could not be created
396  */
397 typedef librpz_client_t *(librpz_client_create_t)(librpz_emsg_t * emsg,
398 						  librpz_clist_t *clist,
399 						  const char *	  cstr,
400 						  bool		  use_expired);
401 LIBDEF_F(client_create)
402 
403 /**
404  * Start (if necessary) dnsrpzd and connect to it.
405  * @param[out] emsg: error message
406  * @param client handle
407  * @param optional: true if it is ok if starting the daemon is not allowed
408  */
409 typedef bool(librpz_connect_t)(librpz_emsg_t *emsg, librpz_client_t *client,
410 			       bool optional);
411 LIBDEF_F(connect)
412 
413 /**
414  * Start to destroy a librpz client handle.
415  * It will not be destroyed until the last set of RPZ queries represented
416  * by a librpz_rsp_t ends.
417  * @param client handle to be released
418  * @return false on error
419  */
420 typedef void(librpz_client_detach_t)(librpz_client_t **clientp);
421 LIBDEF_F(client_detach)
422 
423 /**
424  * State for a set of RPZ queries for a single DNS response
425  * or for listing the database.
426  */
427 typedef struct librpz_rsp librpz_rsp_t;
428 
429 /**
430  * Start a set of RPZ queries for a single DNS response.
431  * @param[out] emsg: error message for false return or *rspp=NULL
432  * @param[out] rspp created context or NULL
433  * @param[out] min_ns_dotsp: NULL or pointer to configured MIN-NS-DOTS value
434  * @param client state
435  * @param have_rd: RD=1 in the DNS request
436  * @param have_do: DO=1 in the DNS request
437  * @return false on error
438  */
439 typedef bool(librpz_rsp_create_t)(librpz_emsg_t *emsg, librpz_rsp_t **rspp,
440 				  int *min_ns_dotsp, librpz_client_t *client,
441 				  bool have_rd, bool have_do);
442 LIBDEF_F(rsp_create)
443 
444 /**
445  * Finish RPZ work for a DNS response.
446  */
447 typedef void(librpz_rsp_detach_t)(librpz_rsp_t **rspp);
448 LIBDEF_F(rsp_detach)
449 
450 /**
451  * Get the final, accumulated result of a set of RPZ queries.
452  * Yield LIBRPZ_POLICY_UNDEFINED if
453  *  - there were no hits,
454  *  - there was a dispositive hit, be we have not recursed and are required
455  *	to recurse so that evil DNS authorities will not know we are using RPZ
456  *  - we have a hit and have recursed, but later data such as NSIP could
457  *	override
458  * @param[out] emsg
459  * @param[out] result describes the hit
460  *	or result->policy=LIBRPZ_POLICY_UNDEFINED without a hit
461  * @param[out] result: current policy rewrite values
462  * @param recursed: recursion has now been done even if it was not done
463  *	when the hit was found
464  * @param[in,out] rsp state from librpz_itr_start()
465  * @return false on error
466  */
467 typedef bool(librpz_rsp_result_t)(librpz_emsg_t *emsg, librpz_result_t *result,
468 				  bool recursed, const librpz_rsp_t *rsp);
469 LIBDEF_F(rsp_result)
470 
471 /**
472  * Might looking for a trigger be worthwhile?
473  * @param trig: look for this type of trigger
474  * @param ipv6: true if trig is LIBRPZ_TRIG_CLIENT_IP, LIBRPZ_TRIG_IP,
475  *	or LIBRPZ_TRIG_NSIP and the IP address is IPv6
476  * @return: true if looking could be worthwhile
477  */
478 typedef bool(librpz_have_trig_t)(librpz_trig_t trig, bool ipv6,
479 				 const librpz_rsp_t *rsp);
480 LIBDEF_F(have_trig)
481 
482 /**
483  * Might looking for NSDNAME and NSIP triggers be worthwhile?
484  * @return: true if looking could be worthwhile
485  */
486 typedef bool(librpz_have_ns_trig_t)(const librpz_rsp_t *rsp);
487 LIBDEF_F(have_ns_trig)
488 
489 /**
490  * Convert the found client IP trie key to a CIDR block
491  * @param[out] emsg
492  * @param[out] prefix trigger
493  * @param[in,out] rsp state from librpz_itr_start()
494  * @return false on error
495  */
496 typedef bool(librpz_rsp_clientip_prefix_t)(librpz_emsg_t *  emsg,
497 					   librpz_prefix_t *prefix,
498 					   librpz_rsp_t *   rsp);
499 LIBDEF_F(rsp_clientip_prefix)
500 
501 /**
502  * Compute the owner name of the found or result trie key, usually to log it.
503  * An IP address key might be returned as 8.0.0.0.127.rpz-client-ip.
504  * example.com. might be a qname trigger.  example.com.rpz-nsdname. could
505  * be an NSDNAME trigger.
506  * @param[out] emsg
507  * @param[out] owner domain
508  * @param[in,out] rsp state from librpz_itr_start()
509  * @return false on error
510  */
511 typedef bool(librpz_rsp_domain_t)(librpz_emsg_t *      emsg,
512 				  librpz_domain_buf_t *owner,
513 				  librpz_rsp_t *       rsp);
514 LIBDEF_F(rsp_domain)
515 
516 /**
517  * Get the next RR of the LIBRPZ_POLICY_RECORD result after an initial use of
518  * librpz_rsp_result() or librpz_itr_node() or after a previous use of
519  * librpz_rsp_rr().  The RR is in uncompressed wire format including type,
520  * class, ttl and length in network byte order.
521  * @param[out] emsg
522  * @param[out] typep: optional host byte order record type or ns_t_invalid (0)
523  * @param[out] classp: class such as ns_c_in
524  * @param[out] ttlp: TTL
525  * @param[out] rrp: optional malloc() buffer containing the next RR or
526  *	NULL after the last RR
527  * @param[out] result: current policy rewrite values
528  * @param qname: used construct a wildcard CNAME
529  * @param qname_size
530  * @param[in,out] rsp state from librpz_itr_start()
531  * @return false on error
532  */
533 typedef bool(librpz_rsp_rr_t)(librpz_emsg_t *emsg, uint16_t *typep,
534 			      uint16_t *classp, uint32_t *ttlp,
535 			      librpz_rr_t **rrp, librpz_result_t *result,
536 			      const uint8_t *qname, size_t qname_size,
537 			      librpz_rsp_t *rsp);
538 LIBDEF_F(rsp_rr)
539 
540 /**
541  * Get the next RR of the LIBRPZ_POLICY_RECORD result.
542  * @param[out] emsg
543  * @param[out] ttlp: TTL
544  * @param[out] rrp: malloc() buffer with SOA RR without owner name
545  * @param[out] result: current policy rewrite values
546  * @param[out] origin: SOA owner name
547  * @param[out] origin_size
548  * @param[in,out] rsp state from librpz_itr_start()
549  * @return false on error
550  */
551 typedef bool(librpz_rsp_soa_t)(librpz_emsg_t *emsg, uint32_t *ttlp,
552 			       librpz_rr_t **rrp, librpz_domain_buf_t *origin,
553 			       librpz_result_t *result, librpz_rsp_t *rsp);
554 LIBDEF_F(rsp_soa)
555 
556 /**
557  * Get the SOA serial number for a policy zone to compare with a known value
558  * to check whether a zone transfer is complete.
559  */
560 typedef bool(librpz_soa_serial_t)(librpz_emsg_t *emsg, uint32_t *serialp,
561 				  const char *domain_nm, librpz_rsp_t *rsp);
562 LIBDEF_F(soa_serial)
563 
564 /**
565  * Save the current policy checking state.
566  * @param[out] emsg
567  * @param[in,out] rsp state from librpz_itr_start()
568  * @return false on error
569  */
570 typedef bool(librpz_rsp_push_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
571 LIBDEF_F(rsp_push)
572 #define LIBRPZ_RSP_STACK_DEPTH 3
573 
574 /**
575  * Restore the previous policy checking state.
576  * @param[out] emsg
577  * @param[out] result: NULL or restored policy rewrite values
578  * @param[in,out] rsp state from librpz_itr_start()
579  * @return false on error
580  */
581 typedef bool(librpz_rsp_pop_t)(librpz_emsg_t *emsg, librpz_result_t *result,
582 			       librpz_rsp_t *rsp);
583 LIBDEF_F(rsp_pop)
584 
585 /**
586  * Discard the most recently save policy checking state.
587  * @param[out] emsg
588  * @param[out] result: NULL or restored policy rewrite values
589  * @return false on error
590  */
591 typedef bool(librpz_rsp_pop_discard_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
592 LIBDEF_F(rsp_pop_discard)
593 
594 /**
595  * Disable a zone.
596  * @param[out] emsg
597  * @param znum
598  * @param[in,out] rsp state from librpz_itr_start()
599  * @return false on error
600  */
601 typedef bool(librpz_rsp_forget_zone_t)(librpz_emsg_t *emsg, librpz_cznum_t znum,
602 				       librpz_rsp_t *rsp);
603 LIBDEF_F(rsp_forget_zone)
604 
605 /**
606  * Apply RPZ to an IP address.
607  * @param[out] emsg
608  * @param addr: address to check
609  * @param ipv6: true for 16 byte IPv6 instead of 4 byte IPv4
610  * @param trig LIBRPZ_TRIG_CLIENT_IP, LIBRPZ_TRIG_IP, or LIBRPZ_TRIG_NSIP
611  * @param hit_id: caller chosen
612  * @param recursed: recursion has been done
613  * @param[in,out] rsp state from librpz_itr_start()
614  * @return false on error
615  */
616 typedef bool(librpz_ck_ip_t)(librpz_emsg_t *emsg, const void *addr, uint family,
617 			     librpz_trig_t trig, librpz_result_id_t hit_id,
618 			     bool recursed, librpz_rsp_t *rsp);
619 LIBDEF_F(ck_ip)
620 
621 /**
622  * Apply RPZ to a wire-format domain.
623  * @param[out] emsg
624  * @param domain in wire format
625  * @param domain_size
626  * @param trig LIBRPZ_TRIG_QNAME or LIBRPZ_TRIG_NSDNAME
627  * @param hit_id: caller chosen
628  * @param recursed: recursion has been done
629  * @param[in,out] rsp state from librpz_itr_start()
630  * @return false on error
631  */
632 typedef bool(librpz_ck_domain_t)(librpz_emsg_t *emsg, const uint8_t *domain,
633 				 size_t domain_size, librpz_trig_t trig,
634 				 librpz_result_id_t hit_id, bool recursed,
635 				 librpz_rsp_t *rsp);
636 LIBDEF_F(ck_domain)
637 
638 /**
639  * Ask dnsrpzd to refresh a zone.
640  * @param[out] emsg error message
641  * @param librpz_domain_t domain to refresh
642  * @param client context
643  * @return false after error
644  */
645 typedef bool(librpz_zone_refresh_t)(librpz_emsg_t *emsg, const char *domain,
646 				    librpz_rsp_t *rsp);
647 LIBDEF_F(zone_refresh)
648 
649 /**
650  * Get a string describing the database
651  * @param license: include the license
652  * @param cfiles: include the configuration file names
653  * @param listens: include the local notify IP addresses
654  * @param[out] emsg error message if the result is null
655  * @param client context
656  * @return malloc'ed string or NULL after error
657  */
658 typedef char *(librpz_db_info_t)(librpz_emsg_t *emsg, bool license, bool cfiles,
659 				 bool listens, librpz_rsp_t *rsp);
660 LIBDEF_F(db_info)
661 
662 /**
663  * Start a context for listing the nodes and/or zones in the mapped file
664  * @param[out] emsg: error message for false return or *rspp=NULL
665  * @param[out] rspp: created context or NULL
666  * @param client context
667  * @return false after error
668  */
669 typedef bool(librpz_itr_start_t)(librpz_emsg_t *emsg, librpz_rsp_t **rspp,
670 				 librpz_client_t *client);
671 LIBDEF_F(itr_start)
672 
673 /**
674  * Get mapped file memory allocation statistics.
675  * @param[out] emsg: error message
676  * @param rsp state from librpz_itr_start()
677  * @return malloc'ed string or NULL after error
678  */
679 typedef char *(librpz_mf_stats_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
680 LIBDEF_F(mf_stats)
681 
682 /**
683  * Get versions currently used by clients.
684  * @param[out] emsg: error message
685  * @param[in,out] rsp: state from librpz_itr_start()
686  * @return malloc'ed string or NULL after error
687  */
688 typedef char *(librpz_vers_stats_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp);
689 LIBDEF_F(vers_stats)
690 
691 /**
692  * Allocate a string describing the next zone or "" after the last zone.
693  * @param[out] emsg
694  * @param all_zones to list all instead of only requested zones
695  * @param[in,out] rsp state from librpz_rsp_start()
696  * @return malloc'ed string or NULL after error
697  */
698 typedef char *(librpz_itr_zone_t)(librpz_emsg_t *emsg, bool all_zones,
699 				  librpz_rsp_t *rsp);
700 LIBDEF_F(itr_zone)
701 
702 /**
703  * Describe the next trie node while dumping the database.
704  * @param[out] emsg
705  * @param[out] result describes node
706  *	or result->policy=LIBRPZ_POLICY_UNDEFINED after the last node.
707  * @param all_zones to list all instead of only requested zones
708  * @param[in,out] rsp state from librpz_itr_start()
709  * @return: false on error
710  */
711 typedef bool(librpz_itr_node_t)(librpz_emsg_t *emsg, librpz_result_t *result,
712 				bool all_zones, librpz_rsp_t *rsp);
713 LIBDEF_F(itr_node)
714 
715 /**
716  * RPZ policy to string with a backup buffer of POLICY2STR_SIZE size
717  */
718 typedef const char *(librpz_policy2str_t)(librpz_policy_t policy, char *buf,
719 					  size_t buf_size);
720 #define POLICY2STR_SIZE sizeof("policy xxxxxx")
721 LIBDEF_F(policy2str)
722 
723 /**
724  * Trigger type to string.
725  */
726 typedef const char *(librpz_trig2str_t)(librpz_trig_t trig);
727 LIBDEF_F(trig2str)
728 
729 /**
730  * Convert a number of seconds to a zone file duration string
731  */
732 typedef const char *(librpz_secs2str_t)(time_t secs, char *buf,
733 					size_t buf_size);
734 #define SECS2STR_SIZE sizeof("1234567w7d24h59m59s")
735 LIBDEF_F(secs2str)
736 
737 /**
738  * Parse a duration with 's', 'm', 'h', 'd', and 'w' units.
739  */
740 typedef bool(librpz_str2secs_t)(librpz_emsg_t *emsg, time_t *val,
741 				const char *str0);
742 LIBDEF_F(str2secs)
743 
744 /**
745  * Translate selected rtypes to strings
746  */
747 typedef const char *(librpz_rtype2str_t)(uint type, char *buf, size_t buf_size);
748 #define RTYPE2STR_SIZE sizeof("type xxxxx")
749 LIBDEF_F(rtype2str)
750 
751 /**
752  * Local version of ns_name_ntop() for portability.
753  */
754 typedef int(librpz_domain_ntop_t)(const u_char *src, char *dst, size_t dstsiz);
755 LIBDEF_F(domain_ntop)
756 
757 /**
758  * Local version of ns_name_pton().
759  */
760 typedef int(librpz_domain_pton2_t)(const char *src, u_char *dst, size_t dstsiz,
761 				   size_t *dstlen, bool lower);
762 LIBDEF_F(domain_pton2)
763 
764 typedef union socku socku_t;
765 typedef socku_t *(librpz_mk_inet_su_t)(socku_t *su, const struct in_addr *addrp,
766 				       in_port_t port);
767 LIBDEF_F(mk_inet_su)
768 
769 typedef socku_t *(librpz_mk_inet6_su_t)(socku_t *	       su,
770 					const struct in6_addr *addrp,
771 					uint32_t scope_id, in_port_t port);
772 LIBDEF_F(mk_inet6_su)
773 
774 typedef bool(librpz_str2su_t)(socku_t *sup, const char *str);
775 LIBDEF_F(str2su)
776 
777 typedef char *(librpz_su2str_t)(char *str, size_t str_len, const socku_t *su);
LIBDEF_F(su2str)778 LIBDEF_F(su2str)
779 #define SU2STR_SIZE (INET6_ADDRSTRLEN + 1 + 6 + 1)
780 
781 /**
782  * default path to dnsrpzd
783  */
784 const char *librpz_dnsrpzd_path;
785 
786 #undef LIBDEF
787 
788 /*
789  * This is the dlopen() interface to librpz.
790  */
791 typedef const struct {
792 	const char *			  dnsrpzd_path;
793 	const char *			  version;
794 	librpz_parse_log_opt_t *	  parse_log_opt;
795 	librpz_log_level_val_t *	  log_level_val;
796 	librpz_set_log_t *		  set_log;
797 	librpz_vpemsg_t *		  vpemsg;
798 	librpz_pemsg_t *		  pemsg;
799 	librpz_vlog_t *			  vlog;
800 	librpz_log_t *			  log;
801 	librpz_fatal_t *fatal		  LIBRPZ_NORET;
802 	librpz_rpz_assert_t *rpz_assert	  LIBRPZ_NORET;
803 	librpz_rpz_vassert_t *rpz_vassert LIBRPZ_NORET;
804 	librpz_clist_create_t *		  clist_create;
805 	librpz_clist_detach_t *		  clist_detach;
806 	librpz_client_create_t *	  client_create;
807 	librpz_connect_t *		  connect;
808 	librpz_client_detach_t *	  client_detach;
809 	librpz_rsp_create_t *		  rsp_create;
810 	librpz_rsp_detach_t *		  rsp_detach;
811 	librpz_rsp_result_t *		  rsp_result;
812 	librpz_have_trig_t *		  have_trig;
813 	librpz_have_ns_trig_t *		  have_ns_trig;
814 	librpz_rsp_clientip_prefix_t *	  rsp_clientip_prefix;
815 	librpz_rsp_domain_t *		  rsp_domain;
816 	librpz_rsp_rr_t *		  rsp_rr;
817 	librpz_rsp_soa_t *		  rsp_soa;
818 	librpz_soa_serial_t *		  soa_serial;
819 	librpz_rsp_push_t *		  rsp_push;
820 	librpz_rsp_pop_t *		  rsp_pop;
821 	librpz_rsp_pop_discard_t *	  rsp_pop_discard;
822 	librpz_rsp_forget_zone_t *	  rsp_forget_zone;
823 	librpz_ck_ip_t *		  ck_ip;
824 	librpz_ck_domain_t *		  ck_domain;
825 	librpz_zone_refresh_t *		  zone_refresh;
826 	librpz_db_info_t *		  db_info;
827 	librpz_itr_start_t *		  itr_start;
828 	librpz_mf_stats_t *		  mf_stats;
829 	librpz_vers_stats_t *		  vers_stats;
830 	librpz_itr_zone_t *		  itr_zone;
831 	librpz_itr_node_t *		  itr_node;
832 	librpz_policy2str_t *		  policy2str;
833 	librpz_trig2str_t *		  trig2str;
834 	librpz_secs2str_t *		  secs2str;
835 	librpz_str2secs_t *		  str2secs;
836 	librpz_rtype2str_t *		  rtype2str;
837 	librpz_domain_ntop_t *		  domain_ntop;
838 	librpz_domain_pton2_t *		  domain_pton2;
839 	librpz_mk_inet_su_t *		  mk_inet_su;
840 	librpz_mk_inet6_su_t *		  mk_inet6_su;
841 	librpz_str2su_t *		  str2su;
842 	librpz_su2str_t *		  su2str;
843 } librpz_0_t;
844 extern librpz_0_t librpz_def_0;
845 
846 /*
847  * Future versions can be upward compatible by defining LIBRPZ_DEF as
848  * librpz_X_t.
849  */
850 #define LIBRPZ_DEF     librpz_def_0
851 #define LIBRPZ_DEF_STR "librpz_def_0"
852 
853 typedef librpz_0_t librpz_t;
854 extern librpz_t *  librpz;
855 
856 #if LIBRPZ_LIB_OPEN == 2
857 #include <dlfcn.h>
858 
859 /**
860  * link-load librpz
861  * @param[out] emsg: error message
862  * @param[in,out] dl_handle: NULL or pointer to new dlopen handle
863  * @param[in] path: librpz.so path
864  * @return address of interface structure or NULL on failure
865  */
866 static inline librpz_t *
librpz_lib_open(librpz_emsg_t * emsg,void ** dl_handle,const char * path)867 librpz_lib_open(librpz_emsg_t *emsg, void **dl_handle, const char *path) {
868 	void *	  handle;
869 	librpz_t *new_librpz;
870 
871 	emsg->c[0] = '\0';
872 
873 	/*
874 	 * Close a previously opened handle on librpz.so.
875 	 */
876 	if (dl_handle != NULL && *dl_handle != NULL) {
877 		if (dlclose(*dl_handle) != 0) {
878 			snprintf(emsg->c, sizeof(librpz_emsg_t),
879 				 "dlopen(NULL): %s", dlerror());
880 			return (NULL);
881 		}
882 		*dl_handle = NULL;
883 	}
884 
885 	/*
886 	 * First try the main executable of the process in case it was
887 	 * linked to librpz.
888 	 * Do not worry if we cannot search the main executable of the process.
889 	 */
890 	handle = dlopen(NULL, RTLD_NOW | RTLD_LOCAL);
891 	if (handle != NULL) {
892 		new_librpz = dlsym(handle, LIBRPZ_DEF_STR);
893 		if (new_librpz != NULL) {
894 			if (dl_handle != NULL) {
895 				*dl_handle = handle;
896 			}
897 			return (new_librpz);
898 		}
899 		if (dlclose(handle) != 0) {
900 			snprintf(emsg->c, sizeof(librpz_emsg_t),
901 				 "dlsym(NULL, " LIBRPZ_DEF_STR "): %s",
902 				 dlerror());
903 			return (NULL);
904 		}
905 	}
906 
907 	if (path == NULL || path[0] == '\0') {
908 		snprintf(emsg->c, sizeof(librpz_emsg_t),
909 			 "librpz not linked and no dlopen() path provided");
910 		return (NULL);
911 	}
912 
913 	handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
914 	if (handle == NULL) {
915 		snprintf(emsg->c, sizeof(librpz_emsg_t), "dlopen(%s): %s", path,
916 			 dlerror());
917 		return (NULL);
918 	}
919 	new_librpz = dlsym(handle, LIBRPZ_DEF_STR);
920 	if (new_librpz != NULL) {
921 		if (dl_handle != NULL) {
922 			*dl_handle = handle;
923 		}
924 		return (new_librpz);
925 	}
926 	snprintf(emsg->c, sizeof(librpz_emsg_t),
927 		 "dlsym(%s, " LIBRPZ_DEF_STR "): %s", path, dlerror());
928 	dlclose(handle);
929 	return (NULL);
930 }
931 #elif defined(LIBRPZ_LIB_OPEN)
932 /*
933  * Statically link to the librpz.so DSO on systems without dlopen()
934  */
935 static inline librpz_t *
librpz_lib_open(librpz_emsg_t * emsg,void ** dl_handle,const char * path)936 librpz_lib_open(librpz_emsg_t *emsg, void **dl_handle, const char *path) {
937 	(void)(path);
938 
939 	if (dl_handle != NULL) {
940 		*dl_handle = NULL;
941 	}
942 
943 #if LIBRPZ_LIB_OPEN == 1
944 	emsg->c[0] = '\0';
945 	return (&LIBRPZ_DEF);
946 #else  /* if LIBRPZ_LIB_OPEN == 1 */
947 	snprintf(emsg->c, sizeof(librpz_emsg_t),
948 		 "librpz not available via ./configure");
949 	return (NULL);
950 #endif /* LIBRPZ_LIB_OPEN */
951 }
952 #endif /* LIBRPZ_LIB_OPEN */
953 
954 #endif /* LIBRPZ_H */
955