/* ==========================================================================
 * lookup.h - Simple DNS Query Interface
 * --------------------------------------------------------------------------
 * Copyright (c) 2004, 2005, 2006  Barracuda Networks, Inc.
 * Copyright (c) 2006  William Ahern <william@25thandClement.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the
 * following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 * --------------------------------------------------------------------------
 * History
 *
 * 2006-04-23
 * 	Completely refactored interface in preparation for adding
 * 	cancellations.
 *
 * 2006-02-14 (william@25thandClement.com)
 * 	Published by Barracuda Networks, originally authored by
 * 	employee William Ahern (wahern@barracudanetworks.com).
 * --------------------------------------------------------------------------
 * Description
 *
 * Simple DNS query state machine which wraps the c-ares asynchronous client
 * DNS library. Supports compound queries for one or more of the following
 * record types: PTR, A, AAAA, CNAME, NS, MX, TXT, SOA and SRV.
 *
 * ==========================================================================
 */
#ifndef EVNET_LOOKUP_H
#define EVNET_LOOKUP_H

#include <sys/time.h>		/* struct timeval */

#if !_WIN32
#include <sys/socket.h> 	/* struct sockaddr struct sockaddr_storage */
#include <netinet/in.h>		/* struct sockaddr_in struct sockaddr_in6 */

#include <netdb.h>		/* NI_MAXHOST */
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

#ifndef NI_MAXHOST
#define NI_MAXHOST	1024
#endif


#define LOOKUP_SUCCESS(e)	(!LOOKUP_FAILURE((e)))
#define LOOKUP_FAILURE(e)	((e) & LOOKUP_EBOUNDARY)
#define LOOKUP_WARNING(e)	((e) & LOOKUP_WBOUNDARY)
#define LOOKUP_MESSAGE(e)	((e) & LOOKUP_MBOUNDARY)

#define LOOKUP_E2WARNING(e)						\
	(LOOKUP_WBOUNDARY						\
		| ((e)							\
			& (~(LOOKUP_EBOUNDARY | LOOKUP_MBOUNDARY))	\
		)							\
	)

#define LOOKUP_W2ERROR(e)						\
	(LOOKUP_EBOUNDARY						\
		| ((e)							\
			& (~(LOOKUP_WBOUNDARY | LOOKUP_MBOUNDARY))	\
		)							\
	)

enum lookup_type {
	LOOKUP_IN_PTR	= 1 << 0,
	LOOKUP_IN_A	= 1 << 1,
	LOOKUP_IN_AAAA	= 1 << 2,
	LOOKUP_IN_CNAME	= 1 << 3,
	LOOKUP_IN_NS	= 1 << 4,
	LOOKUP_IN_MX	= 1 << 5,
	LOOKUP_IN_TXT	= 1 << 6,
	LOOKUP_IN_SOA	= 1 << 7,
	LOOKUP_IN_SRV	= 1 << 8,
};


enum lookup_section {
	LOOKUP_SECTION_LOCAL		= 0,
	LOOKUP_SECTION_ANSWERS		= 1 << 0,
	LOOKUP_SECTION_AUTHORITY	= 1 << 1,
	LOOKUP_SECTION_ADDITIONAL	= 1 << 2,
};


enum lookup_flag {
	LOOKUP_PREFER_A		= 1 << 0,
	LOOKUP_PREFER_AAAA	= 1 << 1,
	LOOKUP_FALLBACK		= 1 << 2,
};


enum lookup_errno {
	LOOKUP_ESUCCESS		= 0,

	LOOKUP_EBOUNDARY	= 0x0020,	/* 32 - 63 */
	LOOKUP_ESYSTEM,
	LOOKUP_ETIMEDOUT,
	LOOKUP_EARES,
	LOOKUP_EBAD_FAMILY,
	LOOKUP_EBAD_RESPONSE,
	LOOKUP_EEMPTY_RESPONSE,
	LOOKUP_EUNKNOWN_RESPONSE,
	LOOKUP_EDUPLICATE_RESPONSE,
	LOOKUP_ENOTFOUND,
	LOOKUP_ENODATA,
	LOOKUP_EBAD_REQUEST,
	
	LOOKUP_WBOUNDARY	= 0x0040,	/* 64 - 127 */
	LOOKUP_WSYSTEM,
	LOOKUP_WTIMEDOUT,
	LOOKUP_WARES,
	LOOKUP_WBAD_RESPONSE,
	LOOKUP_WEMPTY_RESPONSE,
	LOOKUP_WUNKNOWN_RESPONSE,
	LOOKUP_WDUPLICATE_RESPONSE,
	LOOKUP_WNOTFOUND,
	LOOKUP_WNODATA,
	LOOKUP_WBAD_REQUEST,

	LOOKUP_MBOUNDARY	= 0x0100,	/* 128 - 255 */

	LOOKUP_NERR,	/* Do not move, do not put anything below. */
};

extern const char *lookup_errlist[];

extern const unsigned lookup_nerr;


enum lookup_method {
	LOOKUP_METHOD_BIND	= 1,
	LOOKUP_METHOD_FILE,
#if LOOKUP_CACHE_IMPLEMENTED
	LOOKUP_METHOD_CACHE,
#endif
};


