#pragma once

#include <endian.h>

#include <netdb.h>

#ifndef BYTE_ORDER
#if (BSD >= 199103)
# include <machine/endian.h>
#else
#ifdef __linux
# include <endian.h>
#else
#define LITTLE_ENDIAN   1234    /* least-significant byte first (vax, pc) */
#define BIG_ENDIAN      4321    /* most-significant byte first (IBM, net) */
#define PDP_ENDIAN      3412    /* LSB first in word, MSW first in long (pdp)*/

#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
     defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
     defined(__alpha__) || defined(__alpha) || \
     (defined(__Lynx__) && defined(__x86__))
#define BYTE_ORDER      LITTLE_ENDIAN
#endif

#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
	defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
	defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
	defined(apollo) || defined(__convex__) || defined(_CRAY) || \
	defined(__hppa) || defined(__hp9000) || \
	defined(__hp9000s300) || defined(__hp9000s700) || \
	defined(__hp3000s900) || defined(__hpux) || defined(MPE) || \
	defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) ||  \
 		(defined(__Lynx__) && \
 		(defined(__68k__) || defined(__sparc__) || defined(__powerpc__)))

#define BYTE_ORDER      BIG_ENDIAN
#endif
#endif /* __linux */
#endif /* BSD */
#endif /* BYTE_ORDER */

#if !defined(BYTE_ORDER) || \
	(BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \
	BYTE_ORDER != PDP_ENDIAN)
         /* you must determine what the correct bit order is for
          * your compiler - the next line is an intentional error
          * which will force your compiles to bomb until you fix
          * the above macros.
          */
  #error "Undefined or invalid BYTE_ORDER";
#endif
  
	typedef struct {
        unsigned        id :16;         /* query identification number */
#if BYTE_ORDER == BIG_ENDIAN
                        /* fields in third byte */
        unsigned        qr: 1;          /* response flag */
        unsigned        opcode: 4;      /* purpose of message */
        unsigned        aa: 1;          /* authoritive answer */
        unsigned        tc: 1;          /* truncated message */
        unsigned        rd: 1;          /* recursion desired */
                        /* fields in fourth byte */
        unsigned        ra: 1;          /* recursion available */
        unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
        unsigned        ad: 1;          /* authentic data from named */
        unsigned        cd: 1;          /* checking disabled by resolver */
        unsigned        rcode :4;       /* response code */
#endif
#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
                        /* fields in third byte */
        unsigned        rd :1;          /* recursion desired */
        unsigned        tc :1;          /* truncated message */
        unsigned        aa :1;          /* authoritive answer */
        unsigned        opcode :4;      /* purpose of message */
        unsigned        qr :1;          /* response flag */
                        /* fields in fourth byte */
        unsigned        rcode :4;       /* response code */
        unsigned        cd: 1;          /* checking disabled by resolver */
        unsigned        ad: 1;          /* authentic data from named */
        unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */
        unsigned        ra :1;          /* recursion available */
#endif
                        /* remaining bytes */
        unsigned        qdcount :16;    /* number of question entries */
        unsigned        ancount :16;    /* number of answer entries */
        unsigned        nscount :16;    /* number of authority entries */
        unsigned        arcount :16;    /* number of resource entries */
} HEADER;

//-----------------------------------------------------------------------------

#define MAXALIASES      35
 #define MAXADDRS        35
 
 struct res_static {
     char*           h_addr_ptrs[MAXADDRS + 1];
     char*           host_aliases[MAXALIASES];
     char            hostbuf[8*1024];
     u_int32_t       host_addr[16 / sizeof(u_int32_t)];  /* IPv4 or IPv6 */
     FILE*           hostf;
     int             stayopen;
     const char*     servent_ptr;
     struct servent  servent;
     struct hostent  host;
 };
 
 extern res_static __res_get_static(void);

