/* udns.h
   header file for the UDNS library.

   Copyright (C) 2005  Michael Tokarev <mjt@corpit.ru>
   This file is part of UDNS library, an async DNS stub resolver.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library, in file named COPYING.LGPL; if not,
   write to the Free Software Foundation, Inc., 59 Temple Place,
   Suite 330, Boston, MA  02111-1307  USA

 */

#ifndef UDNS_VERSION	/* include guard */

#define UDNS_VERSION "0.4"

#ifdef WINDOWS
# ifdef UDNS_DYNAMIC_LIBRARY
#  ifdef DNS_LIBRARY_BUILD
#   define UDNS_API __declspec(dllexport)
#   define UDNS_DATA_API __declspec(dllexport)
#  else
#   define UDNS_API __declspec(dllimport)
#   define UDNS_DATA_API __declspec(dllimport)
#  endif
# endif
#endif

#ifndef UDNS_API
# define UDNS_API
#endif
#ifndef UDNS_DATA_API
# define UDNS_DATA_API
#endif

#include <sys/types.h>		/* for time_t */

#ifdef __cplusplus
extern "C" {
#endif

/* forward declarations if sockets stuff isn't #include'd */
struct in_addr;
struct in6_addr;
struct sockaddr;

/**************************************************************************/
/**************** Common definitions **************************************/

UDNS_API const char *
dns_version(void);

struct dns_ctx;
struct dns_query;

/* shorthand for [const] unsigned char */
typedef unsigned char dnsc_t;
typedef const unsigned char dnscc_t;

#define DNS_MAXDN	255	/* max DN length */
#define DNS_DNPAD	1	/* padding for DN buffers */
#define DNS_MAXLABEL	63	/* max DN label length */
#define DNS_MAXNAME	1024	/* max asciiz domain name length */
#define DNS_HSIZE	12	/* DNS packet header size */
#define DNS_PORT	53	/* default domain port */
#define DNS_MAXSERV	6	/* max servers to consult */
#define DNS_MAXPACKET	512	/* max traditional-DNS UDP packet size */
#define DNS_EDNS0PACKET	4096	/* EDNS0 packet size to use */

enum dns_class {	/* DNS RR Classes */
  DNS_C_INVALID	= 0,	/* invalid class */
  DNS_C_IN	= 1,	/* Internet */
  DNS_C_CH	= 3,	/* CHAOS */
  DNS_C_HS	= 4,	/* HESIOD */
  DNS_C_ANY	= 255	/* wildcard */
};

enum dns_type {		/* DNS RR Types */
  DNS_T_INVALID		= 0,	/* Cookie. */
  DNS_T_A		= 1,	/* Host address. */
  DNS_T_NS		= 2,	/* Authoritative server. */
  DNS_T_MD		= 3,	/* Mail destination. */
  DNS_T_MF		= 4,	/* Mail forwarder. */
  DNS_T_CNAME		= 5,	/* Canonical name. */
  DNS_T_SOA		= 6,	/* Start of authority zone. */
  DNS_T_MB		= 7,	/* Mailbox domain name. */
  DNS_T_MG		= 8,	/* Mail group member. */
  DNS_T_MR		= 9,	/* Mail rename name. */
  DNS_T_NULL		= 10,	/* Null resource record. */
  DNS_T_WKS		= 11,	/* Well known service. */
  DNS_T_PTR		= 12,	/* Domain name pointer. */
  DNS_T_HINFO		= 13,	/* Host information. */
  DNS_T_MINFO		= 14,	/* Mailbox information. */
  DNS_T_MX		= 15,	/* Mail routing information. */
  DNS_T_TXT		= 16,	/* Text strings. */
  DNS_T_RP		= 17,	/* Responsible person. */
  DNS_T_AFSDB		= 18,	/* AFS cell database. */
  DNS_T_X25		= 19,	/* X_25 calling address. */
  DNS_T_ISDN		= 20,	/* ISDN calling address. */
  DNS_T_RT		= 21,	/* Router. */
  DNS_T_NSAP		= 22,	/* NSAP address. */
  DNS_T_NSAP_PTR	= 23,	/* Reverse NSAP lookup (deprecated). */
  DNS_T_SIG		= 24,	/* Security signature. */
  DNS_T_KEY		= 25,	/* Security key. */
  DNS_T_PX		= 26,	/* X.400 mail mapping. */
  DNS_T_GPOS		= 27,	/* Geographical position (withdrawn). */
  DNS_T_AAAA		= 28,	/* Ip6 Address. */
  DNS_T_LOC		= 29,	/* Location Information. */
  DNS_T_NXT		= 30,	/* Next domain (security). */
  DNS_T_EID		= 31,	/* Endpoint identifier. */
  DNS_T_NIMLOC		= 32,	/* Nimrod Locator. */
  DNS_T_SRV		= 33,	/* Server Selection. */
  DNS_T_ATMA		= 34,	/* ATM Address */
  DNS_T_NAPTR		= 35,	/* Naming Authority PoinTeR */
  DNS_T_KX		= 36,	/* Key Exchange */
  DNS_T_CERT		= 37,	/* Certification record */
  DNS_T_A6		= 38,	/* IPv6 address (deprecates AAAA) */
  DNS_T_DNAME		= 39,	/* Non-terminal DNAME (for IPv6) */
  DNS_T_SINK		= 40,	/* Kitchen sink (experimentatl) */
  DNS_T_OPT		= 41,	/* EDNS0 option (meta-RR) */
  DNS_T_DS		= 43,	/* DNSSEC */
  DNS_T_SSHFP		= 44,
  DNS_T_IPSECKEY	= 45,
  DNS_T_RRSIG		= 46,	/* DNSSEC */
  DNS_T_NSEC		= 47,	/* DNSSEC */
  DNS_T_DNSKEY		= 48,
  DNS_T_DHCID		= 49,
  DNS_T_NSEC3		= 50,
  DNS_T_NSEC3PARAMS	= 51,
  DNS_T_TALINK		= 58, /* draft-ietf-dnsop-trust-history */
  DNS_T_SPF		= 99,
  DNS_T_UINFO		= 100,
  DNS_T_UID		= 101,
  DNS_T_GID		= 102,
  DNS_T_UNSPEC		= 103,
  DNS_T_TSIG		= 250,	/* Transaction signature. */
  DNS_T_IXFR		= 251,	/* Incremental zone transfer. */
  DNS_T_AXFR		= 252,	/* Transfer zone of authority. */
  DNS_T_MAILB		= 253,	/* Transfer mailbox records. */
  DNS_T_MAILA		= 254,	/* Transfer mail agent records. */
  DNS_T_ANY		= 255,	/* Wildcard match. */
  DNS_T_ZXFR		= 256,	/* BIND-specific, nonstandard. */
  DNS_T_DLV		= 32769, /* RFC 4431, 5074, DNSSEC Lookaside Validation */
  DNS_T_MAX		= 65536
};

/**************************************************************************/
/**************** Domain Names (DNs) **************************************/

/* return length of the DN */
UDNS_API unsigned
dns_dnlen(dnscc_t *dn);

/* return #of labels in a DN */
UDNS_API unsigned
dns_dnlabels(dnscc_t *dn);

/* lower- and uppercase single DN char */
#define DNS_DNLC(c) ((c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 'a' : (c))
#define DNS_DNUC(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))

/* compare the DNs, return dnlen of equal or 0 if not */
UDNS_API unsigned
dns_dnequal(dnscc_t *dn1, dnscc_t *dn2);

/* copy one DN to another, size checking */
UDNS_API unsigned
dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz);

