Man Linux: Main Page and Category List

NAME

       udns - stub DNS resolver library

SYNOPSYS

       #include <udns.h>
       struct dns_ctx;
       struct dns_query;
       extern struct dns_ctx dns_defctx;
       struct dns_ctx *ctx;
       typedef void dns_query_fn(ctx, void *result, void *data);
       typedef int
       dns_parse_fn(const unsigned char *qnd,
              const unsigned char *pkt,
              const unsigned char *cur,
              const unsigned char *end,
              void **resultp);

       cc ... -ludns

DESCRIPTION

       The  DNS  library,  udns,  implements  thread-safe  stub  DNS  resolver
       functionality, which may be used both traditional, syncronous  way  and
       asyncronously, with application-supplied event loop.

       While  DNS  works with both TCP and UDP, performing UDP query first and
       if the result does not fit in UDP buffer (512 bytes  max  for  original
       DNS  protocol), retrying the query over TCP, the library uses UDP only,
       but uses EDNS0 (RFC2671) extensions which allows larger UDP buffers.

       The library uses single UDP socket to perform all operations even  when
       asking  multiple  nameservers.   This way, it is very simple to use the
       library in asyncronous event-loop applications: an  application  should
       add  only  single  socket to the set of filedescriptors it monitors for
       I/O.

       The  library  uses  two  main  objects,  resolver   context   of   type
       struct dns_ctx,  and query structure of type struct dns_query, both are
       opaque for an application.  Resolver context holds  global  information
       about  the resolver, such as list of nameservers to use, list of active
       requests and the like.  Query objects holds information about a  single
       DNS query in progress and are allocated/processed/freed by the library.
       Pointer to query structure may be treated as an identifier  of  an  in-
       progress  query  and  may be used to cancel the asyncronous query or to
       wait for it to complete.

       Asyncronous interface works as  follows.   An  application  initializes
       resolver  context,  submits  any  number of queries for it using one of
       supplied dns_submit_XXX() routines (each return the query identifier as
       pointer  to query structure), waits for input on the UDP socket used by
       the  library,  and  gives  some  control  to  the  library  by  calling
       dns_ioevent()   and  dns_timeouts()  routines  when  appropriate.   The
       library performs all  necessary  processing  and  executes  application
       supplied  callback routine when a query completes (either successefully
       or not), giving it the result if any, pointer to the  resolver  context
       (from  which  completion  status may be obtained), and the data pointer
       supplied by an application when the query  has  been  submitted.   When
       submitting  a query, an application requests how to handle the reply --
       to either return raw DNS reply packet for its own low-level processing,
       or it may provide an address of parsing routine of type dns_parse_fn to
       perform conversion of on-wire format into easy to  use  data  structure
       (the  library  provides  parsing  routines  for  several  commonly used
       resource record types, as well as type-safe higher-level inteface  that
       requests  parsing  automatically).   The  I/O  monitoring  and  timeout
       handling may be either traditional select() or  poll()  based,  or  any
       callback-driven technique may be used.

       Additionally,  the  library  provides traditional syncronous interface,
       which may be intermixed with asyncronous calls (during syncronous query
       processing,  other  asyncronous  queries  for the same resolver context
       continued to be processed  as  usual).   An  application  uses  one  of
       numerous  dns_resolve_XXX() routines provided by the library to perform
       a query.  As with asyncronous  interface,  an  application  may  either
       request  to  return  raw  DNS packet or type-specific data structure by
       providing the parsing routine to handle the reply.  Every routine  from
       dns_resolve_XXX()  series  return  pointer to result or NULL in case of
       any error.  Query completion status (or length of the raw  DNS  packet)
       is  available from the resolver context using dns_status() routine, the
       same way as for the asyncronous interface.

       Internally, library uses on-wire format of domain names, referred to as
       DN format in this manual page.  This is a series of domain labels whith
       preceeding  length  byte,  terminated  by  zero-length  label  wich  is
       integral part of the DN format.  There are several routines provided to
       convert from traditional asciiz string to DN  and  back.   Higher-level
       type-specific  query interface hides the DN format from an application.

COMMON DEFINITIONS

       Every DNS Resource Record (RR) has a type and  a  class.   The  library
       defines  several  integer constants, DNS_C_XXX and DNS_T_XXX, to use as
       symbolic names for RR classes and types, such as DNS_C_IN for  Internet
       class,  DNS_T_A  for  IPv4  address  record type and so on.  See udns.h
       header file for complete list of all such constants.

       The following constants are defined in udns.h header file:

       DNS_MAXDN (255 bytes)
              Maximum length of the  domain  name  in  internal  (on-wire)  DN
              format.

       DNS_MAXLABEL (63 bytes)
              Maximum length of a single label in DN format.

       DNS_MAXNAME (1024 bytes)
              Maximum length of asciiz format of a domain name.

       DNS_HSIZE (12 bytes)
              Size of header in DNS packet.

       DNS_PORT (53)
              Default port to use when contacting a DNS server.

       DNS_MAXSERV (6 servers)
              Maximum number of DNS servers to use.

       DNS_MAXPACKET (512 bytes)
              Maximum  length  of  DNS UDP packet as specified by original DNS
              protocol

       DNS_EDNS0PACKET (4096 bytes)
              Default length of DNS UDP packet  (with  EDNS0  extensions)  the
              library  uses.   Note that recursive nameservers usually resides
              near the client asking them to resolve names, e.g. on  the  same
              LAN   segment   or   even  on  the  same  host,  so  UDP  packet
              fragmentation isn’t a problem in most cases.  Note also that the
              size  of  actual  packets  will be as many bytes as actual reply
              size requires, which is smaller than this value  in  almost  all
              cases.

       Additionally,  several  constants are defined to simplify work with raw
       DNS packets, such as DNS response codes (DNS_R_XXX), DNS header  layout
       (DNS_H_XXX)  and others.  Again, see udns.h for complete list.  Library
       error codes (DNS_E_XXX) are described later in this manual page.