//-----------------------------------------------------------------------------
#define NS_PACKETSZ     512     /* default UDP packet size */
#define NS_MAXDNAME     1025    /* maximum domain name */
 #define NS_MAXMSG       65535   /* maximum message size */
 #define NS_MAXCDNAME    255     /* maximum compressed domain name */
 #define NS_MAXLABEL     63      /* maximum length of domain label */
 #define NS_HFIXEDSZ     12      /* #/bytes of fixed data in header */
 #define NS_QFIXEDSZ     4       /* #/bytes of fixed data in query */
 #define NS_RRFIXEDSZ    10      /* #/bytes of fixed data in r record */
 #define NS_INT32SZ      4       /* #/bytes of data in a uint32_t */
 #define NS_INT16SZ      2       /* #/bytes of data in a uint16_t */
 #define NS_INT8SZ       1       /* #/bytes of data in a uint8_t */
  #define NS_INADDRSZ     4       /* IPv4 T_A */
 #define NS_IN6ADDRSZ    16      /* IPv6 T_AAAA */
 #define NS_CMPRSFLGS    0xc0    /* Flag bits indicating name compression. */
 #define NS_DEFAULTPORT  53      /* For both TCP and UDP. */

struct ns_tsig_key {
         char name[NS_MAXDNAME], alg[NS_MAXDNAME];
         unsigned char *data;
         int len;
};

typedef enum __ns_class {
         ns_c_invalid = 0,       /* Cookie. */
         ns_c_in = 1,            /* Internet. */
         ns_c_2 = 2,             /* unallocated/unsupported. */
         ns_c_chaos = 3,         /* MIT Chaos-net. */
         ns_c_hs = 4,            /* MIT Hesiod. */
         /* Query class values which do not appear in resource records */
         ns_c_none = 254,        /* for prereq. sections in update requests */
         ns_c_any = 255,         /* Wildcard match. */
         ns_c_max = 65536
 } ns_class;

#define RES_SET_H_ERRNO(r,x) (h_errno = (r)->res_h_errno = (x))
struct __res_state; /* forward */

#ifndef _PATH_RESCONF
#ifdef ANDROID_CHANGES
#define _PATH_RESCONF        "/etc/ppp/resolv.conf"
#else
#define _PATH_RESCONF        "/etc/resolv.conf"
#endif
#endif
 
typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error }
         res_sendhookact; 
typedef res_sendhookact (*res_send_qhook)(struct sockaddr * const *,
                                               const u_char **, int *,
                                               u_char *, int, int *);
 
typedef res_sendhookact (*res_send_rhook)(const struct sockaddr *,
                                               const u_char *, int, u_char *,
                                               int, int *);
 
struct res_sym {
         int             number;    /* Identifying number, like T_MX */
         const char *    name;      /* Its symbolic name, like "MX" */
         const char *    humanname; /* Its fun name, like "mail exchanger" */
};

//-------------------------------------------------------------------------------

/* Global defines and variables for resolver stub. */
#define MAXNS                   3       /* max # name servers we'll track */
#define MAXDFLSRCH              3       /* # default domain levels to try */
#define MAXDNSRCH               6       /* max # domains in search path */
#define LOCALDOMAINPARTS        2       /* min levels in name that is "local" */
 
#define RES_TIMEOUT             5       /* min. seconds between retries */
#define MAXRESOLVSORT           10      /* number of net to sort on */
#define RES_MAXNDOTS            15      /* should reflect bit field size */
#define RES_MAXRETRANS          30      /* only for resolv.conf/RES_OPTIONS */
#define RES_MAXRETRY            5       /* only for resolv.conf/RES_OPTIONS */
#define RES_DFLRETRY            2       /* Default #/tries. */
#define RES_MAXTIME             65535   /* Infinity, in milliseconds. */
 
struct __res_state_ext;

