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