/* convert asciiz string of length namelen (0 to use strlen) to DN */
UDNS_API int
dns_ptodn(const char *name, unsigned namelen,
          dnsc_t *dn, unsigned dnsiz, int *isabs);

/* simpler form of dns_ptodn() */
#define dns_sptodn(name,dn,dnsiz) dns_ptodn((name),0,(dn),(dnsiz),0)

UDNS_DATA_API extern dnscc_t dns_inaddr_arpa_dn[14];
#define DNS_A4RSIZE	30
UDNS_API int
dns_a4todn(const struct in_addr *addr, dnscc_t *tdn,
           dnsc_t *dn, unsigned dnsiz);
UDNS_API int
dns_a4ptodn(const struct in_addr *addr, const char *tname,
            dnsc_t *dn, unsigned dnsiz);
UDNS_API dnsc_t *
dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne);

UDNS_DATA_API extern dnscc_t dns_ip6_arpa_dn[10];
#define DNS_A6RSIZE	74
UDNS_API int
dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn,
           dnsc_t *dn, unsigned dnsiz);
UDNS_API int
dns_a6ptodn(const struct in6_addr *addr, const char *tname,
            dnsc_t *dn, unsigned dnsiz);
UDNS_API dnsc_t *
dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne);

/* convert DN into asciiz string */
UDNS_API int
dns_dntop(dnscc_t *dn, char *name, unsigned namesiz);