struct __res_state {
         int     retrans;                /* retransmission time interval */
         int     retry;                  /* number of times to retransmit */
#ifdef sun
         u_int   options;                /* option flags - see below. */
#else
         u_long  options;                /* option flags - see below. */
#endif
         int     nscount;                /* number of name servers */
         struct sockaddr_in
                 nsaddr_list[MAXNS];     /* address of name server */
 #define nsaddr  nsaddr_list[0]          /* for backward compatibility */
         u_short id;                     /* current message id */
         char    *dnsrch[MAXDNSRCH+1];   /* components of domain to search */
         char    defdname[256];          /* default domain (deprecated) */
 #ifdef sun
         u_int   pfcode;                 /* RES_PRF_ flags - see below. */
 #else
         u_long  pfcode;                 /* RES_PRF_ flags - see below. */
 #endif
         unsigned ndots:4;               /* threshold for initial abs. query */
         unsigned nsort:4;               /* number of elements in sort_list[] */
         char    unused[3];
         struct {
                 struct in_addr  addr;
                 uint32_t        mask;
         } sort_list[MAXRESOLVSORT];
 #ifdef __OLD_RES_STATE
         char lookups[4];
 #else
         res_send_qhook qhook;           /* query hook */
         res_send_rhook rhook;           /* response hook */
         int     res_h_errno;            /* last one set for this context */
         int     _vcsock;                /* PRIVATE: for res_send VC i/o */
         u_int   _flags;                 /* PRIVATE: see below */
         u_int   _pad;                   /* make _u 64 bit aligned */
         union {
                 /* On an 32-bit arch this means 512b total. */
                 char    pad[72 - 4*sizeof (int) - 2*sizeof (void *)];
                 struct {
                         uint16_t                nscount;
                         uint16_t                nstimes[MAXNS]; /* ms. */
                         int                     nssocks[MAXNS];
                         struct __res_state_ext *ext;    /* extention for IPv6 */
                 } _ext;
         } _u;
 #endif
         struct res_static   rstatic[1];
 };
 
