"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/dns/include/dns/librpz.h" (4 Sep 2020, 31390 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "librpz.h" see the Fossies "Dox" file reference documentation.

    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);
  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 *
  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 *
  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 */