/* convert DN into asciiz string, using static buffer (NOT thread-safe!) */
UDNS_API const char *
dns_dntosp(dnscc_t *dn);

/* return buffer size (incl. null byte) required for asciiz form of a DN */
UDNS_API unsigned
dns_dntop_size(dnscc_t *dn);

/* either wrappers or reimplementations for inet_ntop() and inet_pton() */
UDNS_API const char *dns_ntop(int af, const void *src, char *dst, int size);
UDNS_API int dns_pton(int af, const char *src, void *dst);

/**************************************************************************/
/**************** DNS raw packet layout ***********************************/

enum dns_rcode {	/* reply codes */
  DNS_R_NOERROR		= 0,	/* ok, no error */
  DNS_R_FORMERR		= 1,	/* format error */
  DNS_R_SERVFAIL	= 2,	/* server failed */
  DNS_R_NXDOMAIN	= 3,	/* domain does not exists */
  DNS_R_NOTIMPL		= 4,	/* not implemented */
  DNS_R_REFUSED		= 5,	/* query refused */
  /* these are for BIND_UPDATE */
  DNS_R_YXDOMAIN	= 6,	/* Name exists */
  DNS_R_YXRRSET		= 7,	/* RRset exists */
  DNS_R_NXRRSET		= 8,	/* RRset does not exist */
  DNS_R_NOTAUTH		= 9,	/* Not authoritative for zone */
  DNS_R_NOTZONE		= 10,	/* Zone of record different from zone section */
  /*ns_r_max = 11,*/
  /* The following are TSIG extended errors */
  DNS_R_BADSIG		= 16,
  DNS_R_BADKEY		= 17,
  DNS_R_BADTIME		= 18
};

static __inline unsigned dns_get16(dnscc_t *s) {
  return ((unsigned)s[0]<<8) | s[1];
}
static __inline unsigned dns_get32(dnscc_t *s) {
  return ((unsigned)s[0]<<24) | ((unsigned)s[1]<<16)
        | ((unsigned)s[2]<<8) | s[3];
}
static __inline dnsc_t *dns_put16(dnsc_t *d, unsigned n) {
  *d++ = (dnsc_t)((n >> 8) & 255); *d++ = (dnsc_t)(n & 255); return d;
}
static __inline dnsc_t *dns_put32(dnsc_t *d, unsigned n) {
  *d++ = (dnsc_t)((n >> 24) & 255); *d++ = (dnsc_t)((n >> 16) & 255);
  *d++ = (dnsc_t)((n >>  8) & 255); *d++ = (dnsc_t)(n & 255);
  return d;
}