RESOLVER CONTEXT

       Resolver context, of type struct dns_ctx, is an object which is  opaque
       to  an  application.   Several  routines  provided  by  the  library to
       initialize, copy and free resolver  contexts.   Most  other  high-level
       routines in this library expects a pointer to resolver context, ctx, as
       the first argument.  There is a  default  resolver  context  available,
       named  dns_defctx.  When the context pointer ctx passed to a routine is
       NULL, dns_defctx is used.  Several resolver contexts may be  active  at
       the  same  time, for example, when an application is multi-threaded and
       each thread uses resolver.

       In order to use the library, an application should initialize and  open
       one  or more resolver context objects.  These are two separate actions,
       performed by dns_init() (or dns_reset()), and dns_open().  Between  the
       two calls, an application is free to pefrorm additional initialisation,
       such as setting custom nameservers, options  or  domain  search  lists.
       Optionally,  in  case  no additional custom initialisation is required,
       dns_init() may open the context if do_open argument (see below) is non-
       zero.

       When  initializing  resolver context, the library uses information from
       system file /etc/resolv.conf (see resolv.conf(5)), consults environment
       variables $LOCALDOMAIN, $DNSCACHEIP, $NAMESERVERS and $RES_OPTIONS, and
       local host name to obtain list of local nameservers, domain name search
       list and various resolver options.

       The following routines to initialize resolver context are available:

       void dns_reset(ctx)
       int dns_init(ctx, int do_open)
              dns_reset()  resets  a given resolver context to default values,
              preparing it to be opened by dns_open().  It is ok to call  this
              routine  against  opened and active context - all active queries
              will be dropped, sockets will be closed and so on.  This routine
              does  not  initialize  any  parameters from system configuration
              files, use dns_init() for  this.   There’s  no  error  return  -
              operation   always   succeeds.    dns_init()   does   everything
              dns_reset() does, plus initializes  various  parameters  of  the
              context   according   to   system   configuration   and  process
              environment variables.  If do_open is non-zero, dns_init() calls
              dns_open(),   so   that  the  whole  library  initialisation  is
              performed in a single step.

       struct dns_ctx *dns_new(struct dns_ctx *copy)
       void dns_free(ctx)
              dns_new()  allocates  new  resolver  context  and   copies   all
              parameters for a given resolver context copy, or default context
              if copy is NULL, and returns  pointer  to  the  newly  allocated
              context.   The  context  being  copied  should  be  initialized.
              dns_new() may fail if there’s no memory available to make a copy
              of  copy,  in  which  case the routine will return NULL pointer.
              dns_free() is used to close assotiated socket and free  resolver
              context resources and cancelling (abandoming) all active queries
              assotiated with it.  It’s an  error  to  free  dns_defctx,  only
              dynamically allocated contexts returned by dns_new() are allowed
              to be freed by dns_free().

       int dns_add_serv(ctx, const char *servaddr)
       int dns_add_serv_s(ctx, const struct sockaddr *sa)
       int dns_add_srch(ctx, const char *srch)
              Add an  element  to  list  of  nameservers  (dns_add_serv(),  as
              asciiz-string servaddr with an IP address of the nameserver, and
              dns_add_serv_s(), as initialized socket address sa),  or  search
              list (dns_add_srch(), as a pointer to domain name) for the given
              context ctx.  If the  last  argument  is  a  NULL  pointer,  the
              corresponding  list  (search  or  nameserver)  is reset instead.
              Upon successeful completion, each routine returns new number  of
              elements  in  the list in question.  On error, negative value is
              returned and global variable errno is set appropriately.  It  is
              an  error to call any of this functions if the context is opened
              (after dns_open() or dns_init() with non-zero argument).

       int dns_set_opts(ctx, const char *opts)
              set resolver context options from opts string, in the  same  way
              as  processing options statement in resolv.conf and $RES_OPTIONS
              environment variable.

       void dns_set_opt(ctx, int opt, val)
              TODO The flags argument is a bitmask  with  the  following  bits
              defined:

              DNS_NOSRCH
                     do not perform domain name search in search list.

              DNS_NORD
                     do  not  request  recursion when performing queries (i.e.
                     don’t set RD flag in querues).

              DNS_AAONLY
                     request authoritative answers only (i.e. set AA  flag  in
                     queries).

       int dns_open(ctx)
       int dns_sock(const ctx)
       void dns_close(ctx)
              dns_open()  opens the UDP socket used for queries if not already
              open, and return assotiated filedescriptor (or negative value in
              case  of error).  Before any query can be submitted, the context
              should be opened using this routine.  And  before  opening,  the
              context should be initialized.  dns_sock() return the UDP socket
              if open, or -1 if not.  dns_close() closes the UDP socket if  it
              was open, and drops all active queries if any.

       int dns_active(const ctx)
              return  number  of  active  queries queued for the given context
              ctx, or zero if none.

       int dns_status(const ctx)
              return status code from last operation.  When  using  syncronous
              interface,  this  is  the  query  completion  status of the last
              query.  With asyncronous interface,  from  within  the  callback
              routine,  this  is  the query completion status of the query for
              which the callback  is  being  called.   When  query  submission
              fails,  this  is  the error code indicating failure reason.  All
              error codes  are  negative  and  are  represented  by  DNS_E_XXX
              constants described below.

       void dns_ioevent(ctx, time_t now)
              this  routine  may  be  called  by an application to process I/O
              events on the UDP socket used by the  library,  as  returned  by
              dns_sock().   The routine tries to receive incoming UDP datagram
              from the socket and process it.  The socket is set up to be non-
              blocking,  so  it is safe to call the routine even if there’s no
              data to read.  The routine will process as many datagrams as are
              queued  for  the  socket,  so  it  is safe to use it with either
              level-triggered or edge-triggered I/O monitoring model.  The now
              argument  is  either a current time as returned by time(), or 0,
              in which case the routine will obtain current time by it’s  own.

       int dns_timeouts(ctx, int maxwait, time_t now)
              process  any pending timeouts and return number of secounds from
              current time (now if it is not 0) to the time when  the  library
              wants  the application to pass it control to process more queued
              requests.  In case when there are no requests pending, this time
              is  -1.  The routine will not request a time larger than maxwait
              secounds if it is greather or equal to zero.  If now is  0,  the
              routine  will obtain current time by it’s own; when it is not 0,
              it should contain current time as returned by time().

       typedef void dns_utm_fn(ctx, int timeout, void *data)
       void dns_set_cbck(ctx, dns_utm_fn *utmfn, void *data)
              An application may use custom  callback-based  I/O  multiplexing
              mechanism.   Usually  such  a mechanism have concept of a timer,
              and an ability to register a timer event in a form of a callback
              routine which will be executed after certain amount of time.  In
              order to use such an event mechanism, udns provides  an  ability
              to  register and de-register timer events necessary for internal
              processing using whatever event mechanism an  application  uses.
              For  this  to  work,  it is possible to assotiate a pointer to a
              routine that will perform  necessary  work  for  (de)registering
              timer  events  with a given resolver context, and udns will call
              that routine at appropriate times.  Prototype of such a  routine
              is shown by dns_utm_fn typedef above.  Libudns assotiates single
              timer with resolver context.  User-supplied utmfn  routine  will
              be called by the library with the following arguments:

              ctx == NULL
                     delete  user  timer,  at  context  free  time  or when an
                     application changes  user  timer  request  routine  using
                     dns_set_cbck();

              ctx != NULL, timeout < 0
                     don’t  fire  timer  anymore,  when  there  are  no active
                     requests;

              ctx != NULL, timeout == 0
                     fire timer at the next possibility, but not immediately;

              ctx != NULL, timeout > 0
                     fire timer after timeout seconds after now.

              The data argument passed to the routine  will  be  the  same  as
              passed to dns_set_cbck().

              When  a  timer expires, an application should call dns_tmeouts()
              routine (see below).  Non-callback timer usage is provided  too.

       XXXX  TODO:  some  more resolver context routines, like dns_set_dbgfn()
       etc.