struct lookup_options {
	char *resolv;			/* Path to resolv file (/etc/resolv.conf). */
	char *hosts;			/* Path to hosts file (/etc/hosts). */

#if LOOKUP_CACHE_IMPLEMENTED
	enum lookup_method order[3]; 	/* Lookup order, usually cache, file, bind. */
#else
	enum lookup_method order[2]; 	/* Lookup order, usually file, bind. */
#endif

	int loan_answers;		/* If 0, then lookup_rr structures
					 * will be automatically freed upon
					 * return from the callback. 
					 * Otherwise, lookup_rr_free() must
					 * be used to free the answers.
					 */

#if LOOKUP_CACHE_IMPLEMENTED
	unsigned cache_max;		/* Maximum number of queries to cache. */

	char *cache_map;		/* Path to shared cache memory map. */
#endif

	unsigned chain_max;		/* Maximum length of CNAME chains
					 * tolerated.
					 */

	unsigned query_max;		/* Maximum number of live queries to
					 * issue per lookup request (limit
					 * excessive work for compound
					 * queries).
					 */

	unsigned nchannels;		/* Maximum number of C-Ares channels
					 * to employ. Currently ALL are
					 * instantiated up-front, rather
					 * than incrementally.
					 */
};

extern const struct lookup_options lookup_defaults;


/*
 * Query resource record.
 */
struct lookup_rr {
	enum lookup_type type;
	enum lookup_section section;

	char qname[NI_MAXHOST];
	size_t qnamelen;

	unsigned ttl;

	union {
		struct {
			unsigned short preference;

			char host[NI_MAXHOST];
			size_t hostlen;
		} mx;

		struct {
			union {
				struct sockaddr sa;
				struct sockaddr_in sin;
#if USE_IPV6
				struct sockaddr_in6 sin6;
#endif
				struct sockaddr_storage ss;
			} sa;

			size_t salen;
		} ip;

		struct {
			char host[NI_MAXHOST];
			size_t hostlen;

			char mbox[NI_MAXHOST];
			size_t mboxlen;

			unsigned int serial;
			int refresh;
			int retry;
			int expire;
			unsigned int minimum;
		} soa;

		struct {
			char host[NI_MAXHOST];
			size_t hostlen;
		} ptr;

		struct {
			char host[NI_MAXHOST];
			size_t hostlen;
		} ns;

		struct {
			char data[NI_MAXHOST];
			size_t datalen;
		} txt;

		struct {
			char host[NI_MAXHOST];
			size_t hostlen;
		} cname;

		struct {
			unsigned short priority;
			unsigned short weight;
			unsigned short port;

			char host[NI_MAXHOST];
			size_t hostlen;
		} srv;
	} rr;

	struct lookup_rr *next;

#ifdef LIBEVNET_SOURCE
	int resolved;
	int followed;
	struct lookup_rr *alias;

	unsigned long srvsum;

	LIST_ENTRY(lookup_rr) le;
#endif
}; /* struct lookup_rr */


/*
 * Synchronous-mode query result.
 */
struct lookup_result {
	enum lookup_errno l_errno;

	int nanswers;
	struct lookup_rr *answers;

	int nadditional;
	struct lookup_rr *additional;

#ifdef LIBEVNET_SOURCE
	struct lookup *lookup;

	int done;
	int sys_errno;

	LIST_HEAD(,lookup_rr) l_answers;
	LIST_HEAD(,lookup_rr) l_additional;
#endif
}; /* struct lookup_result */


/*
 * Helper macro to create timeval structures on-the-fly (and on-the-stack),
 * using compound literals from C99.
 */
#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L) 
#define lookup_tv(s)	(&(struct timeval){ (s), 0 })
#endif


/*
 * Declare some structures that might haven't been declared just yet.
 */
struct lookup;
struct arena_prototype;
struct event_base;


/*
 * Open and close a lookup resource object.
 */
struct lookup *lookup_open(const struct lookup_options *, struct event_base *, const struct arena_prototype *);

void lookup_close(struct lookup *);


/*
 * Core lookup routine.
 */
typedef void (*lookup_return)(int, struct lookup_rr *, int, struct lookup_rr *, enum lookup_errno, void *);

void lookup_result_free(struct lookup *, struct lookup_result *);

void lookup_rr_free(struct lookup *, struct lookup_rr *);

struct lookup_result *lookup_rr(struct lookup *, const char *, size_t, int, int, lookup_return, void *, struct timeval *);

struct lookup_result *lookup_ptr(struct lookup *, struct sockaddr *, socklen_t, int, lookup_return, void *, struct timeval *);


/*
 * Error descriptions.
 */
enum lookup_errno lookup_errno(struct lookup *);

const char *lookup_strerror(struct lookup *);


/*
 * Simplified, namesake interface.
 */
enum lookup_errno lookup_init(const struct lookup_options *, struct event_base *, const struct arena_prototype *);

enum lookup_errno lookup_reset(const struct lookup_options *, struct event_base *, const struct arena_prototype *);

struct lookup_result *lookup(const char *, size_t, int, int, lookup_return, void *, struct timeval *);

struct lookup_result *rlookup(struct sockaddr *, socklen_t, int, lookup_return, void *, struct timeval *);


#endif /* EVNET_LOOKUP_H */


syntax highlighted by Code2HTML, v. 0.9.1