/* DNS Header layout */
enum {
 /* bytes 0:1 - query ID */
  DNS_H_QID1	= 0,
  DNS_H_QID2	= 1,
  DNS_H_QID	= DNS_H_QID1,
#define dns_qid(pkt)	dns_get16((pkt)+DNS_H_QID)
 /* byte 2: flags1 */
  DNS_H_F1	= 2,
  DNS_HF1_QR	= 0x80,	/* query response flag */
#define dns_qr(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_QR)
  DNS_HF1_OPCODE = 0x78, /* opcode, 0 = query */
#define dns_opcode(pkt)	(((pkt)[DNS_H_F1]&DNS_HF1_OPCODE)>>3)
  DNS_HF1_AA	= 0x04,	/* auth answer */
#define dns_aa(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_AA)
  DNS_HF1_TC	= 0x02,	/* truncation flag */
#define dns_tc(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_TC)
  DNS_HF1_RD	= 0x01,	/* recursion desired (may be set in query) */
#define dns_rd(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_RD)
 /* byte 3: flags2 */
  DNS_H_F2	= 3,
  DNS_HF2_RA	= 0x80,	/* recursion available */
#define dns_ra(pkt)	((pkt)[DNS_H_F2]&DNS_HF2_RA)
  DNS_HF2_Z	= 0x40,	/* reserved */
  DNS_HF2_AD	= 0x20, /* DNSSEC: authentic data */
#define dns_ad(pkt)	((pkt)[DNS_H_F2]&DNS_HF2_AD)
  DNS_HF2_CD	= 0x10, /* DNSSEC: checking disabled */
#define dns_cd(pkt)	((pkt)[DNS_H_F2]&DNS_HF2_CD)
  DNS_HF2_RCODE	= 0x0f,	/* response code, DNS_R_XXX above */
#define dns_rcode(pkt)	((pkt)[DNS_H_F2]&DNS_HF2_RCODE)
 /* bytes 4:5: qdcount, numqueries */
  DNS_H_QDCNT1	= 4,
  DNS_H_QDCNT2	= 5,
  DNS_H_QDCNT	= DNS_H_QDCNT1,
#define dns_numqd(pkt)	dns_get16((pkt)+4)
 /* bytes 6:7: ancount, numanswers */
  DNS_H_ANCNT1	= 6,
  DNS_H_ANCNT2	= 7,
  DNS_H_ANCNT	= DNS_H_ANCNT1,
#define dns_numan(pkt)	dns_get16((pkt)+6)
 /* bytes 8:9: nscount, numauthority */
  DNS_H_NSCNT1	= 8,
  DNS_H_NSCNT2	= 9,
  DNS_H_NSCNT	= DNS_H_NSCNT1,
#define dns_numns(pkt)	dns_get16((pkt)+8)
 /* bytes 10:11: arcount, numadditional */
  DNS_H_ARCNT1	= 10,
  DNS_H_ARCNT2	= 11,
  DNS_H_ARCNT	= DNS_H_ARCNT1,
#define dns_numar(pkt)	dns_get16((pkt)+10)
#define dns_payload(pkt) ((pkt)+DNS_HSIZE)
  /* EDNS0 (OPT RR) flags (Ext. Flags) */
  DNS_EF1_DO	= 0x80, /* DNSSEC OK */
};

/* packet buffer: start at pkt, end before pkte, current pos *curp.
 * extract a DN and set *curp to the next byte after DN in packet.
 * return -1 on error, 0 if dnsiz is too small, or dnlen on ok.
 */
UDNS_API int
dns_getdn(dnscc_t *pkt, dnscc_t **curp, dnscc_t *end,
          dnsc_t *dn, unsigned dnsiz);

/* skip the DN at position cur in packet ending before pkte,
 * return pointer to the next byte after the DN or NULL on error */
UDNS_API dnscc_t *
dns_skipdn(dnscc_t *end, dnscc_t *cur);

struct dns_rr {		/* DNS Resource Record */
  dnsc_t dnsrr_dn[DNS_MAXDN];	/* the DN of the RR */
  enum dns_class dnsrr_cls;	/* Class */
  enum dns_type  dnsrr_typ;	/* Type */
  unsigned dnsrr_ttl;		/* Time-To-Live (TTL) */
  unsigned dnsrr_dsz;		/* data size */
  dnscc_t *dnsrr_dptr;		/* pointer to start of data */
  dnscc_t *dnsrr_dend;		/* past end of data */
};

