/* * Copyright (C) Internet Systems Consortium, Inc. ("ISC") * * SPDX-License-Identifier: MPL-2.0 * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, you can obtain one at https://mozilla.org/MPL/2.0/. * * See the COPYRIGHT file distributed with this work for additional * information regarding copyright ownership. */ /* * Define the interface from a DNS resolver to the Response Policy Zone * library, librpz. * * This file should be included only the interface functions between the * resolver and librpz to avoid name space pollution. * * Copyright (c) 2016-2017 Farsight Security, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * version 1.2.12 */ #pragma once #include #include #include #include #include #include #include /* * Allow either ordinary or dlopen() linking. */ #ifdef LIBRPZ_INTERNAL #define LIBDEF(t, s) extern t s; #define LIBDEF_F(f) LIBDEF(librpz_##f##_t, librpz_##f) #else /* ifdef LIBRPZ_INTERNAL */ #define LIBDEF(t, s) #define LIBDEF_F(f) #endif /* ifdef LIBRPZ_INTERNAL */ /* * Response Policy Zone triggers. * Comparisons of trigger precedences require * LIBRPZ_TRIG_CLIENT_IP < LIBRPZ_TRIG_QNAME < LIBRPZ_TRIG_IP * < LIBRPZ_TRIG_NSDNAME < LIBRPZ_TRIG_NSIP} */ typedef enum { LIBRPZ_TRIG_BAD = 0, LIBRPZ_TRIG_CLIENT_IP = 1, LIBRPZ_TRIG_QNAME = 2, LIBRPZ_TRIG_IP = 3, LIBRPZ_TRIG_NSDNAME = 4, LIBRPZ_TRIG_NSIP = 5 } librpz_trig_t; #define LIBRPZ_TRIG_SIZE 3 /* sizeof librpz_trig_t in bits */ typedef uint8_t librpz_tbit_t; /* one bit for each of the TRIGS_NUM * trigger types */ /* * Response Policy Zone Actions or policies */ typedef enum { LIBRPZ_POLICY_UNDEFINED = 0, /* an empty entry or no decision yet */ LIBRPZ_POLICY_DELETED = 1, /* placeholder for a deleted policy */ LIBRPZ_POLICY_PASSTHRU = 2, /* 'passthru': do not rewrite */ LIBRPZ_POLICY_DROP = 3, /* 'drop': do not respond */ LIBRPZ_POLICY_TCP_ONLY = 4, /* 'tcp-only': answer UDP with TC=1 */ LIBRPZ_POLICY_NXDOMAIN = 5, /* 'nxdomain': answer with NXDOMAIN */ LIBRPZ_POLICY_NODATA = 6, /* 'nodata': answer with ANCOUNT=0 */ LIBRPZ_POLICY_RECORD = 7, /* rewrite with the policy's RR */ /* only in client configurations to override the zone */ LIBRPZ_POLICY_GIVEN, /* 'given': what policy record says */ LIBRPZ_POLICY_DISABLED, /* at most log */ LIBRPZ_POLICY_CNAME, /* answer with 'cname x' */ } librpz_policy_t; #define LIBRPZ_POLICY_BITS 4 /* * Special policies that appear as targets of CNAMEs * NXDOMAIN is signaled by a CNAME with a "." target. * NODATA is signaled by a CNAME with a "*." target. */ #define LIBRPZ_RPZ_PREFIX "rpz-" #define LIBRPZ_RPZ_PASSTHRU LIBRPZ_RPZ_PREFIX "passthru" #define LIBRPZ_RPZ_DROP LIBRPZ_RPZ_PREFIX "drop" #define LIBRPZ_RPZ_TCP_ONLY LIBRPZ_RPZ_PREFIX "tcp-only" typedef uint16_t librpz_dznum_t; /* dnsrpzd zone # in [0,DZNUM_MAX] */ typedef uint8_t librpz_cznum_t; /* client zone # in [0,CZNUM_MAX] */ /* * CIDR block */ typedef struct librpz_prefix { union { struct in_addr in; struct in6_addr in6; } addr; uint8_t family; uint8_t len; } librpz_prefix_t; /* * A domain */ typedef uint8_t librpz_dsize_t; typedef struct librpz_domain { librpz_dsize_t size; /* of only .d */ uint8_t d[0]; /* variable length wire format */ } librpz_domain_t; /* * A maximal domain buffer */ typedef struct librpz_domain_buf { librpz_dsize_t size; uint8_t d[NS_MAXCDNAME]; } librpz_domain_buf_t; /* * A resource record without the owner name. * C compilers say that sizeof(librpz_rr_t)=12 instead of 10. */ typedef struct { uint16_t type; /* network byte order */ uint16_t class; /* network byte order */ uint32_t ttl; /* network byte order */ uint16_t rdlength; /* network byte order */ uint8_t rdata[0]; /* variable length */ } librpz_rr_t; /* * The database file might be mapped with different starting addresses * by concurrent clients (resolvers), and so all pointers are offsets. */ typedef uint32_t librpz_idx_t; #define LIBRPZ_IDX_NULL 0 #define LIBRPZ_IDX_MIN 1 #define LIBRPZ_IDX_BAD ((librpz_idx_t)-1) /** * Partial decoded results of a set of RPZ queries for a single DNS response * or iteration through the mapped file. */ typedef int16_t librpz_result_id_t; typedef struct librpz_result { librpz_idx_t next_rr; librpz_result_id_t hit_id; /* trigger ID from resolver */ librpz_policy_t zpolicy; /* policy from zone */ librpz_policy_t policy; /* adjusted by client configuration */ librpz_dznum_t dznum; /* dnsrpzd zone number */ librpz_cznum_t cznum; /* librpz client zone number */ librpz_trig_t trig : LIBRPZ_TRIG_SIZE; bool log : 1; /* log rewrite given librpz_log_level * */ } librpz_result_t; /** * librpz trace or log levels. */ typedef enum { LIBRPZ_LOG_FATAL = 0, /* always print fatal errors */ LIBRPZ_LOG_ERROR = 1, /* errors have this level */ LIBRPZ_LOG_TRACE1 = 2, /* big events such as dnsrpzd starts */ LIBRPZ_LOG_TRACE2 = 3, /* smaller dnsrpzd zone transfers */ LIBRPZ_LOG_TRACE3 = 4, /* librpz hits */ LIBRPZ_LOG_TRACE4 = 5, /* librpz lookups */ LIBRPZ_LOG_INVALID = 999, } librpz_log_level_t; typedef librpz_log_level_t(librpz_log_level_val_t)(librpz_log_level_t level); LIBDEF_F(log_level_val) /** * Logging function that can be supplied by the resolver. * @param level is one of librpz_log_level_t * @param ctx is for use by the resolver's logging system. * NULL mean a context-free message. */ typedef void(librpz_log_fnc_t)(librpz_log_level_t level, void *ctx, const char *buf); /** * Point librpz logging functions to the resolver's choice. */ typedef void(librpz_set_log_t)(librpz_log_fnc_t *new_log, const char *prog_nm); LIBDEF_F(set_log) /** * librpz error messages are put in these buffers. * Use a structure instead of naked char* to let the compiler check the length. * A function defined with "foo(char buf[120])" can be called with * "char sbuf[2]; foo(sbuf)" and suffer a buffer overrun. */ typedef struct { char c[120]; } librpz_emsg_t; #ifdef LIBRPZ_HAVE_ATTR #define LIBRPZ_UNUSED __attribute__((unused)) #define LIBRPZ_PF(f, l) __attribute__((format(printf, f, l))) #define LIBRPZ_NORET __attribute__((__noreturn__)) #else /* ifdef LIBRPZ_HAVE_ATTR */ #define LIBRPZ_UNUSED #define LIBRPZ_PF(f, l) #define LIBRPZ_NORET #endif /* ifdef LIBRPZ_HAVE_ATTR */ typedef bool(librpz_parse_log_opt_t)(librpz_emsg_t *emsg, const char *arg); LIBDEF_F(parse_log_opt) typedef void(librpz_vpemsg_t)(librpz_emsg_t *emsg, const char *p, va_list args); LIBDEF_F(vpemsg) typedef void(librpz_pemsg_t)(librpz_emsg_t *emsg, const char *p, ...) LIBRPZ_PF(2, 3); LIBDEF_F(pemsg) typedef void(librpz_vlog_t)(librpz_log_level_t level, void *ctx, const char *p, va_list args); LIBDEF_F(vlog) typedef void(librpz_log_t)(librpz_log_level_t level, void *ctx, const char *p, ...) LIBRPZ_PF(3, 4); LIBDEF_F(log) typedef void(librpz_fatal_t)(int ex_code, const char *p, ...) LIBRPZ_PF(2, 3); extern void librpz_fatal(int ex_code, const char *p, ...) LIBRPZ_PF(2, 3) LIBRPZ_NORET; typedef void(librpz_rpz_assert_t)(const char *file, unsigned line, const char *p, ...) LIBRPZ_PF(3, 4); extern void librpz_rpz_assert(const char *file, unsigned line, const char *p, ...) LIBRPZ_PF(3, 4) LIBRPZ_NORET; typedef void(librpz_rpz_vassert_t)(const char *file, uint line, const char *p, va_list args); extern void librpz_rpz_vassert(const char *file, uint line, const char *p, va_list args) LIBRPZ_NORET; /* * As far as clients are concerned, all relative pointers or indexes in a * version of the mapped file except trie node parent pointers remain valid * forever. A client must release a version so that it can be garbage * collected by the file system. When dnsrpzd needs to expand the file, * it copies the old file to a new, larger file. Clients can continue * using the old file. * * Versions can also appear in a single file. Old nodes and trie values * within the file are not destroyed until all clients using the version * that contained the old values release the version. * * A client is marked as using version by connecting to the daemon. It is * marked as using all subsequent versions. A client releases all versions * by closing the connection or a range of versions by updating is slot * in the shared memory version table. * * As far as clients are concerned, there are the following possible librpz * failures: * - malloc() or other fatal internal librpz problems indicated by * a failing return from a librpz function * All operations will fail until client handle is destroyed and * recreated with librpz_client_detach() and librpz_client_create(). * - corrupt database detected by librpz code, corrupt database detected * by dnsrpzd, or disconnection from the daemon. * Current operations will fail. * * Clients assume that the file has already been unlinked before * the corrupt flag is set so that they do not race with the server * over the corruption of a single file. A client that finds the * corrupt set knows that dnsrpzd has already crashed with * abort() and is restarting. The client can re-connect to dnsrpzd * and retransmit its configuration, backing off as usual if anything * goes wrong. * * Searches of the database by a client do not need locks against dnsrpzd or * other clients, but a lock is used to protect changes to the connection * by competing threads in the client. The client provides functions * to serialize the concurrent use of any single client handle. * Functions that do nothing are appropriate for applications that are * not "threaded" or that do not share client handles among threads. * Otherwise, functions must be provided to librpz_clientcreate(). * Something like the following works with pthreads: * * static void * lock(void *mutex) { assert(pthread_mutex_lock(mutex) == 0); } * * static void * unlock(void *mutex) { assert(pthread_mutex_unlock(mutex) == 0); } * * static void * mutex_destroy(void *mutex) { assert(pthread_mutex_destroy(mutex) == 0); } * * * * At every instant, all of the data and pointers in the mapped file are valid. * Changes to trie node or other data are always made so that it and * all pointers in and to it remain valid for a time. Old versions are * eventually discarded. * * Dnsrpzd periodically defines a new version by setting aside all changes * made since the previous version was defined. Subsequent changes * made (only!) by dnsrpzd will be part of the next version. * * To discard an old version, dnsrpzd must know that all clients have stopped * using that version. Clients do that by using part of the mapped file * to tell dnsrpzd the oldest version that each client is using. * Dnsrpzd assigns each connecting client an entry in the cversions array * in the mapped file. The client puts version numbers into that entry * to signal to dnsrpzd which versions that can be discarded. * Dnsrpzd is free, as far as that client is concerned, to discard all * numerically smaller versions. A client can disclaim all versions with * the version number VERSIONS_ALL or 0. * * The race between a client changing its entry and dnsrpzd discarding a * version is resolved by allowing dnsrpzd to discard all versions * smaller or equal to the client's version number. If dnsrpzd is in * the midst of discarding or about to discard version N when the * client asserts N, no harm is done. The client depends only on * the consistency of version N+1. * * This version mechanism depends in part on not being exercised too frequently * Version numbers are 32 bits long and dnsrpzd creates new versions * at most once every 30 seconds. */ /* * Lock functions for concurrent use of a single librpz_client_t client handle. */ typedef void(librpz_mutex_t)(void *mutex); /* * List of connections to dnsrpzd daemons. */ typedef struct librpz_clist librpz_clist_t; /* * Client's handle on dnsrpzd. */ typedef struct librpz_client librpz_client_t; /** * Create the list of connections to the dnsrpzd daemon. * @param[out] emsg: error message * @param lock: start exclusive access to the client handle * @param unlock: end exclusive access to the client handle * @param mutex_destroy: release the lock * @param mutex: pointer to the lock for the client handle * @param log_ctx: NULL or resolver's context log messages */ typedef librpz_clist_t *(librpz_clist_create_t)(librpz_emsg_t *emsg, librpz_mutex_t *lock, librpz_mutex_t *unlock, librpz_mutex_t *mutex_destroy, void *mutex, void *log_ctx); LIBDEF_F(clist_create) /** * Release the list of dnsrpzd connections. */ typedef void(librpz_clist_detach_t)(librpz_clist_t **clistp); LIBDEF_F(clist_detach) /** * Create a librpz client handle. * @param[out] emsg: error message * @param clist: of dnsrpzd connections * @param cstr: string of configuration settings separated by ';' or '\n' * @param use_expired: true to not ignore expired zones * @return client handle or NULL if the handle could not be created */ typedef librpz_client_t *(librpz_client_create_t)(librpz_emsg_t *emsg, librpz_clist_t *clist, const char *cstr, bool use_expired); LIBDEF_F(client_create) /** * Start (if necessary) dnsrpzd and connect to it. * @param[out] emsg: error message * @param client handle * @param optional: true if it is ok if starting the daemon is not allowed */ typedef bool(librpz_connect_t)(librpz_emsg_t *emsg, librpz_client_t *client, bool optional); LIBDEF_F(connect) /** * Start to destroy a librpz client handle. * It will not be destroyed until the last set of RPZ queries represented * by a librpz_rsp_t ends. * @param client handle to be released * @return false on error */ typedef void(librpz_client_detach_t)(librpz_client_t **clientp); LIBDEF_F(client_detach) /** * State for a set of RPZ queries for a single DNS response * or for listing the database. */ typedef struct librpz_rsp librpz_rsp_t; /** * Start a set of RPZ queries for a single DNS response. * @param[out] emsg: error message for false return or *rspp=NULL * @param[out] rspp created context or NULL * @param[out] min_ns_dotsp: NULL or pointer to configured MIN-NS-DOTS value * @param client state * @param have_rd: RD=1 in the DNS request * @param have_do: DO=1 in the DNS request * @return false on error */ typedef bool(librpz_rsp_create_t)(librpz_emsg_t *emsg, librpz_rsp_t **rspp, int *min_ns_dotsp, librpz_client_t *client, bool have_rd, bool have_do); LIBDEF_F(rsp_create) /** * Finish RPZ work for a DNS response. */ typedef void(librpz_rsp_detach_t)(librpz_rsp_t **rspp); LIBDEF_F(rsp_detach) /** * Get the final, accumulated result of a set of RPZ queries. * Yield LIBRPZ_POLICY_UNDEFINED if * - there were no hits, * - there was a dispositive hit, be we have not recursed and are required * to recurse so that evil DNS authorities will not know we are using RPZ * - we have a hit and have recursed, but later data such as NSIP could * override * @param[out] emsg * @param[out] result describes the hit * or result->policy=LIBRPZ_POLICY_UNDEFINED without a hit * @param[out] result: current policy rewrite values * @param recursed: recursion has now been done even if it was not done * when the hit was found * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_rsp_result_t)(librpz_emsg_t *emsg, librpz_result_t *result, bool recursed, const librpz_rsp_t *rsp); LIBDEF_F(rsp_result) /** * Might looking for a trigger be worthwhile? * @param trig: look for this type of trigger * @param ipv6: true if trig is LIBRPZ_TRIG_CLIENT_IP, LIBRPZ_TRIG_IP, * or LIBRPZ_TRIG_NSIP and the IP address is IPv6 * @return: true if looking could be worthwhile */ typedef bool(librpz_have_trig_t)(librpz_trig_t trig, bool ipv6, const librpz_rsp_t *rsp); LIBDEF_F(have_trig) /** * Might looking for NSDNAME and NSIP triggers be worthwhile? * @return: true if looking could be worthwhile */ typedef bool(librpz_have_ns_trig_t)(const librpz_rsp_t *rsp); LIBDEF_F(have_ns_trig) /** * Convert the found client IP trie key to a CIDR block * @param[out] emsg * @param[out] prefix trigger * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_rsp_clientip_prefix_t)(librpz_emsg_t *emsg, librpz_prefix_t *prefix, librpz_rsp_t *rsp); LIBDEF_F(rsp_clientip_prefix) /** * Compute the owner name of the found or result trie key, usually to log it. * An IP address key might be returned as 8.0.0.0.127.rpz-client-ip. * example.com. might be a qname trigger. example.com.rpz-nsdname. could * be an NSDNAME trigger. * @param[out] emsg * @param[out] owner domain * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_rsp_domain_t)(librpz_emsg_t *emsg, librpz_domain_buf_t *owner, librpz_rsp_t *rsp); LIBDEF_F(rsp_domain) /** * Get the next RR of the LIBRPZ_POLICY_RECORD result after an initial use of * librpz_rsp_result() or librpz_itr_node() or after a previous use of * librpz_rsp_rr(). The RR is in uncompressed wire format including type, * class, ttl and length in network byte order. * @param[out] emsg * @param[out] typep: optional host byte order record type or ns_t_invalid (0) * @param[out] classp: class such as ns_c_in * @param[out] ttlp: TTL * @param[out] rrp: optional malloc() buffer containing the next RR or * NULL after the last RR * @param[out] result: current policy rewrite values * @param qname: used construct a wildcard CNAME * @param qname_size * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_rsp_rr_t)(librpz_emsg_t *emsg, uint16_t *typep, uint16_t *classp, uint32_t *ttlp, librpz_rr_t **rrp, librpz_result_t *result, const uint8_t *qname, size_t qname_size, librpz_rsp_t *rsp); LIBDEF_F(rsp_rr) /** * Get the next RR of the LIBRPZ_POLICY_RECORD result. * @param[out] emsg * @param[out] ttlp: TTL * @param[out] rrp: malloc() buffer with SOA RR without owner name * @param[out] result: current policy rewrite values * @param[out] origin: SOA owner name * @param[out] origin_size * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_rsp_soa_t)(librpz_emsg_t *emsg, uint32_t *ttlp, librpz_rr_t **rrp, librpz_domain_buf_t *origin, librpz_result_t *result, librpz_rsp_t *rsp); LIBDEF_F(rsp_soa) /** * Get the SOA serial number for a policy zone to compare with a known value * to check whether a zone transfer is complete. */ typedef bool(librpz_soa_serial_t)(librpz_emsg_t *emsg, uint32_t *serialp, const char *domain_nm, librpz_rsp_t *rsp); LIBDEF_F(soa_serial) /** * Save the current policy checking state. * @param[out] emsg * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_rsp_push_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp); LIBDEF_F(rsp_push) #define LIBRPZ_RSP_STACK_DEPTH 3 /** * Restore the previous policy checking state. * @param[out] emsg * @param[out] result: NULL or restored policy rewrite values * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_rsp_pop_t)(librpz_emsg_t *emsg, librpz_result_t *result, librpz_rsp_t *rsp); LIBDEF_F(rsp_pop) /** * Discard the most recently save policy checking state. * @param[out] emsg * @param[out] result: NULL or restored policy rewrite values * @return false on error */ typedef bool(librpz_rsp_pop_discard_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp); LIBDEF_F(rsp_pop_discard) /** * Disable a zone. * @param[out] emsg * @param znum * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_rsp_forget_zone_t)(librpz_emsg_t *emsg, librpz_cznum_t znum, librpz_rsp_t *rsp); LIBDEF_F(rsp_forget_zone) /** * Apply RPZ to an IP address. * @param[out] emsg * @param addr: address to check * @param ipv6: true for 16 byte IPv6 instead of 4 byte IPv4 * @param trig LIBRPZ_TRIG_CLIENT_IP, LIBRPZ_TRIG_IP, or LIBRPZ_TRIG_NSIP * @param hit_id: caller chosen * @param recursed: recursion has been done * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_ck_ip_t)(librpz_emsg_t *emsg, const void *addr, uint family, librpz_trig_t trig, librpz_result_id_t hit_id, bool recursed, librpz_rsp_t *rsp); LIBDEF_F(ck_ip) /** * Apply RPZ to a wire-format domain. * @param[out] emsg * @param domain in wire format * @param domain_size * @param trig LIBRPZ_TRIG_QNAME or LIBRPZ_TRIG_NSDNAME * @param hit_id: caller chosen * @param recursed: recursion has been done * @param[in,out] rsp state from librpz_itr_start() * @return false on error */ typedef bool(librpz_ck_domain_t)(librpz_emsg_t *emsg, const uint8_t *domain, size_t domain_size, librpz_trig_t trig, librpz_result_id_t hit_id, bool recursed, librpz_rsp_t *rsp); LIBDEF_F(ck_domain) /** * Ask dnsrpzd to refresh a zone. * @param[out] emsg error message * @param librpz_domain_t domain to refresh * @param client context * @return false after error */ typedef bool(librpz_zone_refresh_t)(librpz_emsg_t *emsg, const char *domain, librpz_rsp_t *rsp); LIBDEF_F(zone_refresh) /** * Get a string describing the database * @param license: include the license * @param cfiles: include the configuration file names * @param listens: include the local notify IP addresses * @param[out] emsg error message if the result is null * @param client context * @return malloc'ed string or NULL after error */ typedef char *(librpz_db_info_t)(librpz_emsg_t *emsg, bool license, bool cfiles, bool listens, librpz_rsp_t *rsp); LIBDEF_F(db_info) /** * Start a context for listing the nodes and/or zones in the mapped file * @param[out] emsg: error message for false return or *rspp=NULL * @param[out] rspp: created context or NULL * @param client context * @return false after error */ typedef bool(librpz_itr_start_t)(librpz_emsg_t *emsg, librpz_rsp_t **rspp, librpz_client_t *client); LIBDEF_F(itr_start) /** * Get mapped file memory allocation statistics. * @param[out] emsg: error message * @param rsp state from librpz_itr_start() * @return malloc'ed string or NULL after error */ typedef char *(librpz_mf_stats_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp); LIBDEF_F(mf_stats) /** * Get versions currently used by clients. * @param[out] emsg: error message * @param[in,out] rsp: state from librpz_itr_start() * @return malloc'ed string or NULL after error */ typedef char *(librpz_vers_stats_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp); LIBDEF_F(vers_stats) /** * Allocate a string describing the next zone or "" after the last zone. * @param[out] emsg * @param all_zones to list all instead of only requested zones * @param[in,out] rsp state from librpz_rsp_start() * @return malloc'ed string or NULL after error */ typedef char *(librpz_itr_zone_t)(librpz_emsg_t *emsg, bool all_zones, librpz_rsp_t *rsp); LIBDEF_F(itr_zone) /** * Describe the next trie node while dumping the database. * @param[out] emsg * @param[out] result describes node * or result->policy=LIBRPZ_POLICY_UNDEFINED after the last node. * @param all_zones to list all instead of only requested zones * @param[in,out] rsp state from librpz_itr_start() * @return: false on error */ typedef bool(librpz_itr_node_t)(librpz_emsg_t *emsg, librpz_result_t *result, bool all_zones, librpz_rsp_t *rsp); LIBDEF_F(itr_node) /** * RPZ policy to string with a backup buffer of POLICY2STR_SIZE size */ typedef const char *(librpz_policy2str_t)(librpz_policy_t policy, char *buf, size_t buf_size); #define POLICY2STR_SIZE sizeof("policy xxxxxx") LIBDEF_F(policy2str) /** * Trigger type to string. */ typedef const char *(librpz_trig2str_t)(librpz_trig_t trig); LIBDEF_F(trig2str) /** * Convert a number of seconds to a zone file duration string */ typedef const char *(librpz_secs2str_t)(time_t secs, char *buf, size_t buf_size); #define SECS2STR_SIZE sizeof("1234567w7d24h59m59s") LIBDEF_F(secs2str) /** * Parse a duration with 's', 'm', 'h', 'd', and 'w' units. */ typedef bool(librpz_str2secs_t)(librpz_emsg_t *emsg, time_t *val, const char *str0); LIBDEF_F(str2secs) /** * Translate selected rtypes to strings */ typedef const char *(librpz_rtype2str_t)(uint type, char *buf, size_t buf_size); #define RTYPE2STR_SIZE sizeof("type xxxxx") LIBDEF_F(rtype2str) /** * Local version of ns_name_ntop() for portability. */ typedef int(librpz_domain_ntop_t)(const u_char *src, char *dst, size_t dstsiz); LIBDEF_F(domain_ntop) /** * Local version of ns_name_pton(). */ typedef int(librpz_domain_pton2_t)(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen, bool lower); LIBDEF_F(domain_pton2) typedef union socku socku_t; typedef socku_t *(librpz_mk_inet_su_t)(socku_t *su, const struct in_addr *addrp, in_port_t port); LIBDEF_F(mk_inet_su) typedef socku_t *(librpz_mk_inet6_su_t)(socku_t *su, const struct in6_addr *addrp, uint32_t scope_id, in_port_t port); LIBDEF_F(mk_inet6_su) typedef bool(librpz_str2su_t)(socku_t *sup, const char *str); LIBDEF_F(str2su) typedef char *(librpz_su2str_t)(char *str, size_t str_len, const socku_t *su); LIBDEF_F(su2str) #define SU2STR_SIZE (INET6_ADDRSTRLEN + 1 + 6 + 1) /** * default path to dnsrpzd */ LIBDEF(const char *, librpz_dnsrpzd_path) #undef LIBDEF /* * This is the dlopen() interface to librpz. */ typedef const struct { const char *dnsrpzd_path; const char *version; librpz_parse_log_opt_t *parse_log_opt; librpz_log_level_val_t *log_level_val; librpz_set_log_t *set_log; librpz_vpemsg_t *vpemsg; librpz_pemsg_t *pemsg; librpz_vlog_t *vlog; librpz_log_t *log; librpz_fatal_t *fatal LIBRPZ_NORET; librpz_rpz_assert_t *rpz_assert LIBRPZ_NORET; librpz_rpz_vassert_t *rpz_vassert LIBRPZ_NORET; librpz_clist_create_t *clist_create; librpz_clist_detach_t *clist_detach; librpz_client_create_t *client_create; librpz_connect_t *connect; librpz_client_detach_t *client_detach; librpz_rsp_create_t *rsp_create; librpz_rsp_detach_t *rsp_detach; librpz_rsp_result_t *rsp_result; librpz_have_trig_t *have_trig; librpz_have_ns_trig_t *have_ns_trig; librpz_rsp_clientip_prefix_t *rsp_clientip_prefix; librpz_rsp_domain_t *rsp_domain; librpz_rsp_rr_t *rsp_rr; librpz_rsp_soa_t *rsp_soa; librpz_soa_serial_t *soa_serial; librpz_rsp_push_t *rsp_push; librpz_rsp_pop_t *rsp_pop; librpz_rsp_pop_discard_t *rsp_pop_discard; librpz_rsp_forget_zone_t *rsp_forget_zone; librpz_ck_ip_t *ck_ip; librpz_ck_domain_t *ck_domain; librpz_zone_refresh_t *zone_refresh; librpz_db_info_t *db_info; librpz_itr_start_t *itr_start; librpz_mf_stats_t *mf_stats; librpz_vers_stats_t *vers_stats; librpz_itr_zone_t *itr_zone; librpz_itr_node_t *itr_node; librpz_policy2str_t *policy2str; librpz_trig2str_t *trig2str; librpz_secs2str_t *secs2str; librpz_str2secs_t *str2secs; librpz_rtype2str_t *rtype2str; librpz_domain_ntop_t *domain_ntop; librpz_domain_pton2_t *domain_pton2; librpz_mk_inet_su_t *mk_inet_su; librpz_mk_inet6_su_t *mk_inet6_su; librpz_str2su_t *str2su; librpz_su2str_t *su2str; } librpz_0_t; extern librpz_0_t librpz_def_0; /* * Future versions can be upward compatible by defining LIBRPZ_DEF as * librpz_X_t. */ #define LIBRPZ_DEF librpz_def_0 #define LIBRPZ_DEF_STR "librpz_def_0" typedef librpz_0_t librpz_t; extern librpz_t *librpz; #if LIBRPZ_LIB_OPEN == 2 #include /** * link-load librpz * @param[out] emsg: error message * @param[in,out] dl_handle: NULL or pointer to new dlopen handle * @param[in] path: librpz.so path * @return address of interface structure or NULL on failure */ static inline librpz_t * librpz_lib_open(librpz_emsg_t *emsg, void **dl_handle, const char *path) { void *handle; librpz_t *new_librpz; emsg->c[0] = '\0'; /* * Close a previously opened handle on librpz.so. */ if (dl_handle != NULL && *dl_handle != NULL) { if (dlclose(*dl_handle) != 0) { snprintf(emsg->c, sizeof(librpz_emsg_t), "dlopen(NULL): %s", dlerror()); return (NULL); } *dl_handle = NULL; } /* * First try the main executable of the process in case it was * linked to librpz. * Do not worry if we cannot search the main executable of the process. */ handle = dlopen(NULL, RTLD_NOW | RTLD_LOCAL); if (handle != NULL) { new_librpz = dlsym(handle, LIBRPZ_DEF_STR); if (new_librpz != NULL) { if (dl_handle != NULL) { *dl_handle = handle; } return (new_librpz); } if (dlclose(handle) != 0) { snprintf(emsg->c, sizeof(librpz_emsg_t), "dlsym(NULL, " LIBRPZ_DEF_STR "): %s", dlerror()); return (NULL); } } if (path == NULL || path[0] == '\0') { snprintf(emsg->c, sizeof(librpz_emsg_t), "librpz not linked and no dlopen() path provided"); return (NULL); } handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); if (handle == NULL) { snprintf(emsg->c, sizeof(librpz_emsg_t), "dlopen(%s): %s", path, dlerror()); return (NULL); } new_librpz = dlsym(handle, LIBRPZ_DEF_STR); if (new_librpz != NULL) { if (dl_handle != NULL) { *dl_handle = handle; } return (new_librpz); } snprintf(emsg->c, sizeof(librpz_emsg_t), "dlsym(%s, " LIBRPZ_DEF_STR "): %s", path, dlerror()); dlclose(handle); return (NULL); } #elif defined(LIBRPZ_LIB_OPEN) /* * Statically link to the librpz.so DSO on systems without dlopen() */ static inline librpz_t * librpz_lib_open(librpz_emsg_t *emsg, void **dl_handle, const char *path) { (void)(path); if (dl_handle != NULL) { *dl_handle = NULL; } #if LIBRPZ_LIB_OPEN == 1 emsg->c[0] = '\0'; return (&LIBRPZ_DEF); #else /* if LIBRPZ_LIB_OPEN == 1 */ snprintf(emsg->c, sizeof(librpz_emsg_t), "librpz not available via ./configure"); return (NULL); #endif /* LIBRPZ_LIB_OPEN */ } #endif /* LIBRPZ_LIB_OPEN */