QUERY INTERFACE

       There are two ways to perform DNS queries: traditional syncronous  way,
       when  udns  performs all the necessary processing and return control to
       the application only when the query  completes,  and  asyncronous  way,
       when  an  application  submits one or more queries to the library using
       given  resolver  context,  and  waits  for  completion  by   monitoring
       filedescriptor  used by library and calling library routines to process
       input on that filedescriptor.  Asyncronous  mode  works  with  callback
       routines:  an  application  supplies an address of a routine to execute
       when the query completes, and a data pointer, which is  passed  to  the
       callback routine.

       Queries are submitted to the library in a form of struct dns_query.  To
       perform  asyncronous  query,  an   application   calls   one   of   the
       dns_submit_XXX()  rounines,  and  provides  necessary information for a
       callback, together with all  the  query  parameters.   When  the  query
       completes,  library  will  call  application-supplied callback routine,
       giving it the resolver context (wich holds  query  completion  status),
       dynamically  allocated  result (which will be either raw DNS packet or,
       if applicatin requested parsing the result by specifying non-NULL parse
       routine,  ready-to-use  type-specific  structure),  and  a data pointer
       provided by an application when it submitted  the  query.   It  is  the
       application who’s responsible for freeing the result memory.

       Generic query callback routine looks like this:
       typedef void
       dns_query_fn(ctx, void *result, void *data)
       Type-specific  query interface expects similar form of callback routine
       with the only difference in type of  result  argument,  which  will  be
       pointer to specific data structure (decoded reply) instead of this void
       pointer to raw DNS packet data.

       Result parsing routine looks like this:
       typedef int
       dns_parse_fn(const unsigned char *qdn,
             const unsigned char *pkt,
             const unsigned char *cur,
             const unsigned char *end,
             void **resultp);
       When called by the library, the arguments are as follows: pkt points to
       the start of the packet received; end points past the end of the packet
       received; cur points past the query DN in  the  query  section  of  the
       packet;  qdn  points  to  the  original  query  DN.  The routine should
       allocate a single buffer to hold the result, parse the reply filling in
       the buffer, and return the buffer using resultp argument.  It returns 0
       in case of error, or udns error code (DNS_E_XXX constants) in  case  of
       error.   Note  that by the time when the parse routine is called by the
       library, packet is already verified to  be  a  reply  to  the  original
       query, by matching query DN, query class and query type.

       Type-specific   query  inteface  supplies  necessary  parsing  routines
       automatically.

       In  case  of  error,   query   completion   status   as   returned   by
       dns_status(ctx), will contain one of the following values:

       positive value
              length of raw DNS packet if parsing is not requested.

       0      the  query was successeful and the reply points to type-specific
              data structure.

       DNS_E_TEMPFAIL
              temporary error, the resolver nameserver was not able to process
              our query or timed out.

       DNS_E_PROTOCOL
              protocol error, a nameserver returned malformed reply.

       DNS_E_NXDOMAIN
              the domain name does not exist.

       DNS_E_NODATA
              there is no data of requested type found.

       DNS_E_NOMEM
              out of memory while processing request.

       DNS_E_BADQUERY
              some  aspect  of  the  query  (most common is the domain name in
              question) is invalid, and the library can’t even start a  query.

       Library provides two series of routines which uses similar interface --
       one for asyncronous queries and another for syncronous queries.   There
       are   two   general   low-level  routines  in  each  series  to  submit
       (asyncronous interface) and resolve (syncronous interface) queries,  as
       well   as   several   type-specific   routines  with  more  easy-to-use
       interfaces.    To   submit   an   asyncronous   query,   use   one   of
       dns_submit_XXX()  routine,  each  of  which  accepts  query parameters,
       pointers to callback routine and to callback data, and optional current
       time   hint.   Note  type-specific  dns_submit_XXX()  routines  expects
       specific type of the callback routine as well, which accepts reply as a
       pointer  to  corresponding  structure,  not  a  void  pointer).   Every
       dns_submit_XXX() routine return pointer to internal query structure  of
       type struct dns_query, used as an identifier for the given query.

       To resolve a query syncronously, use one of dns_resolve_XXX() routines,
       which accepts the same query parameters (but not the callback pointers)
       as  corresponding  dns_submit_XXX(), and return the query result, which
       is the same as passed to the callback routine in  case  of  asyncronous
       interface.

       In   either   case,   the   result   memory  (if  the  query  completed
       successefully) is dynamically allocated  and  should  be  freed  by  an
       application.   If  the  query failed for any reason, the result will be
       NULL, and error status will be available from  dns_status(ctx)  routine
       as shown above.

       struct dns_query *
       dns_submit_dn(ctx,
            const unsigned char *dn, qcls, qtyp, flags,
            parse, cbck, data)
       struct dns_query *
       dns_submit_p(ctx,
            const char *name, qcls, qtyp, flags,
            parse, cbck, data)
          enum dns_class qcls;
          enum dns_type qtyp;
          int flags;
          dns_parse_fn *parse;
          dns_query_fn *cbck;
          void *data;
              submit  a  query  for  processing for the given resolver context
              ctx.  Two routines differs only in 3rd argument, which is domain
              name  in DN format (dn) or asciiz string (name).  The query will
              be performed for the given domain name, with type qtyp in  class
              qcls,  using  option  bits  in  flags,  using RR parsing routine
              pointed by parse if not-NULL, and upon completion, cbck function
              will  be  called with the data argument.  In case of successeful
              query submission, the routine return pointer to  internal  query
              structure  which may be treated as an identifier of the query as
              used by the  library,  and  may  be  used  as  an  argument  for
              dns_cancel()  routine.  In case of error, NULL will be returned,
              and context error status (available using dns_status()  routine)
              will  be set to corresponding error code, which in this case may
              be DNS_E_BADQUERY if the name of dn is invalid,  DNS_E_NOMEM  if
              there’s  no  memory  available  to  allocate query structure, or
              DNS_E_TEMPFAIL if an internal error occured.

       void *dns_resolve_dn(ctx,
            const unsigned char *dn, qcls, qtyp, flags, parse);
       void *dns_resolve_p(ctx,
            const char *name, qcls, qtyp, flags, parse)
          enum dns_class qcls;
          enum dns_type qtyp;
          int flags;
          dns_parse_fn *parse;
              syncronous  interface.   The  routines  perform  all  the  steps
              necessary  to resolve the given query and return the result.  If
              there’s no positive result for  any  reason,  all  the  routines
              return  NULL,  and  set  context  error  status (available using
              dns_status() routine) to indicate the error code.  If the  query
              was  successeful,  context  status  code will contain either the
              length of the raw DNS reply packet if parse  argument  was  NULL
              (in  which  case  the  return  value is pointer to the reply DNS
              packet), or 0 (in which case the return value is the  result  of
              parse  routine).   If the query successeful (return value is not
              NULL), the memory returned  was  dynamically  allocated  by  the
              library and should be free()d by application after use.

       void *dns_resolve(ctx, struct dns_query *q)
              wait   for   the   given   query   q,  as  returned  by  one  of
              dns_submit_XXX()  routines,  for  completion,  and  return   the
              result.  The callback routine will not be called for this query.
              After completion, the query identifier  q  is  not  valid.  Both
              dns_resolve_dn()  and  dns_resolve_p()  are just wrappers around
              corresponding submit routines and this dns_resolve() routine.

       void dns_cancel(ctx, struct dns_query *q)
              cancel an active query q, without calling  a  callback  routine.
              After completion, the query identifier q is not valid.