struct dns_parse {	/* RR/packet parsing state */
  dnscc_t *dnsp_pkt;		/* start of the packet */
  dnscc_t *dnsp_end;		/* end of the packet */
  dnscc_t *dnsp_cur;		/* current packet position */
  dnscc_t *dnsp_ans;		/* start of answer section */
  int dnsp_rrl;			/* number of RRs left to go */
  int dnsp_nrr;			/* RR count so far */
  unsigned dnsp_ttl;		/* TTL value so far */
  dnscc_t *dnsp_qdn;		/* the RR DN we're looking for */
  enum dns_class dnsp_qcls;	/* RR class we're looking for or 0 */
  enum dns_type  dnsp_qtyp;	/* RR type we're looking for or 0 */
  dnsc_t dnsp_dnbuf[DNS_MAXDN];	/* domain buffer */
};

/* initialize the parse structure */
UDNS_API void
dns_initparse(struct dns_parse *p, dnscc_t *qdn,
              dnscc_t *pkt, dnscc_t *cur, dnscc_t *end);

/* search next RR, <0=error, 0=no more RRs, >0 = found. */
UDNS_API int
dns_nextrr(struct dns_parse *p, struct dns_rr *rr);

UDNS_API void
dns_rewind(struct dns_parse *p, dnscc_t *qdn);


/**************************************************************************/
/**************** Resolver Context ****************************************/

/* default resolver context */
UDNS_DATA_API extern struct dns_ctx dns_defctx;

/* reset resolver context to default state, close it if open, drop queries */
UDNS_API void
dns_reset(struct dns_ctx *ctx);

/* reset resolver context and read in system configuration */
UDNS_API int
dns_init(struct dns_ctx *ctx, int do_open);

/* return new resolver context with the same settings as copy */
UDNS_API struct dns_ctx *
dns_new(const struct dns_ctx *copy);

/* free resolver context returned by dns_new(); all queries are dropped */
UDNS_API void
dns_free(struct dns_ctx *ctx);

/* add nameserver for a resolver context (or reset nslist if serv==NULL) */
UDNS_API int
dns_add_serv(struct dns_ctx *ctx, const char *serv);

/* add nameserver using struct sockaddr structure (with ports) */
UDNS_API int
dns_add_serv_s(struct dns_ctx *ctx, const struct sockaddr *sa);

/* add search list element for a resolver context (or reset it if srch==NULL) */
UDNS_API int
dns_add_srch(struct dns_ctx *ctx, const char *srch);

/* set options for a resolver context */
UDNS_API int
dns_set_opts(struct dns_ctx *ctx, const char *opts);

enum dns_opt {		/* options */
  DNS_OPT_FLAGS,	/* flags, DNS_F_XXX */
  DNS_OPT_TIMEOUT,	/* timeout in secounds */
  DNS_OPT_NTRIES,	/* number of retries */
  DNS_OPT_NDOTS,	/* ndots */
  DNS_OPT_UDPSIZE,	/* EDNS0 UDP size */
  DNS_OPT_PORT,		/* port to use */
};

/* set or get (if val<0) an option */
UDNS_API int
dns_set_opt(struct dns_ctx *ctx, enum dns_opt opt, int val);

enum dns_flags {
  DNS_NOSRCH	= 0x00010000,	/* do not perform search */
  DNS_NORD	= 0x00020000,	/* request no recursion */
  DNS_AAONLY	= 0x00040000,	/* set AA flag in queries */
  DNS_SET_DO	= 0x00080000,	/* set EDNS0 "DO" bit (DNSSEC OK) */
  DNS_SET_CD	= 0x00100000,	/* set CD bit (DNSSEC: checking disabled) */
};

/* set the debug function pointer */
typedef void
(dns_dbgfn)(int code, const struct sockaddr *sa, unsigned salen,
            dnscc_t *pkt, int plen,
            const struct dns_query *q, void *data);
UDNS_API void
dns_set_dbgfn(struct dns_ctx *ctx, dns_dbgfn *dbgfn);

/* open and return UDP socket */
UDNS_API int
dns_open(struct dns_ctx *ctx);

/* return UDP socket or -1 if not open */
UDNS_API int
dns_sock(const struct dns_ctx *ctx);

/* close the UDP socket */
UDNS_API void
dns_close(struct dns_ctx *ctx);

/* return number of requests queued */
UDNS_API int
dns_active(const struct dns_ctx *ctx);