typedef struct __res_state *res_state;
 
 union res_sockaddr_union {
         struct sockaddr_in      sin;
 #ifdef IN6ADDR_ANY_INIT
         struct sockaddr_in6     sin6;
 #endif
 #ifdef ISC_ALIGN64
         int64_t                 __align64;      /* 64bit alignment */
 #else
         int32_t                 __align32;      /* 32bit alignment */
 #endif
         char                    __space[128];   /* max size */
 };
 
 /*
  * Resolver flags (used to be discrete per-module statics ints).
  */
 #define RES_F_VC        0x00000001      /* socket is TCP */
 #define RES_F_CONN      0x00000002      /* socket is connected */
 #define RES_F_EDNS0ERR  0x00000004      /* EDNS0 caused errors */
 #define RES_F__UNUSED   0x00000008      /* (unused) */
 #define RES_F_LASTMASK  0x000000F0      /* ordinal server of last res_nsend */
 #define RES_F_LASTSHIFT 4               /* bit position of LASTMASK "flag" */
 #define RES_GETLAST(res) (((res)._flags & RES_F_LASTMASK) >> RES_F_LASTSHIFT)
 
 /* res_findzonecut2() options */
 #define RES_EXHAUSTIVE  0x00000001      /* always do all queries */
 #define RES_IPV4ONLY    0x00000002      /* IPv4 only */
 #define RES_IPV6ONLY    0x00000004      /* IPv6 only */
 
 /*
  * Resolver options (keep these in synch with res_debug.c, please)
  */
 #define RES_INIT        0x00000001      /* address initialized */
 #define RES_DEBUG       0x00000002      /* print debug messages */
 #define RES_AAONLY      0x00000004      /* authoritative answers only (!IMPL)*/
 #define RES_USEVC       0x00000008      /* use virtual circuit */
 #define RES_PRIMARY     0x00000010      /* query primary server only (!IMPL) */
 #define RES_IGNTC       0x00000020      /* ignore trucation errors */
 #define RES_RECURSE     0x00000040      /* recursion desired */
 #define RES_DEFNAMES    0x00000080      /* use default domain name */
 #define RES_STAYOPEN    0x00000100      /* Keep TCP socket open */
 #define RES_DNSRCH      0x00000200      /* search up local domain tree */
 #define RES_INSECURE1   0x00000400      /* type 1 security disabled */
 #define RES_INSECURE2   0x00000800      /* type 2 security disabled */
 #define RES_NOALIASES   0x00001000      /* shuts off HOSTALIASES feature */
 #define RES_USE_INET6   0x00002000      /* use/map IPv6 in gethostbyname() */
 #define RES_ROTATE      0x00004000      /* rotate ns list after each query */
 #define RES_NOCHECKNAME 0x00008000      /* do not check names for sanity. */
 #define RES_KEEPTSIG    0x00010000      /* do not strip TSIG records */
 #define RES_BLAST       0x00020000      /* blast all recursive servers */
 #define RES_NOTLDQUERY  0x00100000      /* don't unqualified name as a tld */
 #define RES_USE_DNSSEC  0x00200000      /* use DNSSEC using OK bit in OPT */
 /* #define RES_DEBUG2   0x00400000 */   /* nslookup internal */
 /* KAME extensions: use higher bit to avoid conflict with ISC use */
 #define RES_USE_DNAME   0x10000000      /* use DNAME */
 #define RES_USE_EDNS0   0x40000000      /* use EDNS0 if configured */
 #define RES_NO_NIBBLE2  0x80000000      /* disable alternate nibble lookup */
 
 #define RES_DEFAULT     (RES_RECURSE | RES_DEFNAMES | \
                          RES_DNSRCH | RES_NO_NIBBLE2)
 
 /*
  * Resolver "pfcode" values.  Used by dig.
  */
 #define RES_PRF_STATS   0x00000001
 #define RES_PRF_UPDATE  0x00000002
 #define RES_PRF_CLASS   0x00000004
 #define RES_PRF_CMD     0x00000008
 #define RES_PRF_QUES    0x00000010
 #define RES_PRF_ANS     0x00000020
 #define RES_PRF_AUTH    0x00000040
 #define RES_PRF_ADD     0x00000080
 #define RES_PRF_HEAD1   0x00000100
 #define RES_PRF_HEAD2   0x00000200
 #define RES_PRF_TTLID   0x00000400
 #define RES_PRF_HEADX   0x00000800
 #define RES_PRF_QUERY   0x00001000
 #define RES_PRF_REPLY   0x00002000
 #define RES_PRF_INIT    0x00004000
 #define RES_PRF_TRUNC   0x00008000
 /*                      0x00010000      */
 
 /* Things involving an internal (static) resolver context. */
 __BEGIN_DECLS
 extern struct __res_state *__res_get_state(void);
 extern void __res_put_state(struct __res_state *);
 
 #ifndef ANDROID_CHANGES
 /*
  * Source and Binary compatibility; _res will not work properly
  * with multi-threaded programs.
  */
 extern struct __res_state *__res_state(void);
 #define _res (*__res_state())
 #endif
 
 __END_DECLS
 
 #ifndef __BIND_NOSTATIC
 #define fp_nquery               __fp_nquery
 #define fp_query                __fp_query
 #define hostalias               __hostalias
 #define p_query                 __p_query
 #define res_close               __res_close
 #define res_opt                 __res_opt
 #define res_isourserver         __res_isourserver
 #define res_querydomain         __res_querydomain
 #define res_send                __res_send
 #define res_sendsigned          __res_sendsigned
 
 #ifdef BIND_RES_POSIX3
 #define dn_expand       __dn_expand
 #define res_init        __res_init
 #define res_query       __res_query
 #define res_search      __res_search
 #define res_mkquery     __res_mkquery
 #endif
 
 __BEGIN_DECLS
 void            fp_nquery(const u_char *, int, FILE *);
 void            fp_query(const u_char *, FILE *);
 const char *    hostalias(const char *);
 void            p_query(const u_char *);
 void            res_close(void);
 int             res_init(void);
 int             res_opt(int, u_char *, int, int);
 int             res_isourserver(const struct sockaddr_in *);
 int             res_mkquery(int, const char *, int, int, const u_char *, int, const u_char *, u_char *, int);
 int             res_query(const char *, int, int, u_char *, int);
 int             res_querydomain(const char *, const char *, int, int, u_char *, int);
 int             res_search(const char *, int, int, u_char *, int);
 int             res_send(const u_char *, int, u_char *, int);
 int             res_sendsigned(const u_char *, int, ns_tsig_key *, u_char *, int);
 __END_DECLS
 #endif
 
 #if !defined(SHARED_LIBBIND) || defined(LIB)
 /*
  * If libbind is a shared object (well, DLL anyway)
  * these externs break the linker when resolv.h is
  * included by a lib client (like named)
  * Make them go away if a client is including this
  *
  */
 extern const struct res_sym __p_key_syms[];
 extern const struct res_sym __p_cert_syms[];
 extern const struct res_sym __p_class_syms[];
 extern const struct res_sym __p_type_syms[];
 extern const struct res_sym __p_rcode_syms[];
 #endif /* SHARED_LIBBIND */
 
 #ifndef ADNROID_CHANGES
 #define b64_ntop                __b64_ntop
 #define b64_pton                __b64_pton
 #endif
 
 #define dn_comp                 __dn_comp
 #define dn_count_labels         __dn_count_labels
 #define dn_skipname             __dn_skipname
 #define fp_resstat              __fp_resstat
 #define loc_aton                __loc_aton
 #define loc_ntoa                __loc_ntoa
 #define p_cdname                __p_cdname
 #define p_cdnname               __p_cdnname
 #define p_class                 __p_class
 #define p_fqname                __p_fqname
 #define p_fqnname               __p_fqnname
 #define p_option                __p_option
 #define p_secstodate            __p_secstodate
 #define p_section               __p_section
 #define p_time                  __p_time
 #define p_type                  __p_type
 #define p_rcode                 __p_rcode
 #define p_sockun                __p_sockun
 #define putlong                 __putlong
 #define putshort                __putshort
 #define res_dnok                __res_dnok
 #define res_findzonecut         __res_findzonecut
 #define res_findzonecut2        __res_findzonecut2
 #define res_hnok                __res_hnok
 #define res_hostalias           __res_hostalias
 #define res_mailok              __res_mailok
 #define res_nameinquery         __res_nameinquery
 #define res_nclose              __res_nclose
 #define res_ninit               __res_ninit
 #define res_nmkquery            __res_nmkquery
 #define res_pquery              __res_pquery
 #define res_nquery              __res_nquery
 #define res_nquerydomain        __res_nquerydomain
 #define res_nsearch             __res_nsearch
 #define res_nsend               __res_nsend
 #define res_nsendsigned         __res_nsendsigned
 #define res_nisourserver        __res_nisourserver
 #define res_ownok               __res_ownok
 #define res_queriesmatch        __res_queriesmatch
 #define res_randomid            __res_randomid
 #define sym_ntop                __sym_ntop
 #define sym_ntos                __sym_ntos
 #define sym_ston                __sym_ston
 #define res_nopt                __res_nopt
 #define res_ndestroy            __res_ndestroy
 #define res_nametoclass         __res_nametoclass
 #define res_nametotype          __res_nametotype
 #define res_setservers          __res_setservers
 #define res_getservers          __res_getservers
 #define res_buildprotolist      __res_buildprotolist
 #define res_destroyprotolist    __res_destroyprotolist
 #define res_destroyservicelist  __res_destroyservicelist
 #define res_get_nibblesuffix    __res_get_nibblesuffix
 #define res_get_nibblesuffix2   __res_get_nibblesuffix2
 #define res_ourserver_p         __res_ourserver_p
 #define res_protocolname        __res_protocolname
 #define res_protocolnumber      __res_protocolnumber
 #define res_send_setqhook       __res_send_setqhook
 #define res_send_setrhook       __res_send_setrhook
 #define res_servicename         __res_servicename
 #define res_servicenumber       __res_servicenumber
 __BEGIN_DECLS
 int             res_hnok(const char *);
 int             res_ownok(const char *);
 int             res_mailok(const char *);
 int             res_dnok(const char *);
 int             sym_ston(const struct res_sym *, const char *, int *);
 const char *    sym_ntos(const struct res_sym *, int, int *);
 const char *    sym_ntop(const struct res_sym *, int, int *);
 #ifndef ANDROID_CHANGES
 int             b64_ntop(u_char const *, size_t, char *, size_t);
 int             b64_pton(char const *, u_char *, size_t);
 #endif
 int             loc_aton(const char *, u_char *);
 const char *    loc_ntoa(const u_char *, char *);
 int             dn_skipname(const u_char *, const u_char *);
 void            putlong(uint32_t, u_char *);
 void            putshort(uint16_t, u_char *);
 #ifndef __ultrix__
 uint16_t        _getshort(const u_char *);
 uint32_t        _getlong(const u_char *);
 #endif
 const char *    p_class(int);
 const char *    p_time(uint32_t);
 const char *    p_type(int);
 const char *    p_rcode(int);
 const char *    p_sockun(union res_sockaddr_union, char *, size_t);
 const u_char *  p_cdnname(const u_char *, const u_char *, int, FILE *);
 const u_char *  p_cdname(const u_char *, const u_char *, FILE *);
 const u_char *  p_fqnname(const u_char *, const u_char *,
                                int, char *, int);
 const u_char *  p_fqname(const u_char *, const u_char *, FILE *);
 const char *    p_option(u_long);
 char *          p_secstodate(u_long);
 int             dn_count_labels(const char *);
 int             dn_comp(const char *, u_char *, int, u_char **, u_char **);
 int             dn_expand(const u_char *, const u_char *, const u_char *,
                                char *, int);
 u_int           res_randomid(void);
 int             res_nameinquery(const char *, int, int, const u_char *,
                                      const u_char *);
 int             res_queriesmatch(const u_char *, const u_char *,
                                       const u_char *, const u_char *);
 const char *    p_section(int, int);
 /* Things involving a resolver context. */
 int             res_ninit(res_state);
 int             res_nisourserver(const res_state, const struct sockaddr_in *);
 void            fp_resstat(const res_state, FILE *);
 void            res_pquery(const res_state, const u_char *, int, FILE *);
 const char *    res_hostalias(const res_state, const char *, char *, size_t);
 int             res_nquery(res_state, const char *, int, int, u_char *, int);
 int             res_nsearch(res_state, const char *, int, int, u_char *, int);
 int             res_nquerydomain(res_state, const char *, const char *,
                                       int, int, u_char *, int);
 int             res_nmkquery(res_state, int, const char *, int, int,
                                   const u_char *, int, const u_char *,
                                   u_char *, int);
 int             res_nsend(res_state, const u_char *, int, u_char *, int);
 int             res_nsendsigned(res_state, const u_char *, int,
                                      ns_tsig_key *, u_char *, int);
 int             res_findzonecut(res_state, const char *, ns_class, int,
                                      char *, size_t, struct in_addr *, int);
 int             res_findzonecut2(res_state, const char *, ns_class, int,
                                       char *, size_t,
                                       union res_sockaddr_union *, int);
 void            res_nclose(res_state);
 int             res_nopt(res_state, int, u_char *, int, int);
 void            res_send_setqhook(res_send_qhook);
 void            res_send_setrhook(res_send_rhook);
 int             __res_vinit(res_state, int);
 void            res_destroyservicelist(void);
 const char *    res_servicename(uint16_t, const char *);
 const char *    res_protocolname(int);
 void            res_destroyprotolist(void);
 void            res_buildprotolist(void);
 const char *    res_get_nibblesuffix(res_state);
 const char *    res_get_nibblesuffix2(res_state);
 void            res_ndestroy(res_state);
 uint16_t        res_nametoclass(const char *, int *);
 uint16_t        res_nametotype(const char *, int *);
 void            res_setservers(res_state,
                                     const union res_sockaddr_union *, int);
 int             res_getservers(res_state,
                                     union res_sockaddr_union *, int);
 
 int res_get_dns_changed();
 u_int  res_randomid(void);
 
 __END_DECLS