TYPE-SPECIFIC QUERIES

       In  addition  to  the  generic  low-level  query interface, the library
       provides a set of routines to perform specific queries in  a  type-safe
       manner,  as  well  as  parsers  for  several well-known resource record
       types.  The library implements high-level interface for A,  AAAA,  PTR,
       MX  and  TXT records and DNSBL and RHSBL functionality.  These routines
       returns specific types as  result  of  a  query,  instead  of  raw  DNS
       packets.  The following types and routines are available.

       struct dns_rr_null {
         char *dnsn_qname;     /* original query name */
         char *dnsn_cname;     /* canonical name */
         unsigned dnsn_ttl;    /* Time-To-Live (TTL) value */
         int dnsn_nrr;         /* number of records in the set */
       };

       NULL RR set, used as a base for all other RR type structures.  Every RR
       structure as used by the  library  have  four  standard  fields  as  in
       struct dns_rr_null.

   IN A Queries
       struct dns_rr_a4 {       /* IN A RRset */
         char *dnsa4_qname;     /* original query name */
         char *dnsa4_cname;     /* canonical name */
         unsigned dnsa4_ttl;    /* Time-To-Live (TTL) value */
         int dnsa4_nrr;         /* number of addresses in the set */
         struct in_addr dnsa4_addr[]; /* array of addresses */
       };
       typedef void
         dns_query_a4_fn(ctx, struct dns_rr_a4 *result, data)
       dns_parse_fn dns_parse_a4;
       struct dns_query *
       dns_submit_a4(ctx, const char *name, int flags,
          dns_query_a4_fn *cbck, data);
       struct dns_rr_a4 *
       dns_resolve_a4(ctx, const char *name, int flags);

       The  dns_rr_a4  structure  holds a result of an IN A query, which is an
       array of IPv4 addresses.  Callback routine for IN A queries expected to
       be   of  type  dns_query_a4_fn,  which  expects  pointer  to  dns_rr_a4
       structure  as  query  result  instead   of   raw   DNS   packet.    The
       dns_parse_a4()  is  used to convert raw DNS reply packet into dns_rr_a4
       structure (it is used internally and may  be  used  directly  too  with
       generic     query    interface).     Routines    dns_submit_a4()    and
       dns_resolve_a4() are used to  perform  A  IN  queries  in  a  type-safe
       manner.   The  name parameter is the domain name in question, and flags
       is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest
       (if  the  name  is absolute, that is, it ends up with a dot, DNS_NOSRCH
       flag will be set automatically).

   IN AAAA Queries
       struct dns_rr_a6 {       /* IN AAAA RRset */
         char *dnsa6_qname;     /* original query name */
         char *dnsa6_cname;     /* canonical name */
         unsigned dnsa6_ttl;    /* Time-To-Live (TTL) value */
         int dnsa6_nrr;         /* number of addresses in the set */
         struct in6_addr dnsa6_addr[]; /* array of addresses */
       };
       typedef void
         dns_query_a6_fn(ctx, struct dns_rr_a6 *result, data)
       dns_parse_fn dns_parse_a6;
       struct dns_query *
       dns_submit_a6(ctx, const char *name, int flags,
          dns_query_a6_fn *cbck, data);
       struct dns_rr_a6 *
       dns_resolve_a6(ctx, const char *name, int flags);

       The dns_rr_a6 structure holds a result of an IN AAAA query, which is an
       array of IPv6 addresses.  Callback routine for IN AAAA queries expected
       to be of type  dns_query_a6_fn,  which  expects  pointer  to  dns_rr_a6
       structure   as   query   result   instead   of  raw  DNS  packet.   The
       dns_parse_a6() is used to convert raw DNS reply packet  into  dns_rr_a6
       structure  (it  is  used  internally  and may be used directly too with
       generic    query    interface).     Routines    dns_submit_a6()     and
       dns_resolve_a6()  are  used  to  perform AAAA IN queries in a type-safe
       manner.  The name parameter is the domain name in question,  and  flags
       is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest
       (if the name is absolute, that is, it ends up with  a  dot,  DNS_NOSRCH
       flag will be set automatically).

   IN PTR Queries
       struct dns_rr_ptr {       /* IN PTR RRset */
         char *dnsptr_qname;     /* original query name */
         char *dnsptr_cname;     /* canonical name */
         unsigned dnsptr_ttl;    /* Time-To-Live (TTL) value */
         int dnsptr_nrr;         /* number of domain name pointers */
         char *dnsptr_ptr[];     /* array of domain name pointers */
       };
       typedef void
         dns_query_ptr_fn(ctx, struct dns_rr_ptr *result, data)
       dns_parse_fn dns_parse_ptr;
       struct dns_query *
       dns_submit_a4ptr(ctx, const struct in_addr *addr,
          dns_query_ptr_fn *cbck, data);
       struct dns_rr_ptr *
       dns_resolve_a4ptr(ctx, const struct in_addr *addr);
       struct dns_query *
       dns_submit_a6ptr(ctx, const struct in6_addr *addr,
          dns_query_ptr_fn *cbck, data);
       struct dns_rr_ptr *
       dns_resolve_a6ptr(ctx, const struct in6_addr *addr);

       The dns_rr_ptr structure holds a result of an IN PTR query, which is an
       array of domain name  pointers  for  a  given  IPv4  or  IPv6  address.
       Callback   routine   for   IN  PTR  queries  expected  to  be  of  type
       dns_query_ptr_fn, which expects  pointer  to  dns_rr_ptr  structure  as
       query result instead of raw DNS packet.  The dns_parse_ptr() is used to
       convert raw DNS reply packet into  dns_rr_ptr  structure  (it  is  used
       internally  and may be used directly too with generic query interface).
       Routines dns_submit_a4ptr() and dns_resolve_a4ptr() are used to perform
       IN  PTR  queries  for  IPv4  addresses  in a type-safe manner. Routines
       dns_submit_a6ptr() and dns_resolve_a6ptr() are used to perform  IN  PTR
       queries for IPv6 addresses.

   IN MX Queries
       struct dns_mx {          /* single MX record */
         int priority;          /* priority value of this MX */
         char *name;            /* domain name of this MX */
       };
       struct dns_rr_mx {       /* IN MX RRset */
         char *dnsmx_qname;     /* original query name */
         char *dnsmx_cname;     /* canonical name */
         unsigned dnsmx_ttl;    /* Time-To-Live (TTL) value */
         int dnsmx_nrr;         /* number of mail exchangers in the set */
         struct dns_mx dnsmx_mx[]; /* array of mail exchangers */
       };
       typedef void
         dns_query_mx_fn(ctx, struct dns_rr_mx *result, data)
       dns_parse_fn dns_parse_mx;
       struct dns_query *
       dns_submit_mx(ctx, const char *name, int flags,
          dns_query_mx_fn *cbck, data);
       struct dns_rr_mx *
       dns_resolve_mx(ctx, const char *name, int flags);

       The  dns_rr_mx  structure holds a result of an IN MX query, which is an
       array of mail exchangers for a given domain.  Callback routine  for  IN
       MX  queries  expected  to  be  of  type  dns_query_mx_fn, which expects
       pointer to dns_rr_mx structure as  query  result  instead  of  raw  DNS
       packet.   The  dns_parse_mx()  is  used to convert raw DNS reply packet
       into dns_rr_mx structure  (it  is  used  internally  and  may  be  used
       directly  too  with generic query interface).  Routines dns_submit_mx()
       and dns_resolve_mx() are used to perform IN MX queries in  a  type-safe
       manner.   The  name parameter is the domain name in question, and flags
       is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest
       (if  the  name  is absolute, that is, it ends up with a dot, DNS_NOSRCH
       flag will be set automatically).

   TXT Queries
       struct dns_txt {          /* single TXT record */
         int len;                /* length of the text */
         unsigned char *txt;     /* pointer to the text */
       };
       struct dns_rr_txt {       /* TXT RRset */
         char *dnstxt_qname;     /* original query name */
         char *dnstxt_cname;     /* canonical name */
         unsigned dnstxt_ttl;    /* Time-To-Live (TTL) value */
         int dnstxt_nrr;         /* number of text records in the set */
         struct dns_txt dnstxt_txt[]; /* array of TXT records */
       };
       typedef void
         dns_query_txt_fn(ctx, struct dns_rr_txt *result, data)
       dns_parse_fn dns_parse_txt;
       struct dns_query *
       dns_submit_txt(ctx, const char *name, enum dns_class qcls,
          int flags, dns_query_txt_fn *cbck, data);
       struct dns_rr_txt *
       dns_resolve_txt(ctx, const char *name,
                    enum dns_class qcls, int flags);

       The dns_rr_txt structure holds a result of a TXT  query,  which  is  an
       array  of  text  records for a given domain name.  Callback routine for
       TXT queries expected to be  of  type  dns_query_txt_fn,  which  expects
       pointer  to  dns_rr_txt  structure  as  query result instead of raw DNS
       packet.  The dns_parse_txt() is used to convert raw  DNS  reply  packet
       into  dns_rr_txt  structure  (it  is  used  internally  and may be used
       directly too with generic query interface).  Routines  dns_submit_txt()
       and  dns_resolve_txt() are used to perform IN MX queries in a type-safe
       manner.  The name parameter is the domain name in question,  and  flags
       is query flags bitmask, with one bit, DNS_NOSRCH, of practical interest
       (if the name is absolute, that is, it ends up with  a  dot,  DNS_NOSRCH
       flag  will  be  set  automatically).   Note  that  each  TXT  string is
       represented by struct dns_txt, while zero-terminated (and the len field
       of the structure does not include the terminator), may contain embedded
       null characters -- content of TXT records is  not  interpreted  by  the
       library in any way.

   SRV Queries
       struct dns_srv {          /* single SRV record */
         int priority;           /* priority of the record */
         int weight;             /* weight of the record */
         int port;               /* the port number to connect to */
         char *name;             /* target host name */
       };
       struct dns_rr_srv {       /* SRV RRset */
         char *dnssrv_qname;     /* original query name */
         char *dnssrv_cname;     /* canonical name */
         unsigned dnssrv_ttl;    /* Time-To-Live (TTL) value */
         int dnssrv_nrr;         /* number of text records in the set */
         struct dns_srv dnssrv_srv[]; /* array of SRV records */
       };
       typedef void
         dns_query_srv_fn(ctx, struct dns_rr_srv *result, data)
       dns_parse_fn dns_parse_srv;
       struct dns_query *
       dns_submit_srv(ctx, const char *name, const char *service, const char *protocol,
          int flags, dns_query_txt_fn *cbck, data);
       struct dns_rr_srv *
       dns_resolve_srv(ctx, const char *name, const char *service, const char *protocol,
                    int flags);

       The  dns_rr_srv  structure holds a result of an IN SRV (rfc2782) query,
       which is an array of servers (together with  port  numbers)  which  are
       performing  operations  for  a  given service using given protocol on a
       target domain name.  Callback routine for IN SRV queries expected to be
       of type dns_query_srv_fn, which expects pointer to dns_rr_srv structure
       as query result instead of raw DNS packet.  The dns_parse_srv() is used
       to  convert  raw DNS reply packet into dns_rr_srv structure (it is used
       internally and may be used directly too with generic query  interface).
       Routines  dns_submit_srv() and dns_resolve_srv() are used to perform IN
       SRV queries in a type-safe manner.  The name parameter  is  the  domain
       name  in  question,  service  and protocl specifies the service and the
       protocol in question (the library will construct query DN according  to
       rfc2782  rules)  and may be NULL (in this case the library assumes name
       parameter holds the complete SRV  query),  and  flags  is  query  flags
       bitmask,  with  one bit, DNS_NOSRCH, of practical interest (if the name
       is absolute, that is, it ends up with a dot, DNS_NOSRCH  flag  will  be
       set automatically).

   NAPTR Queries
       struct dns_naptr {        /* single NAPTR record */
         int order;              /* record order */
         int preference;         /* preference of this record */
         char *flags;            /* application-specific flags */
         char *services;         /* service parameters */
         char *regexp;           /* substitutional regular expression */
         char *replacement;      /* replacement string */
       };
       struct dns_rr_naptr {     /* NAPTR RRset */
         char *dnsnaptr_qname;   /* original query name */
         char *dnsnaptr_cname;   /* canonical name */
         unsigned dnsnaptr_ttl;  /* Time-To-Live (TTL) value */
         int dnsnaptr_nrr;       /* number of text records in the set */
         struct dns_naptr dnsnaptr_naptr[]; /* array of NAPTR records */
       };
       typedef void
         dns_query_naptr_fn(ctx, struct dns_rr_naptr *result, data)
       dns_parse_fn dns_parse_naptr;
       struct dns_query *
       dns_submit_naptr(ctx, const char *name, int flags,
          dns_query_txt_fn *cbck, data);
       struct dns_rr_naptr *
       dns_resolve_naptr(ctx, const char *name, int flags);

       The  dns_rr_naptr  structure  holds  a  result of an IN NAPTR (rfc3403)
       query.  Callback routine for IN NAPTR queries expected to  be  of  type
       dns_query_naptr_fn,  expects pointer to dns_rr_naptr structure as query
       result instead of raw DNS packet.  The  dns_parse_naptr()  is  used  to
       convert  raw  DNS  reply packet into dns_rr_naptr structure (it is used
       internally and may be used directly too with generic query  interface).
       Routines dns_submit_naptr() and dns_resolve_naptr() are used to perform
       IN NAPTR queries in a type-safe manner.   The  name  parameter  is  the
       domain  name  in  question,  and flags is query flags bitmask, with one
       bit, DNS_NOSRCH, of practical interest (if the name is  absolute,  that
       is,  it ends up with a dot, DNS_NOSRCH flag will be set automatically).

   DNSBL Interface
       A DNS-based  blocklists,  or  a  DNSBLs,  are  in  wide  use  nowadays,
       especially  to protect mailservers from spammers.  The library provides
       DNSBL interface, a set of routines to perform queries  against  DNSBLs.
       Routines accepts an IP address (IPv4 and IPv6 are both supported) and a
       base DNSBL zone as query parameters, and returns  either  dns_rr_a4  or
       dns_rr_txt structure.  Note that IPv6 interface return IPv4 RRset.

       struct dns_query *
       dns_submit_a4dnsbl(ctx,
         const struct in_addr *addr, const char *dnsbl,
         dns_query_a4_fn *cbck, void *data);
       struct dns_query *
       dns_submit_a4dnsbl_txt(ctx,
         const struct in_addr *addr, const char *dnsbl,
         dns_query_txt_fn *cbck, void *data);
       struct dns_query *
       dns_submit_a6dnsbl(ctx,
         const struct in6_addr *addr, const char *dnsbl,
         dns_query_a4_fn *cbck, void *data);
       struct dns_query *
       dns_submit_a6dnsbl_txt(ctx,
         const struct in6_addr *addr, const char *dnsbl,
         dns_query_txt_fn *cbck, void *data);
       struct dns_rr_a4 *dns_resolve_a4dnsbl(ctx,
         const struct in_addr *addr, const char *dnsbl)
       struct dns_rr_txt *dns_resolve_a4dnsbl_txt(ctx,
         const struct in_addr *addr, const char *dnsbl)
       struct dns_rr_a4 *dns_resolve_a6dnsbl(ctx,
         const struct in6_addr *addr, const char *dnsbl)
       struct dns_rr_txt *dns_resolve_a6dnsbl_txt(ctx,
         const struct in6_addr *addr, const char *dnsbl)
       Perform  (submit  or  resolve) a DNSBL query for the given dnsbl domain
       and an IP addr in question, requesting either A or TXT records.

   RHSBL Interface
       RHSBL is similar to DNSBL, but instead of an IP address, the  parameter
       is a domain name.

       struct dns_query *
       dns_submit_rhsbl(ctx, const char *name, const char *rhsbl,
         dns_query_a4_fn *cbck, void *data);
       struct dns_query *
       dns_submit_rhsbl_txt(ctx, const char *name, const char *rhsbl,
         dns_query_txt_fn *cbck, void *data);
       struct dns_rr_a4 *
       dns_resolve_rhsbl(ctx, const char *name, const char *rhsbl);
       struct dns_rr_txt *
       dns_resolve_rhsbl_txt(ctx, const char *name, const char *rhsbl);
       Perform  (submit  or  resolve) a RHSBL query for the given rhsbl domain
       and name in question, requesting either A or TXT records.