/* return status of the last operation */
UDNS_API int
dns_status(const struct dns_ctx *ctx);
UDNS_API void
dns_setstatus(struct dns_ctx *ctx, int status);

/* handle I/O event on UDP socket */
UDNS_API void
dns_ioevent(struct dns_ctx *ctx, time_t now);

/* process any timeouts, return time in secounds to the
 * next timeout (or -1 if none) but not greather than maxwait */
UDNS_API int
dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now);

/* define timer requesting routine to use */
typedef void dns_utm_fn(struct dns_ctx *ctx, int timeout, void *data);
UDNS_API void
dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data);

/**************************************************************************/
/**************** Making Queries ******************************************/

/* query callback routine */
typedef void dns_query_fn(struct dns_ctx *ctx, void *result, void *data);

/* query parse routine: raw DNS => application structure */
typedef int
dns_parse_fn(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
             void **res);

enum dns_status {
  DNS_E_NOERROR		= 0,	/* ok, not an error */
  DNS_E_TEMPFAIL	= -1,	/* timeout, SERVFAIL or similar */
  DNS_E_PROTOCOL	= -2,	/* got garbled reply */
  DNS_E_NXDOMAIN	= -3,	/* domain does not exists */
  DNS_E_NODATA		= -4,	/* domain exists but no data of reqd type */
  DNS_E_NOMEM		= -5,	/* out of memory while processing */
  DNS_E_BADQUERY	= -6	/* the query is malformed */
};

/* submit generic DN query */
UDNS_API struct dns_query *
dns_submit_dn(struct dns_ctx *ctx,
              dnscc_t *dn, int qcls, int qtyp, int flags,
              dns_parse_fn *parse, dns_query_fn *cbck, void *data);
/* submit generic name query */
UDNS_API struct dns_query *
dns_submit_p(struct dns_ctx *ctx,
             const char *name, int qcls, int qtyp, int flags,
             dns_parse_fn *parse, dns_query_fn *cbck, void *data);

/* cancel the given async query in progress */
UDNS_API int
dns_cancel(struct dns_ctx *ctx, struct dns_query *q);

/* resolve a generic query, return the answer */
UDNS_API void *
dns_resolve_dn(struct dns_ctx *ctx,
               dnscc_t *qdn, int qcls, int qtyp, int flags,
               dns_parse_fn *parse);
UDNS_API void *
dns_resolve_p(struct dns_ctx *ctx,
              const char *qname, int qcls, int qtyp, int flags,
              dns_parse_fn *parse);
UDNS_API void *
dns_resolve(struct dns_ctx *ctx, struct dns_query *q);


/* Specific RR handlers */

#define dns_rr_common(prefix)						\
  char *prefix##_cname;		/* canonical name */			\
  char *prefix##_qname;		/* original query name */		\
  unsigned prefix##_ttl;	/* TTL value */				\
  int prefix##_nrr		/* number of records */

struct dns_rr_null {		/* NULL RRset, aka RRset template */
  dns_rr_common(dnsn);
};

UDNS_API int
dns_stdrr_size(const struct dns_parse *p);
UDNS_API void *
dns_stdrr_finish(struct dns_rr_null *ret, char *cp, const struct dns_parse *p);

struct dns_rr_a4 {		/* the A RRset */
  dns_rr_common(dnsa4);
  struct in_addr *dnsa4_addr;	/* array of addresses, naddr elements */
};

UDNS_API dns_parse_fn dns_parse_a4;	/* A RR parsing routine */
typedef void				/* A query callback routine */
dns_query_a4_fn(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data);

/* submit A IN query */
UDNS_API struct dns_query *
dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags,
              dns_query_a4_fn *cbck, void *data);

/* resolve A IN query */
UDNS_API struct dns_rr_a4 *
dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags);


struct dns_rr_a6 {		/* the AAAA RRset */
  dns_rr_common(dnsa6);
  struct in6_addr *dnsa6_addr;	/* array of addresses, naddr elements */
};

UDNS_API dns_parse_fn dns_parse_a6;	/* A RR parsing routine */
typedef void				/* A query callback routine */
dns_query_a6_fn(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data);

