Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
udns(3)			   Library Functions Manual		       udns(3)

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 func-
       tionality, which	may be used  both  traditional,	 synchronous  way  and
       asynchronously, 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 asynchronous 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 asynchronous query	or  to
       wait for	it to complete.

       Asynchronous  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_io-
       event() and dns_timeouts() routines when	appropriate.  The library per-
       forms  all necessary processing and executes application	supplied call-
       back routine when a query completes (either successefully or not), giv-
       ing 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 re-
       turn 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  li-
       brary  provides	parsing	 routines  for	several	commonly used resource
       record types, as	well as	type-safe higher-level interface 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	synchronous interface,
       which may be intermixed with  asynchronous  calls  (during  synchronous
       query processing, other asynchronous queries for	the same resolver con-
       text  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 asynchronous interface, an application	may either re-
       quest  to return	raw DNS	packet or type-specific	data structure by pro-
       viding 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 asynchronous	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  with
       preceding  length  byte,	terminated by zero-length label	which is inte-
       gral 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 de-
       fines 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 for-
	      mat.

       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 li-
	      brary  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 fragmenta-
	      tion isn't a problem in most cases.  Note	also that the size  of
	      actual  packets  will  be	as many	bytes as actual	reply size re-
	      quires, 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  ini-
       tialize,	 copy  and free	resolver contexts.  Most other high-level rou-
       tines 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,	$NSCACHEIP, $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 - oper-
	      ation always succeeds.  dns_init() does  everything  dns_reset()
	      does, plus initializes various parameters	of the context accord-
	      ing  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  parame-
	      ters  for	 a  given resolver context copy, or default context if
	      copy is NULL, and	returns	pointer	to the	newly  allocated  con-
	      text.    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 associated socket and free resolver
	      context resources	and cancelling (abandoming) all	active queries
	      associated with it.  It's	an error to free dns_defctx, only  dy-
	      namically	 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	corre-
	      sponding list (search or nameserver)  is	reset  instead.	  Upon
	      successeful  completion, each routine returns new	number of ele-
	      ments in the list	in question.  On error,	negative value is  re-
	      turned 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.  Return number of unrecognized/invalid op-
	      tions found (all recognized and valid options gets processed).

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

	      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 associated 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 synchronous
	      interface, this is the  query  completion	 status	 of  the  last
	      query.   With  asynchronous  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 con-
	      stants 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_tmcbck(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	appli-
		     cation  changes  user   timer   request   routine	 using
		     dns_set_tmcbck();

	      ctx != NULL, timeout < 0
		     don't  fire  timer	 anymore, when there are no active re-
		     quests;

	      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_tmcbck().

	      When  a timer expires, an	application should call	dns_timeouts()
	      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 synchronous way,
       when  udns  performs all	the necessary processing and return control to
       the application only when the query completes,  and  asynchronous  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.  Asynchronous 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	asynchronous  query,  an application calls one of the dns_sub-
       mit_XXX() rounines, and provides	necessary information for a  callback,
       together	 with all the query parameters.	 When the query	completes, li-
       brary will call application-supplied callback routine,  giving  it  the
       resolver	context	(which holds query completion status), dynamically al-
       located	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	 allo-
       cate 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  er-
       ror.  Note that by the time when	the parse routine is called by the li-
       brary,  packet is already verified to be	a reply	to the original	query,
       by matching query DN, query class and query type.

       Type-specific query interface supplies necessary	parsing	routines auto-
       matically.

       In case of error, query	completion  status  as	returned  by  dns_sta-
       tus(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	 asynchronous  queries	and  another  for synchronous queries.
       There are two general low-level	routines  in  each  series  to	submit
       (asynchronous  interface)  and resolve (synchronous interface) queries,
       as well as several type-specific	routines with more easy-to-use	inter-
       faces.	To  submit  an asynchronous 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	corre-
       sponding	structure, not a void pointer).	 Every	dns_submit_XXX()  rou-
       tine   return   pointer	 to   internal	 query	 structure   of	  type
       struct dns_query, used as an identifier for the given query.

       To resolve a query synchronously, use  one  of  dns_resolve_XXX()  rou-
       tines,  which  accepts  the same	query parameters (but not the callback
       pointers) as corresponding dns_submit_XXX(), and	return the  query  re-
       sult,  which  is	 the same as passed to the callback routine in case of
       asynchronous interface.

       In either case, the result memory (if  the  query  completed  successe-
       fully)  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_can-
	      cel() 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 occurred.

       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;
	      synchronous interface.  The routines perform all the steps  nec-
	      essary  to  resolve  the	given query and	return the result.  If
	      there's no positive result for any reason, all the routines  re-
	      turn  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  li-
	      brary 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_sub-
	      mit_XXX()	routines, for completion, and return the result.   The
	      callback	routine	will not be called for this query.  After com-
	      pletion, the query identifier  q	is  not	 valid.	 Both  dns_re-
	      solve_dn()  and  dns_resolve_p() are just	wrappers around	corre-
	      sponding 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 pro-
       vides a set of routines to perform specific queries in a	type-safe man-
       ner, 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	struc-
       ture  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	inter-
       face).  Routines	dns_submit_a4()	and dns_resolve_a4() are used to  per-
       form A IN queries in a type-safe	manner.	 The name parameter is the do-
       main  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_re-
       solve_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.	 Call-
       back  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  in-
       ternally	 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 di-
       rectly too with generic query interface).  Routines dns_submit_mx() and
       dns_resolve_mx()	are used to perform IN MX queries in a type-safe  man-
       ner.   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 ar-
       ray 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_re-
       solve_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	struc-
       ture does not include the terminator), may contain embedded null	 char-
       acters  --  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  bit-
       mask,  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 *service;		 /* service parameter */
	 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 do-
       main 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, espe-
       cially 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 rou-
       tines 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	 nega-
	      tive value if name is invalid.  If isabs is non-NULL and conver-
	      sion  was	 successeful,  *isabs will be set to either 1 or 0 de-
	      pending 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 sim-
	      plified 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 re-
	      sult 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 sta-
	      tic 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 com-
       plete list.  In particular, constants  DNS_R_NOERROR  (0),  DNS_R_SERV-
       FAIL, 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 im-
	      mediately	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 iden-
	      tifier (qid), recursion desired (rd) flag,  truncation  occurred
	      (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 position */
	 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 sec-
	      tion  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_init-
	      parse() 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,  ini-
	      tializes	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  pro-
	      vided  in	 the  p	structure, filling in the rr structure and ad-
	      vancing 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 en-
	      counters	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.  reposi-
	      tion  the	 parse	structure p to the start of answer section and
	      initialize p->dnsp_rrl to	the number of entries in  answer  sec-
	      tion.

       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 com-
	      mon 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  rou-
       tines, 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  net-
	      work,  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+udns@tls.msk.ru.

VERSION
       This manual page	corresponds to udns version 0.6, released Jul-2024.

Library	Functions		   Jan 2014			       udns(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=udns&sektion=3&manpath=FreeBSD+Ports+14.3.quarterly>

home | help