LOW-LEVEL INTERFACE

   Domain Names (DNs)
       A DN is a series of domain name labels each starts  with  length  byte,
       followed  by  empty  label  (label  with  zero  length).  The following
       routines to work with DNs are provided.

       unsigned dns_dnlen(const unsigned char *dn)
              return length of the domain name dn, including  the  terminating
              label.

       unsigned dns_dnlabels(const unsigned char *dn)
              return number of non-zero labels in domain name dn.

       unsigned dns_dnequal(dn1, dn2)
         const unsigned char *dn1, *dn2;
              test  whenever  the  two  domain  names,  dn1 and dn2, are equal
              (case-insensitive).  Return domain name length if equal or 0  if
              not.

       unsigned dns_dntodn(sdn, ddn, dnsiz)
         const unsigned char *sdn;
         unsigned char *ddn;
         unsigned dnsiz;
              copies  the  source domain name sdn to destination buffer ddn of
              size dnsiz.  Return domain name length or 0 if ddn is too small.

       int dns_ptodn(name, namelen, dn, dnsiz, isabs)
       int dns_sptodn(name, dn, dnsiz)
         const char *name; unsigned namelen;
         unsigned char *dn; unsigned dnsiz;
         int *isabs;
              convert asciiz name name of length namelen to DN format, placing
              result into buffer dn of size dnsiz.  Return length of the DN if
              successeful,  0  if  the  dn  buffer  supplied  is too small, or
              negative value if name is invalid.  If  isabs  is  non-NULL  and
              conversion  was successeful, *isabs will be set to either 1 or 0
              depending whenever name was absolute (i.e. ending with a dot) or
              not.   Name  length,  namelength,  may  be  zero,  in which case
              strlen(name) will be used.   Second  form,  dns_sptodn(),  is  a
              simplified form of dns_ptodn(), equivalent to
              dns_ptodn(name, 0, dn, dnlen, 0).

       extern const unsigned char dns_inaddr_arpa_dn[]
       int dns_a4todn(const struct in_addr *addr, const unsigned char *tdn,
             unsigned char *dn, unsigned dnsiz)
       int dns_a4ptodn(const struct in_addr *addr, const char *tname,
             unsigned char *dn, unsigned dnsiz)
       extern const unsigned char dns_ip6_arpa_dn[]
       int dns_a6todn(const struct in6_addr *addr, const unsigned char *tdn,
             unsigned char *dn, unsigned dnsiz)
       int dns_a6ptodn(const struct in6_addr *addr, const char *tname,
             unsigned char *dn, unsigned dnsiz)
              several  variants  of  routines to convert IPv4 and IPv6 address
              addr into reverseDNS-like domain  name  in  DN  format,  storing
              result  in  dn  of  size dnsiz.  tdn (or tname) is the base zone
              name, like in-addr.arpa for IPv4 or in6.arpa for IPv6.   If  tdn
              (or tname) is NULL, dns_inaddr_arpa_dn (or dns_ip6_arpa_dn) will
              be used.  The routines may be used to construct a DN for a DNSBL
              lookup for example.  All routines return length of the resulting
              DN on success, -1 if resulting DN is invalid, or  0  if  the  dn
              buffer (dnsiz) is too small.  To hold standard rDNS DN, a buffer
              of size DNS_A4RSIZE (30 bytes) for IPv4 address, or  DNS_A6RSIZE
              (74 bytes) for IPv6 address, is sufficient.

       int dns_dntop(dn, name, namesiz)
          const unsigned char *dn;
          const char *name; unsigned namesiz;
              convert  domain  name  dn in DN format to asciiz string, placing
              result into name buffer of  size  namesiz.   Maximum  length  of
              asciiz  representation  of  domain  name  is  DNS_MAXNAME (1024)
              bytes.  Root domain is  represented  as  empty  string.   Return
              length  of  the resulting name (including terminating character,
              i.e. strlen(name)+1) on success, 0 if the  name  buffer  is  too
              small,  or  negative  value  if  dn is invalid (last case should
              never happen since all routines in this  library  which  produce
              domain names ensure the DNs generated are valid).

       const char *dns_dntosp(const unsigned char *dn)
              convert  domain  name  dn  in  DN  format to asciiz string using
              static buffer.  Return the resulting asciiz string on success or
              NULL on failure.  Note since this routine uses static buffer, it
              is not thread-safe.

       unsigned dns_dntop_size(const unsigned char *dn)
              return the buffer size needed to convert the dn domain  name  in
              DN format to asciiz string, for dns_dntop().  The routine return
              either the size of buffer required, including the trailing  zero
              byte, or 0 if dn is invalid.

   Working with DNS Packets
       The  following  routines  are provided to encode and decode DNS on-wire
       packets.  This is low-level interface.

       DNS response codes (returned by dns_rcode()  routine)  are  defined  as
       constants  prefixed  with  DNS_R_.   See  udns.h  header  file  for the
       complete   list.    In   particular,   constants   DNS_R_NOERROR   (0),
       DNS_R_SERVFAIL, DNS_R_NXDOMAIN may be of interest to an application.

       unsigned dns_get16(const unsigned char *p)
       unsigned dns_get32(const unsigned char *p)
              helper  routines,  convert  16-bit  or 32-bit integer in on-wire
              format pointed to by p to unsigned.

       unsigned char *dns_put16(unsigned char *d, unsigned n)
       unsigned char *dns_put32(unsigned char *d, unsigned n)
              helper routine, convert unsigned 16-bit or 32-bit integer  n  to
              on-wire format to buffer pointed to by d, return d+2 or d+4.

       DNS_HSIZE (12)
              defines  size  of  DNS  header.   Data section in the DNS packet
              immediately follows the header.  In the header, there are  query
              identifier (id), various flags and codes, and number of resource
              records in various data sections.  See udns.h  header  file  for
              complete list of DNS header definitions.

       unsigned dns_qid(const unsigned char *pkt)
       int dns_rd(const unsigned char *pkt)
       int dns_tc(const unsigned char *pkt)
       int dns_aa(const unsigned char *pkt)
       int dns_qr(const unsigned char *pkt)
       int dns_ra(const unsigned char *pkt)
       unsigned dns_opcode(const unsigned char *pkt)
       unsigned dns_rcode(const unsigned char *pkt)
       unsigned dns_numqd(const unsigned char *pkt)
       unsigned dns_numan(const unsigned char *pkt)
       unsigned dns_numns(const unsigned char *pkt)
       unsigned dns_numar(const unsigned char *pkt)
       const unsigned char *dns_payload(const unsigned char *pkt)
              return  various  parts  from  the  DNS  packet header pkt: query
              identifier  (qid),  recursion  desired  (rd)  flag,   truncation
              occured   (tc)  flag,  authoritative  answer  (aa)  flag,  query
              response (qr) flag, recursion  available  (ra)  flag,  operation
              code  (opcode),  result  code  (rcode),  number  of  entries  in
              question section (numqd), number of answers (numan),  number  of
              authority records (numns), number of additional records (numar),
              and the pointer to the packet data (payload).

       int dns_getdn(pkt, curp, pkte, dn, dnsiz)
       const unsigned char *dns_skipdn(cur, pkte)
          const unsigned char *pkt, *pkte, **curp, *cur;
          unsigned char *dn; unsigned dnsiz;
              dns_getdn() extract DN from DNS packet  pkt  which  ends  before
              pkte  starting at position *curp into buffer pointed to by dn of
              size dnsiz.  Upon successeful completion, *curp  will  point  to
              the next byte in the packet after the extracted domain name.  It
              return positive number (length of the DN if dn) upon successeful
              completion,  negative  value  on error (when the packet contains
              invalid data), or zero if the dnsiz is too small (maximum length
              of  a domain name is DNS_MAXDN).  dns_skipdn() return pointer to
              the next byte in DNS packet which ends up before  pkte  after  a
              domain  name which starts at the cur byte, or NULL if the packet
              is invalid.  dns_skipdn() is more or  less  equivalent  to  what
              dns_getdn() does, except it does not actually extract the domain
              name in question, and uses simpler interface.

       struct dns_rr {
         unsigned char dnsrr_dn[DNS_MAXDN]; /* the RR DN name */
         enum dns_class dnsrr_cls;          /* class of the RR */
         enum dns_type  dnsrr_typ;          /* type of the RR */
         unsigned dnsrr_ttl;                /* TTL value */
         unsigned dnsrr_dsz;                /* size of data in bytes */
         const unsigned char *dnsrr_dptr;   /* pointer to the first data byte */
         const unsigned char *dnsrr_dend;   /* next byte after RR */
       };
              The dns_rr structure is used to hold  information  about  single
              DNS Resource Record (RR) in an easy to use form.

       struct dns_parse {
         const unsigned char *dnsp_pkt; /* pointer to the packet being parsed */
         const unsigned char *dnsp_end; /* end of the packet pointer */
         const unsigned char *dnsp_cur; /* current packet positionn */
         const unsigned char *dnsp_ans; /* pointer to the answer section */
         int dnsp_rrl;                  /* number of RRs left */
         int dnsp_nrr;                  /* number of relevant RRs seen so far */
         unsigned dnsp_ttl;             /* TTL value so far */
         const unsigned char *dnsp_qdn; /* the domain of interest or NULL */
         enum dns_class dnsp_qcls;      /* class of interest or 0 for any */
         enum dns_type  dnsp_qtyp;      /* type of interest or 0 for any */
         unsigned char dnsp_dnbuf[DNS_MAXDN]; /* domain name buffer */
       };
              The  dns_parse  structure is used to parse DNS reply packet.  It
              holds information  about  the  packet  being  parsed  (dnsp_pkt,
              dnsp_end  and  dnsp_cur  fields),  number  of RRs in the current
              section left to do, and the information about specific RR  which
              we’re looking for (dnsp_qdn, dnsp_qcls and dnsp_qtyp fields).

       int dns_initparse(struct dns_parse *p,
         const unsigned char *qdn,
         const unsigned char *pkt,
         const unsigned char *cur,
         const unsigned char *end)
              initializes  the RR parsing structure p.  Arguments pkt, cur and
              end should describe the received packet: pkt is the start of the
              packet, end points to the next byte after the end of the packet,
              and cur points past the query DN  in  query  section  (to  query
              class+type  information).  And qdn points to the query DN.  This
              is   the   arguments   passed   to    dns_parse_fn()    routine.
              dns_initparse()  initializes  dnsp_pkt,  dnsp_end  and  dnsp_qdn
              fields to the corresponding arguments, extracts and  initializes
              dnsp_qcls  and  dnsp_qtyp  fields  to  the  values  found at cur
              pointer, initializes dnsp_cur and dnsp_ans fields  to  be  cur+4
              (to the start of answer section), and initializes dnsp_rrl field
              to be number of entries in answer section. dnsp_ttl will be  set
              to max TTL value, 0xffffffff, and dnsp_nrr to 0.

       int dns_nextrr(struct dns_parse *p, struct dns_rr *rr);
              searches  for  next  RR  in  the  packet  based  on the criteria
              provided in the p structure, filling in  the  rr  structure  and
              advancing  p->dnsp_cur  to  the  next  RR  in  the  packet.   RR
              selection is based on dnsp_qdn, dnsp_qcls and  dnsp_qtyp  fields
              in the dns_parse structure.  Any (or all) of the 3 fields may be
              0, which means any actual value from the packet  is  acceptable.
              In  case the field isn’t 0 (or NULL for dnsp_qdn), only RRs with
              corresponding  characteristics  are  acceptable.   Additionally,
              when dnsp_qdn is non-NULL, dns_nextrr() performs automatic CNAME
              expansion.  Routine will return positive value on success, 0  in
              case  it  reached  the  end  of  current  section  in the packet
              (p->dnsp_rrl is zero), or negative value if next RR can  not  be
              decoded   (packet  format  is  invalid).   The  routine  updates
              p->dnsp_qdn automatically when this field  is  non-NULL  and  it
              encounters   appropriate  CNAME  RRs  (saving  CNAME  target  in
              p->dnsp_dnbuf), so after end of the  process,  p->dnsp_qdn  will
              point  to canonical name of the domain in question.  The routine
              updates p->dnsp_ttl value to be  the  minimum  TTL  of  all  RRs
              found.

       void dns_rewind(struct dns_parse *p, const unsigned char *qdn)
              this routine "rewinds" the packet parse state structure to be at
              the  same  state  as  after  a  call  to  dns_initparse(),  i.e.
              reposition  the parse structure p to the start of answer section
              and initialize p->dnsp_rrl to the number of  entries  in  answer
              section.

       int dns_stdrr_size(const struct dns_parse *p);
              return  size  to  hold  standard RRset structure information, as
              shown in dns_rr_null structure  (for  the  query  and  canonical
              names).   Used  to  calculate  amount  of memory to allocate for
              common part of type-specific RR structures in parsing  routines.

       void *dns_stdrr_finish(struct dns_rr_null *ret, char *cp,
         const struct dns_parse *p);
              initializes  standard RRset fields in ret structure using buffer
              pointed to by cp, which should have at least as  many  bytes  as
              dns_stdrr_size(p)  returned.   Used  to  finalize common part of
              type-specific RR structures in parsing routines.

       See library source for  usage  examples  of  all  the  above  low-level
       routines, especially source of the parsing routines.

   Auxilary Routines
       int dns_pton(int af, const char *src, void *dst);
              privides  functionality similar to standard inet_pton() routine,
              to convert printable representation of an IP address  of  family
              af  (either  AF_INET  or AF_INET6) pointed to by src into binary
              form  suitable  for  socket  addresses  and  transmission   over
              network,  in  buffer  pointed to by dst.  The destination buffer
              should be of size 4 for AF_INET family or 16 for AF_INET6.   The
              return  value  is  positive  on success, 0 if src is not a valid
              text representation of an address of family af, or  negative  if
              the given address family is not supported.

       const char *dns_ntop(int af, const void *src,
           char *dst, int dstsize)
              privides  functionality similar to standard inet_ntop() routine,
              to convert binary representation of an IP address of  family  af
              (either  AF_INET  or AF_INET6) pointed to by src (either 4 or 16
              bytes) into printable form in buffer in buffer pointed to by dst
              of  size  dstsize.  The destination buffer should be at least of
              size 16 bytes for AF_INET family or 46 bytes for AF_INET6.   The
              return  value  is  either dst, or NULL pointer if dstsize is too
              small to hold this address or if the given address family is not
              supported.

AUTHOR

       The udns library has been written by Michael Tokarev, mjt@corpit.ru.

VERSION

       This  manual page corresponds to udns version 0.0.9, released Jan-2007.