/* submit AAAA IN query */
UDNS_API struct dns_query *
dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags,
              dns_query_a6_fn *cbck, void *data);

/* resolve AAAA IN query */
UDNS_API struct dns_rr_a6 *
dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags);


struct dns_rr_ptr {		/* the PTR RRset */
  dns_rr_common(dnsptr);
  char **dnsptr_ptr;		/* array of PTRs */
};

UDNS_API dns_parse_fn dns_parse_ptr;	/* PTR RR parsing routine */
typedef void				/* PTR query callback */
dns_query_ptr_fn(struct dns_ctx *ctx, struct dns_rr_ptr *result, void *data);
/* submit PTR IN in-addr.arpa query */
UDNS_API struct dns_query *
dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr,
                 dns_query_ptr_fn *cbck, void *data);
/* resolve PTR IN in-addr.arpa query */
UDNS_API struct dns_rr_ptr *
dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr);

/* the same as above, but for ip6.arpa */
UDNS_API struct dns_query *
dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr,
                 dns_query_ptr_fn *cbck, void *data);
UDNS_API struct dns_rr_ptr *
dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr);


struct dns_mx {		/* single MX RR */
  int priority;		/* MX priority */
  char *name;		/* MX name */
};
struct dns_rr_mx {		/* the MX RRset */
  dns_rr_common(dnsmx);
  struct dns_mx *dnsmx_mx;	/* array of MXes */
};
UDNS_API dns_parse_fn dns_parse_mx;	/* MX RR parsing routine */
typedef void				/* MX RR callback */
dns_query_mx_fn(struct dns_ctx *ctx, struct dns_rr_mx *result, void *data);
/* submit MX IN query */
UDNS_API struct dns_query *
dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags,
              dns_query_mx_fn *cbck, void *data);
/* resolve MX IN query */
UDNS_API struct dns_rr_mx *
dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags);


struct dns_txt {	/* single TXT record */
  int len;		/* length of the text */
  dnsc_t *txt;	/* pointer to text buffer. May contain nulls. */
};
struct dns_rr_txt {		/* the TXT RRset */
  dns_rr_common(dnstxt);
  struct dns_txt *dnstxt_txt;	/* array of TXT records */
};
UDNS_API dns_parse_fn dns_parse_txt;	/* TXT RR parsing routine */
typedef void				/* TXT RR callback */
dns_query_txt_fn(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data);
/* submit TXT query */
UDNS_API struct dns_query *
dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags,
               dns_query_txt_fn *cbck, void *data);
/* resolve TXT query */
UDNS_API struct dns_rr_txt *
dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags);


struct dns_srv {	/* single SRV RR */
  int priority;		/* SRV priority */
  int weight;		/* SRV weight */
  int port;		/* SRV port */
  char *name;		/* SRV name */
};
struct dns_rr_srv {		/* the SRV RRset */
  dns_rr_common(dnssrv);
  struct dns_srv *dnssrv_srv;	/* array of SRVes */
};
UDNS_API dns_parse_fn dns_parse_srv;	/* SRV RR parsing routine */
typedef void				/* SRV RR callback */
dns_query_srv_fn(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data);
/* submit SRV IN query */
UDNS_API struct dns_query *
dns_submit_srv(struct dns_ctx *ctx,
               const char *name, const char *srv, const char *proto,
               int flags, dns_query_srv_fn *cbck, void *data);
/* resolve SRV IN query */
UDNS_API struct dns_rr_srv *
dns_resolve_srv(struct dns_ctx *ctx,
                const char *name, const char *srv, const char *proto,
                int flags);

/* NAPTR (RFC3403) RR type */
struct dns_naptr {	/* single NAPTR RR */
  int order;		/* NAPTR order */
  int preference;	/* NAPTR preference */
  char *flags;		/* NAPTR flags */
  char *service;	/* NAPTR service */
  char *regexp;		/* NAPTR regexp */
  char *replacement;	/* NAPTR replacement */
};

struct dns_rr_naptr {		/* the NAPTR RRset */
  dns_rr_common(dnsnaptr);
  struct dns_naptr *dnsnaptr_naptr;	/* array of NAPTRes */
};
UDNS_API dns_parse_fn dns_parse_naptr;	/* NAPTR RR parsing routine */
typedef void				/* NAPTR RR callback */
dns_query_naptr_fn(struct dns_ctx *ctx,
                   struct dns_rr_naptr *result, void *data);
/* submit NAPTR IN query */
UDNS_API struct dns_query *
dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags,
                 dns_query_naptr_fn *cbck, void *data);
/* resolve NAPTR IN query */
UDNS_API struct dns_rr_naptr *
dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags);


UDNS_API struct dns_query *
dns_submit_a4dnsbl(struct dns_ctx *ctx,
                   const struct in_addr *addr, const char *dnsbl,
                   dns_query_a4_fn *cbck, void *data);
UDNS_API struct dns_query *
dns_submit_a4dnsbl_txt(struct dns_ctx *ctx,
                       const struct in_addr *addr, const char *dnsbl,
                       dns_query_txt_fn *cbck, void *data);
UDNS_API struct dns_rr_a4 *
dns_resolve_a4dnsbl(struct dns_ctx *ctx,
                    const struct in_addr *addr, const char *dnsbl);
UDNS_API struct dns_rr_txt *
dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx,
                        const struct in_addr *addr, const char *dnsbl);

UDNS_API struct dns_query *
dns_submit_a6dnsbl(struct dns_ctx *ctx,
                   const struct in6_addr *addr, const char *dnsbl,
                   dns_query_a4_fn *cbck, void *data);
UDNS_API struct dns_query *
dns_submit_a6dnsbl_txt(struct dns_ctx *ctx,
                       const struct in6_addr *addr, const char *dnsbl,
                       dns_query_txt_fn *cbck, void *data);
UDNS_API struct dns_rr_a4 *
dns_resolve_a6dnsbl(struct dns_ctx *ctx,
                    const struct in6_addr *addr, const char *dnsbl);
UDNS_API struct dns_rr_txt *
dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx,
                        const struct in6_addr *addr, const char *dnsbl);

UDNS_API struct dns_query *
dns_submit_rhsbl(struct dns_ctx *ctx,
                 const char *name, const char *rhsbl,
                 dns_query_a4_fn *cbck, void *data);
UDNS_API struct dns_query *
dns_submit_rhsbl_txt(struct dns_ctx *ctx,
                     const char *name, const char *rhsbl,
                     dns_query_txt_fn *cbck, void *data);
UDNS_API struct dns_rr_a4 *
dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl);
UDNS_API struct dns_rr_txt *
dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl);

/**************************************************************************/
/**************** Names, Names ********************************************/

struct dns_nameval {
  int val;
  const char *name;
};

UDNS_DATA_API extern const struct dns_nameval dns_classtab[];
UDNS_DATA_API extern const struct dns_nameval dns_typetab[];
UDNS_DATA_API extern const struct dns_nameval dns_rcodetab[];
UDNS_API int
dns_findname(const struct dns_nameval *nv, const char *name);
#define dns_findclassname(cls) dns_findname(dns_classtab, (cls))
#define dns_findtypename(type) dns_findname(dns_typetab, (type))
#define dns_findrcodename(rcode) dns_findname(dns_rcodetab, (rcode))

UDNS_API const char *dns_classname(enum dns_class cls);
UDNS_API const char *dns_typename(enum dns_type type);
UDNS_API const char *dns_rcodename(enum dns_rcode rcode);
const char *_dns_format_code(char *buf, const char *prefix, int code);

UDNS_API const char *dns_strerror(int errnum);

/* simple pseudo-random number generator, code by Bob Jenkins */

struct udns_jranctx {	/* the context */
  unsigned a, b, c, d;
};

/* initialize the RNG with a given seed */
UDNS_API void
udns_jraninit(struct udns_jranctx *x, unsigned seed);

/* return next random number.  32bits on most platforms so far. */
UDNS_API unsigned
udns_jranval(struct udns_jranctx *x);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif	/* include guard */
