1275970Scy/* Copyright 2006-2007 Niels Provos
2275970Scy * Copyright 2007-2012 Nick Mathewson and Niels Provos
3275970Scy *
4275970Scy * Redistribution and use in source and binary forms, with or without
5275970Scy * modification, are permitted provided that the following conditions
6275970Scy * are met:
7275970Scy * 1. Redistributions of source code must retain the above copyright
8275970Scy *    notice, this list of conditions and the following disclaimer.
9275970Scy * 2. Redistributions in binary form must reproduce the above copyright
10275970Scy *    notice, this list of conditions and the following disclaimer in the
11275970Scy *    documentation and/or other materials provided with the distribution.
12275970Scy * 3. The name of the author may not be used to endorse or promote products
13275970Scy *    derived from this software without specific prior written permission.
14275970Scy *
15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25275970Scy */
26275970Scy
27275970Scy/* Based on software by Adam Langly. Adam's original message:
28275970Scy *
29275970Scy * Async DNS Library
30275970Scy * Adam Langley <agl@imperialviolet.org>
31275970Scy * http://www.imperialviolet.org/eventdns.html
32275970Scy * Public Domain code
33275970Scy *
34275970Scy * This software is Public Domain. To view a copy of the public domain dedication,
35275970Scy * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
36275970Scy * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
37275970Scy *
38275970Scy * I ask and expect, but do not require, that all derivative works contain an
39275970Scy * attribution similar to:
40275970Scy *	Parts developed by Adam Langley <agl@imperialviolet.org>
41275970Scy *
42275970Scy * You may wish to replace the word "Parts" with something else depending on
43275970Scy * the amount of original code.
44275970Scy *
45275970Scy * (Derivative works does not include programs which link against, run or include
46275970Scy * the source verbatim in their source distributions)
47275970Scy *
48275970Scy * Version: 0.1b
49275970Scy */
50275970Scy
51275970Scy#include "event2/event-config.h"
52275970Scy#include "evconfig-private.h"
53275970Scy
54275970Scy#include <sys/types.h>
55275970Scy
56275970Scy#ifndef _FORTIFY_SOURCE
57275970Scy#define _FORTIFY_SOURCE 3
58275970Scy#endif
59275970Scy
60275970Scy#include <string.h>
61275970Scy#include <fcntl.h>
62275970Scy#ifdef EVENT__HAVE_SYS_TIME_H
63275970Scy#include <sys/time.h>
64275970Scy#endif
65275970Scy#ifdef EVENT__HAVE_STDINT_H
66275970Scy#include <stdint.h>
67275970Scy#endif
68275970Scy#include <stdlib.h>
69275970Scy#include <string.h>
70275970Scy#include <errno.h>
71275970Scy#ifdef EVENT__HAVE_UNISTD_H
72275970Scy#include <unistd.h>
73275970Scy#endif
74275970Scy#include <limits.h>
75275970Scy#include <sys/stat.h>
76275970Scy#include <stdio.h>
77275970Scy#include <stdarg.h>
78275970Scy#ifdef _WIN32
79275970Scy#include <winsock2.h>
80275970Scy#include <ws2tcpip.h>
81275970Scy#ifndef _WIN32_IE
82275970Scy#define _WIN32_IE 0x400
83275970Scy#endif
84275970Scy#include <shlobj.h>
85275970Scy#endif
86275970Scy
87275970Scy#include "event2/dns.h"
88275970Scy#include "event2/dns_struct.h"
89275970Scy#include "event2/dns_compat.h"
90275970Scy#include "event2/util.h"
91275970Scy#include "event2/event.h"
92275970Scy#include "event2/event_struct.h"
93275970Scy#include "event2/thread.h"
94275970Scy
95275970Scy#include "defer-internal.h"
96275970Scy#include "log-internal.h"
97275970Scy#include "mm-internal.h"
98275970Scy#include "strlcpy-internal.h"
99275970Scy#include "ipv6-internal.h"
100275970Scy#include "util-internal.h"
101275970Scy#include "evthread-internal.h"
102275970Scy#ifdef _WIN32
103275970Scy#include <ctype.h>
104275970Scy#include <winsock2.h>
105275970Scy#include <windows.h>
106275970Scy#include <iphlpapi.h>
107275970Scy#include <io.h>
108275970Scy#else
109275970Scy#include <sys/socket.h>
110275970Scy#include <netinet/in.h>
111275970Scy#include <arpa/inet.h>
112275970Scy#endif
113275970Scy
114275970Scy#ifdef EVENT__HAVE_NETINET_IN6_H
115275970Scy#include <netinet/in6.h>
116275970Scy#endif
117275970Scy
118275970Scy#define EVDNS_LOG_DEBUG EVENT_LOG_DEBUG
119275970Scy#define EVDNS_LOG_WARN EVENT_LOG_WARN
120275970Scy#define EVDNS_LOG_MSG EVENT_LOG_MSG
121275970Scy
122275970Scy#ifndef HOST_NAME_MAX
123275970Scy#define HOST_NAME_MAX 255
124275970Scy#endif
125275970Scy
126275970Scy#include <stdio.h>
127275970Scy
128275970Scy#undef MIN
129275970Scy#define MIN(a,b) ((a)<(b)?(a):(b))
130275970Scy
131275970Scy#define ASSERT_VALID_REQUEST(req) \
132275970Scy	EVUTIL_ASSERT((req)->handle && (req)->handle->current_req == (req))
133275970Scy
134275970Scy#define u64 ev_uint64_t
135275970Scy#define u32 ev_uint32_t
136275970Scy#define u16 ev_uint16_t
137275970Scy#define u8  ev_uint8_t
138275970Scy
139275970Scy/* maximum number of addresses from a single packet */
140275970Scy/* that we bother recording */
141275970Scy#define MAX_V4_ADDRS 32
142275970Scy#define MAX_V6_ADDRS 32
143275970Scy
144275970Scy
145275970Scy#define TYPE_A	       EVDNS_TYPE_A
146275970Scy#define TYPE_CNAME     5
147275970Scy#define TYPE_PTR       EVDNS_TYPE_PTR
148275970Scy#define TYPE_SOA       EVDNS_TYPE_SOA
149275970Scy#define TYPE_AAAA      EVDNS_TYPE_AAAA
150275970Scy
151275970Scy#define CLASS_INET     EVDNS_CLASS_INET
152275970Scy
153275970Scy/* Persistent handle.  We keep this separate from 'struct request' since we
154275970Scy * need some object to last for as long as an evdns_request is outstanding so
155275970Scy * that it can be canceled, whereas a search request can lead to multiple
156275970Scy * 'struct request' instances being created over its lifetime. */
157275970Scystruct evdns_request {
158275970Scy	struct request *current_req;
159275970Scy	struct evdns_base *base;
160275970Scy
161275970Scy	int pending_cb; /* Waiting for its callback to be invoked; not
162275970Scy			 * owned by event base any more. */
163275970Scy
164275970Scy	/* elements used by the searching code */
165275970Scy	int search_index;
166275970Scy	struct search_state *search_state;
167275970Scy	char *search_origname;	/* needs to be free()ed */
168275970Scy	int search_flags;
169275970Scy};
170275970Scy
171275970Scystruct request {
172275970Scy	u8 *request;  /* the dns packet data */
173275970Scy	u8 request_type; /* TYPE_PTR or TYPE_A or TYPE_AAAA */
174275970Scy	unsigned int request_len;
175275970Scy	int reissue_count;
176275970Scy	int tx_count;  /* the number of times that this packet has been sent */
177275970Scy	void *user_pointer;  /* the pointer given to us for this request */
178275970Scy	evdns_callback_type user_callback;
179275970Scy	struct nameserver *ns;	/* the server which we last sent it */
180275970Scy
181275970Scy	/* these objects are kept in a circular list */
182275970Scy	/* XXX We could turn this into a CIRCLEQ. */
183275970Scy	struct request *next, *prev;
184275970Scy
185275970Scy	struct event timeout_event;
186275970Scy
187275970Scy	u16 trans_id;  /* the transaction id */
188275970Scy	unsigned request_appended :1;	/* true if the request pointer is data which follows this struct */
189275970Scy	unsigned transmit_me :1;  /* needs to be transmitted */
190275970Scy
191275970Scy	/* XXXX This is a horrible hack. */
192275970Scy	char **put_cname_in_ptr; /* store the cname here if we get one. */
193275970Scy
194275970Scy	struct evdns_base *base;
195275970Scy
196275970Scy	struct evdns_request *handle;
197275970Scy};
198275970Scy
199275970Scystruct reply {
200275970Scy	unsigned int type;
201275970Scy	unsigned int have_answer : 1;
202275970Scy	union {
203275970Scy		struct {
204275970Scy			u32 addrcount;
205275970Scy			u32 addresses[MAX_V4_ADDRS];
206275970Scy		} a;
207275970Scy		struct {
208275970Scy			u32 addrcount;
209275970Scy			struct in6_addr addresses[MAX_V6_ADDRS];
210275970Scy		} aaaa;
211275970Scy		struct {
212275970Scy			char name[HOST_NAME_MAX];
213275970Scy		} ptr;
214275970Scy	} data;
215275970Scy};
216275970Scy
217275970Scystruct nameserver {
218275970Scy	evutil_socket_t socket;	 /* a connected UDP socket */
219275970Scy	struct sockaddr_storage address;
220275970Scy	ev_socklen_t addrlen;
221275970Scy	int failed_times;  /* number of times which we have given this server a chance */
222275970Scy	int timedout;  /* number of times in a row a request has timed out */
223275970Scy	struct event event;
224275970Scy	/* these objects are kept in a circular list */
225275970Scy	struct nameserver *next, *prev;
226275970Scy	struct event timeout_event;  /* used to keep the timeout for */
227275970Scy				     /* when we next probe this server. */
228275970Scy				     /* Valid if state == 0 */
229275970Scy	/* Outstanding probe request for this nameserver, if any */
230275970Scy	struct evdns_request *probe_request;
231275970Scy	char state;  /* zero if we think that this server is down */
232275970Scy	char choked;  /* true if we have an EAGAIN from this server's socket */
233275970Scy	char write_waiting;  /* true if we are waiting for EV_WRITE events */
234275970Scy	struct evdns_base *base;
235275970Scy
236275970Scy	/* Number of currently inflight requests: used
237275970Scy	 * to track when we should add/del the event. */
238275970Scy	int requests_inflight;
239275970Scy};
240275970Scy
241275970Scy
242275970Scy/* Represents a local port where we're listening for DNS requests. Right now, */
243275970Scy/* only UDP is supported. */
244275970Scystruct evdns_server_port {
245275970Scy	evutil_socket_t socket; /* socket we use to read queries and write replies. */
246275970Scy	int refcnt; /* reference count. */
247275970Scy	char choked; /* Are we currently blocked from writing? */
248275970Scy	char closing; /* Are we trying to close this port, pending writes? */
249275970Scy	evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
250275970Scy	void *user_data; /* Opaque pointer passed to user_callback */
251275970Scy	struct event event; /* Read/write event */
252275970Scy	/* circular list of replies that we want to write. */
253275970Scy	struct server_request *pending_replies;
254275970Scy	struct event_base *event_base;
255275970Scy
256275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT
257275970Scy	void *lock;
258275970Scy#endif
259275970Scy};
260275970Scy
261275970Scy/* Represents part of a reply being built.	(That is, a single RR.) */
262275970Scystruct server_reply_item {
263275970Scy	struct server_reply_item *next; /* next item in sequence. */
264275970Scy	char *name; /* name part of the RR */
265275970Scy	u16 type; /* The RR type */
266275970Scy	u16 class; /* The RR class (usually CLASS_INET) */
267275970Scy	u32 ttl; /* The RR TTL */
268275970Scy	char is_name; /* True iff data is a label */
269275970Scy	u16 datalen; /* Length of data; -1 if data is a label */
270275970Scy	void *data; /* The contents of the RR */
271275970Scy};
272275970Scy
273275970Scy/* Represents a request that we've received as a DNS server, and holds */
274275970Scy/* the components of the reply as we're constructing it. */
275275970Scystruct server_request {
276275970Scy	/* Pointers to the next and previous entries on the list of replies */
277275970Scy	/* that we're waiting to write.	 Only set if we have tried to respond */
278275970Scy	/* and gotten EAGAIN. */
279275970Scy	struct server_request *next_pending;
280275970Scy	struct server_request *prev_pending;
281275970Scy
282275970Scy	u16 trans_id; /* Transaction id. */
283275970Scy	struct evdns_server_port *port; /* Which port received this request on? */
284275970Scy	struct sockaddr_storage addr; /* Where to send the response */
285275970Scy	ev_socklen_t addrlen; /* length of addr */
286275970Scy
287275970Scy	int n_answer; /* how many answer RRs have been set? */
288275970Scy	int n_authority; /* how many authority RRs have been set? */
289275970Scy	int n_additional; /* how many additional RRs have been set? */
290275970Scy
291275970Scy	struct server_reply_item *answer; /* linked list of answer RRs */
292275970Scy	struct server_reply_item *authority; /* linked list of authority RRs */
293275970Scy	struct server_reply_item *additional; /* linked list of additional RRs */
294275970Scy
295275970Scy	/* Constructed response.  Only set once we're ready to send a reply. */
296275970Scy	/* Once this is set, the RR fields are cleared, and no more should be set. */
297275970Scy	char *response;
298275970Scy	size_t response_len;
299275970Scy
300275970Scy	/* Caller-visible fields: flags, questions. */
301275970Scy	struct evdns_server_request base;
302275970Scy};
303275970Scy
304275970Scystruct evdns_base {
305275970Scy	/* An array of n_req_heads circular lists for inflight requests.
306275970Scy	 * Each inflight request req is in req_heads[req->trans_id % n_req_heads].
307275970Scy	 */
308275970Scy	struct request **req_heads;
309275970Scy	/* A circular list of requests that we're waiting to send, but haven't
310275970Scy	 * sent yet because there are too many requests inflight */
311275970Scy	struct request *req_waiting_head;
312275970Scy	/* A circular list of nameservers. */
313275970Scy	struct nameserver *server_head;
314275970Scy	int n_req_heads;
315275970Scy
316275970Scy	struct event_base *event_base;
317275970Scy
318275970Scy	/* The number of good nameservers that we have */
319275970Scy	int global_good_nameservers;
320275970Scy
321275970Scy	/* inflight requests are contained in the req_head list */
322275970Scy	/* and are actually going out across the network */
323275970Scy	int global_requests_inflight;
324275970Scy	/* requests which aren't inflight are in the waiting list */
325275970Scy	/* and are counted here */
326275970Scy	int global_requests_waiting;
327275970Scy
328275970Scy	int global_max_requests_inflight;
329275970Scy
330275970Scy	struct timeval global_timeout;	/* 5 seconds by default */
331275970Scy	int global_max_reissues;  /* a reissue occurs when we get some errors from the server */
332275970Scy	int global_max_retransmits;  /* number of times we'll retransmit a request which timed out */
333275970Scy	/* number of timeouts in a row before we consider this server to be down */
334275970Scy	int global_max_nameserver_timeout;
335275970Scy	/* true iff we will use the 0x20 hack to prevent poisoning attacks. */
336275970Scy	int global_randomize_case;
337275970Scy
338275970Scy	/* The first time that a nameserver fails, how long do we wait before
339275970Scy	 * probing to see if it has returned?  */
340275970Scy	struct timeval global_nameserver_probe_initial_timeout;
341275970Scy
342275970Scy	/** Port to bind to for outgoing DNS packets. */
343275970Scy	struct sockaddr_storage global_outgoing_address;
344275970Scy	/** ev_socklen_t for global_outgoing_address. 0 if it isn't set. */
345275970Scy	ev_socklen_t global_outgoing_addrlen;
346275970Scy
347275970Scy	struct timeval global_getaddrinfo_allow_skew;
348275970Scy
349275970Scy	int getaddrinfo_ipv4_timeouts;
350275970Scy	int getaddrinfo_ipv6_timeouts;
351275970Scy	int getaddrinfo_ipv4_answered;
352275970Scy	int getaddrinfo_ipv6_answered;
353275970Scy
354275970Scy	struct search_state *global_search_state;
355275970Scy
356275970Scy	TAILQ_HEAD(hosts_list, hosts_entry) hostsdb;
357275970Scy
358275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT
359275970Scy	void *lock;
360275970Scy#endif
361275970Scy
362275970Scy	int disable_when_inactive;
363275970Scy};
364275970Scy
365275970Scystruct hosts_entry {
366275970Scy	TAILQ_ENTRY(hosts_entry) next;
367275970Scy	union {
368275970Scy		struct sockaddr sa;
369275970Scy		struct sockaddr_in sin;
370275970Scy		struct sockaddr_in6 sin6;
371275970Scy	} addr;
372275970Scy	int addrlen;
373275970Scy	char hostname[1];
374275970Scy};
375275970Scy
376275970Scystatic struct evdns_base *current_base = NULL;
377275970Scy
378275970Scystruct evdns_base *
379275970Scyevdns_get_global_base(void)
380275970Scy{
381275970Scy	return current_base;
382275970Scy}
383275970Scy
384275970Scy/* Given a pointer to an evdns_server_request, get the corresponding */
385275970Scy/* server_request. */
386275970Scy#define TO_SERVER_REQUEST(base_ptr)					\
387275970Scy	((struct server_request*)					\
388275970Scy	  (((char*)(base_ptr) - evutil_offsetof(struct server_request, base))))
389275970Scy
390275970Scy#define REQ_HEAD(base, id) ((base)->req_heads[id % (base)->n_req_heads])
391275970Scy
392275970Scystatic struct nameserver *nameserver_pick(struct evdns_base *base);
393275970Scystatic void evdns_request_insert(struct request *req, struct request **head);
394275970Scystatic void evdns_request_remove(struct request *req, struct request **head);
395275970Scystatic void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg);
396275970Scystatic int evdns_transmit(struct evdns_base *base);
397275970Scystatic int evdns_request_transmit(struct request *req);
398275970Scystatic void nameserver_send_probe(struct nameserver *const ns);
399275970Scystatic void search_request_finished(struct evdns_request *const);
400275970Scystatic int search_try_next(struct evdns_request *const req);
401275970Scystatic struct request *search_request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
402275970Scystatic void evdns_requests_pump_waiting_queue(struct evdns_base *base);
403275970Scystatic u16 transaction_id_pick(struct evdns_base *base);
404275970Scystatic struct request *request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
405275970Scystatic void request_submit(struct request *const req);
406275970Scy
407275970Scystatic int server_request_free(struct server_request *req);
408275970Scystatic void server_request_free_answers(struct server_request *req);
409275970Scystatic void server_port_free(struct evdns_server_port *port);
410275970Scystatic void server_port_ready_callback(evutil_socket_t fd, short events, void *arg);
411275970Scystatic int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename);
412275970Scystatic int evdns_base_set_option_impl(struct evdns_base *base,
413275970Scy    const char *option, const char *val, int flags);
414275970Scystatic void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests);
415275970Scystatic void evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg);
416275970Scy
417275970Scystatic int strtoint(const char *const str);
418275970Scy
419275970Scy#ifdef EVENT__DISABLE_THREAD_SUPPORT
420275970Scy#define EVDNS_LOCK(base)  EVUTIL_NIL_STMT_
421275970Scy#define EVDNS_UNLOCK(base) EVUTIL_NIL_STMT_
422275970Scy#define ASSERT_LOCKED(base) EVUTIL_NIL_STMT_
423275970Scy#else
424275970Scy#define EVDNS_LOCK(base)			\
425275970Scy	EVLOCK_LOCK((base)->lock, 0)
426275970Scy#define EVDNS_UNLOCK(base)			\
427275970Scy	EVLOCK_UNLOCK((base)->lock, 0)
428275970Scy#define ASSERT_LOCKED(base)			\
429275970Scy	EVLOCK_ASSERT_LOCKED((base)->lock)
430275970Scy#endif
431275970Scy
432275970Scystatic evdns_debug_log_fn_type evdns_log_fn = NULL;
433275970Scy
434275970Scyvoid
435275970Scyevdns_set_log_fn(evdns_debug_log_fn_type fn)
436275970Scy{
437275970Scy	evdns_log_fn = fn;
438275970Scy}
439275970Scy
440275970Scy#ifdef __GNUC__
441275970Scy#define EVDNS_LOG_CHECK	 __attribute__ ((format(printf, 2, 3)))
442275970Scy#else
443275970Scy#define EVDNS_LOG_CHECK
444275970Scy#endif
445275970Scy
446275970Scystatic void evdns_log_(int severity, const char *fmt, ...) EVDNS_LOG_CHECK;
447275970Scystatic void
448275970Scyevdns_log_(int severity, const char *fmt, ...)
449275970Scy{
450275970Scy	va_list args;
451275970Scy	va_start(args,fmt);
452275970Scy	if (evdns_log_fn) {
453275970Scy		char buf[512];
454275970Scy		int is_warn = (severity == EVDNS_LOG_WARN);
455275970Scy		evutil_vsnprintf(buf, sizeof(buf), fmt, args);
456275970Scy		evdns_log_fn(is_warn, buf);
457275970Scy	} else {
458275970Scy		event_logv_(severity, NULL, fmt, args);
459275970Scy	}
460275970Scy	va_end(args);
461275970Scy}
462275970Scy
463275970Scy#define log evdns_log_
464275970Scy
465275970Scy/* This walks the list of inflight requests to find the */
466275970Scy/* one with a matching transaction id. Returns NULL on */
467275970Scy/* failure */
468275970Scystatic struct request *
469275970Scyrequest_find_from_trans_id(struct evdns_base *base, u16 trans_id) {
470275970Scy	struct request *req = REQ_HEAD(base, trans_id);
471275970Scy	struct request *const started_at = req;
472275970Scy
473275970Scy	ASSERT_LOCKED(base);
474275970Scy
475275970Scy	if (req) {
476275970Scy		do {
477275970Scy			if (req->trans_id == trans_id) return req;
478275970Scy			req = req->next;
479275970Scy		} while (req != started_at);
480275970Scy	}
481275970Scy
482275970Scy	return NULL;
483275970Scy}
484275970Scy
485275970Scy/* a libevent callback function which is called when a nameserver */
486275970Scy/* has gone down and we want to test if it has came back to life yet */
487275970Scystatic void
488275970Scynameserver_prod_callback(evutil_socket_t fd, short events, void *arg) {
489275970Scy	struct nameserver *const ns = (struct nameserver *) arg;
490275970Scy	(void)fd;
491275970Scy	(void)events;
492275970Scy
493275970Scy	EVDNS_LOCK(ns->base);
494275970Scy	nameserver_send_probe(ns);
495275970Scy	EVDNS_UNLOCK(ns->base);
496275970Scy}
497275970Scy
498275970Scy/* a libevent callback which is called when a nameserver probe (to see if */
499275970Scy/* it has come back to life) times out. We increment the count of failed_times */
500275970Scy/* and wait longer to send the next probe packet. */
501275970Scystatic void
502275970Scynameserver_probe_failed(struct nameserver *const ns) {
503275970Scy	struct timeval timeout;
504275970Scy	int i;
505275970Scy
506275970Scy	ASSERT_LOCKED(ns->base);
507275970Scy	(void) evtimer_del(&ns->timeout_event);
508275970Scy	if (ns->state == 1) {
509275970Scy		/* This can happen if the nameserver acts in a way which makes us mark */
510275970Scy		/* it as bad and then starts sending good replies. */
511275970Scy		return;
512275970Scy	}
513275970Scy
514275970Scy#define MAX_PROBE_TIMEOUT 3600
515275970Scy#define TIMEOUT_BACKOFF_FACTOR 3
516275970Scy
517275970Scy	memcpy(&timeout, &ns->base->global_nameserver_probe_initial_timeout,
518275970Scy	    sizeof(struct timeval));
519275970Scy	for (i=ns->failed_times; i > 0 && timeout.tv_sec < MAX_PROBE_TIMEOUT; --i) {
520275970Scy		timeout.tv_sec *= TIMEOUT_BACKOFF_FACTOR;
521275970Scy		timeout.tv_usec *= TIMEOUT_BACKOFF_FACTOR;
522275970Scy		if (timeout.tv_usec > 1000000) {
523275970Scy			timeout.tv_sec += timeout.tv_usec / 1000000;
524275970Scy			timeout.tv_usec %= 1000000;
525275970Scy		}
526275970Scy	}
527275970Scy	if (timeout.tv_sec > MAX_PROBE_TIMEOUT) {
528275970Scy		timeout.tv_sec = MAX_PROBE_TIMEOUT;
529275970Scy		timeout.tv_usec = 0;
530275970Scy	}
531275970Scy
532275970Scy	ns->failed_times++;
533275970Scy
534275970Scy	if (evtimer_add(&ns->timeout_event, &timeout) < 0) {
535275970Scy		char addrbuf[128];
536275970Scy		log(EVDNS_LOG_WARN,
537275970Scy		    "Error from libevent when adding timer event for %s",
538275970Scy		    evutil_format_sockaddr_port_(
539275970Scy			    (struct sockaddr *)&ns->address,
540275970Scy			    addrbuf, sizeof(addrbuf)));
541275970Scy	}
542275970Scy}
543275970Scy
544285612Sdelphijstatic void
545285612Sdelphijrequest_swap_ns(struct request *req, struct nameserver *ns) {
546285612Sdelphij	if (ns && req->ns != ns) {
547285612Sdelphij		EVUTIL_ASSERT(req->ns->requests_inflight > 0);
548285612Sdelphij		req->ns->requests_inflight--;
549285612Sdelphij		ns->requests_inflight++;
550285612Sdelphij
551285612Sdelphij		req->ns = ns;
552285612Sdelphij	}
553285612Sdelphij}
554285612Sdelphij
555275970Scy/* called when a nameserver has been deemed to have failed. For example, too */
556275970Scy/* many packets have timed out etc */
557275970Scystatic void
558275970Scynameserver_failed(struct nameserver *const ns, const char *msg) {
559275970Scy	struct request *req, *started_at;
560275970Scy	struct evdns_base *base = ns->base;
561275970Scy	int i;
562275970Scy	char addrbuf[128];
563275970Scy
564275970Scy	ASSERT_LOCKED(base);
565275970Scy	/* if this nameserver has already been marked as failed */
566275970Scy	/* then don't do anything */
567275970Scy	if (!ns->state) return;
568275970Scy
569275970Scy	log(EVDNS_LOG_MSG, "Nameserver %s has failed: %s",
570275970Scy	    evutil_format_sockaddr_port_(
571275970Scy		    (struct sockaddr *)&ns->address,
572275970Scy		    addrbuf, sizeof(addrbuf)),
573275970Scy	    msg);
574275970Scy
575275970Scy	base->global_good_nameservers--;
576275970Scy	EVUTIL_ASSERT(base->global_good_nameservers >= 0);
577275970Scy	if (base->global_good_nameservers == 0) {
578275970Scy		log(EVDNS_LOG_MSG, "All nameservers have failed");
579275970Scy	}
580275970Scy
581275970Scy	ns->state = 0;
582275970Scy	ns->failed_times = 1;
583275970Scy
584275970Scy	if (evtimer_add(&ns->timeout_event,
585275970Scy		&base->global_nameserver_probe_initial_timeout) < 0) {
586275970Scy		log(EVDNS_LOG_WARN,
587275970Scy		    "Error from libevent when adding timer event for %s",
588275970Scy		    evutil_format_sockaddr_port_(
589275970Scy			    (struct sockaddr *)&ns->address,
590275970Scy			    addrbuf, sizeof(addrbuf)));
591275970Scy		/* ???? Do more? */
592275970Scy	}
593275970Scy
594275970Scy	/* walk the list of inflight requests to see if any can be reassigned to */
595275970Scy	/* a different server. Requests in the waiting queue don't have a */
596275970Scy	/* nameserver assigned yet */
597275970Scy
598275970Scy	/* if we don't have *any* good nameservers then there's no point */
599275970Scy	/* trying to reassign requests to one */
600275970Scy	if (!base->global_good_nameservers) return;
601275970Scy
602275970Scy	for (i = 0; i < base->n_req_heads; ++i) {
603275970Scy		req = started_at = base->req_heads[i];
604275970Scy		if (req) {
605275970Scy			do {
606275970Scy				if (req->tx_count == 0 && req->ns == ns) {
607275970Scy					/* still waiting to go out, can be moved */
608275970Scy					/* to another server */
609285612Sdelphij					request_swap_ns(req, nameserver_pick(base));
610275970Scy				}
611275970Scy				req = req->next;
612275970Scy			} while (req != started_at);
613275970Scy		}
614275970Scy	}
615275970Scy}
616275970Scy
617275970Scystatic void
618275970Scynameserver_up(struct nameserver *const ns)
619275970Scy{
620275970Scy	char addrbuf[128];
621275970Scy	ASSERT_LOCKED(ns->base);
622275970Scy	if (ns->state) return;
623275970Scy	log(EVDNS_LOG_MSG, "Nameserver %s is back up",
624275970Scy	    evutil_format_sockaddr_port_(
625275970Scy		    (struct sockaddr *)&ns->address,
626275970Scy		    addrbuf, sizeof(addrbuf)));
627275970Scy	evtimer_del(&ns->timeout_event);
628275970Scy	if (ns->probe_request) {
629275970Scy		evdns_cancel_request(ns->base, ns->probe_request);
630275970Scy		ns->probe_request = NULL;
631275970Scy	}
632275970Scy	ns->state = 1;
633275970Scy	ns->failed_times = 0;
634275970Scy	ns->timedout = 0;
635275970Scy	ns->base->global_good_nameservers++;
636275970Scy}
637275970Scy
638275970Scystatic void
639275970Scyrequest_trans_id_set(struct request *const req, const u16 trans_id) {
640275970Scy	req->trans_id = trans_id;
641275970Scy	*((u16 *) req->request) = htons(trans_id);
642275970Scy}
643275970Scy
644275970Scy/* Called to remove a request from a list and dealloc it. */
645275970Scy/* head is a pointer to the head of the list it should be */
646275970Scy/* removed from or NULL if the request isn't in a list. */
647275970Scy/* when free_handle is one, free the handle as well. */
648275970Scystatic void
649275970Scyrequest_finished(struct request *const req, struct request **head, int free_handle) {
650275970Scy	struct evdns_base *base = req->base;
651275970Scy	int was_inflight = (head != &base->req_waiting_head);
652275970Scy	EVDNS_LOCK(base);
653275970Scy	ASSERT_VALID_REQUEST(req);
654275970Scy
655275970Scy	if (head)
656275970Scy		evdns_request_remove(req, head);
657275970Scy
658275970Scy	log(EVDNS_LOG_DEBUG, "Removing timeout for request %p", req);
659275970Scy	if (was_inflight) {
660275970Scy		evtimer_del(&req->timeout_event);
661275970Scy		base->global_requests_inflight--;
662275970Scy		req->ns->requests_inflight--;
663275970Scy	} else {
664275970Scy		base->global_requests_waiting--;
665275970Scy	}
666275970Scy	/* it was initialized during request_new / evtimer_assign */
667275970Scy	event_debug_unassign(&req->timeout_event);
668275970Scy
669275970Scy	if (req->ns &&
670275970Scy	    req->ns->requests_inflight == 0 &&
671275970Scy	    req->base->disable_when_inactive) {
672275970Scy		event_del(&req->ns->event);
673285612Sdelphij		evtimer_del(&req->ns->timeout_event);
674275970Scy	}
675275970Scy
676275970Scy	if (!req->request_appended) {
677275970Scy		/* need to free the request data on it's own */
678275970Scy		mm_free(req->request);
679275970Scy	} else {
680275970Scy		/* the request data is appended onto the header */
681275970Scy		/* so everything gets free()ed when we: */
682275970Scy	}
683275970Scy
684275970Scy	if (req->handle) {
685275970Scy		EVUTIL_ASSERT(req->handle->current_req == req);
686275970Scy
687275970Scy		if (free_handle) {
688275970Scy			search_request_finished(req->handle);
689275970Scy			req->handle->current_req = NULL;
690275970Scy			if (! req->handle->pending_cb) {
691275970Scy				/* If we're planning to run the callback,
692275970Scy				 * don't free the handle until later. */
693275970Scy				mm_free(req->handle);
694275970Scy			}
695275970Scy			req->handle = NULL; /* If we have a bug, let's crash
696275970Scy					     * early */
697275970Scy		} else {
698275970Scy			req->handle->current_req = NULL;
699275970Scy		}
700275970Scy	}
701275970Scy
702275970Scy	mm_free(req);
703275970Scy
704275970Scy	evdns_requests_pump_waiting_queue(base);
705275970Scy	EVDNS_UNLOCK(base);
706275970Scy}
707275970Scy
708275970Scy/* This is called when a server returns a funny error code. */
709275970Scy/* We try the request again with another server. */
710275970Scy/* */
711275970Scy/* return: */
712275970Scy/*   0 ok */
713275970Scy/*   1 failed/reissue is pointless */
714275970Scystatic int
715275970Scyrequest_reissue(struct request *req) {
716275970Scy	const struct nameserver *const last_ns = req->ns;
717275970Scy	ASSERT_LOCKED(req->base);
718275970Scy	ASSERT_VALID_REQUEST(req);
719275970Scy	/* the last nameserver should have been marked as failing */
720275970Scy	/* by the caller of this function, therefore pick will try */
721275970Scy	/* not to return it */
722285612Sdelphij	request_swap_ns(req, nameserver_pick(req->base));
723275970Scy	if (req->ns == last_ns) {
724275970Scy		/* ... but pick did return it */
725275970Scy		/* not a lot of point in trying again with the */
726275970Scy		/* same server */
727275970Scy		return 1;
728275970Scy	}
729275970Scy
730275970Scy	req->reissue_count++;
731275970Scy	req->tx_count = 0;
732275970Scy	req->transmit_me = 1;
733275970Scy
734275970Scy	return 0;
735275970Scy}
736275970Scy
737275970Scy/* this function looks for space on the inflight queue and promotes */
738275970Scy/* requests from the waiting queue if it can. */
739275970Scy/* */
740275970Scy/* TODO: */
741275970Scy/* add return code, see at nameserver_pick() and other functions. */
742275970Scystatic void
743275970Scyevdns_requests_pump_waiting_queue(struct evdns_base *base) {
744275970Scy	ASSERT_LOCKED(base);
745275970Scy	while (base->global_requests_inflight < base->global_max_requests_inflight &&
746275970Scy		   base->global_requests_waiting) {
747275970Scy		struct request *req;
748275970Scy
749275970Scy		EVUTIL_ASSERT(base->req_waiting_head);
750275970Scy		req = base->req_waiting_head;
751275970Scy
752275970Scy		req->ns = nameserver_pick(base);
753275970Scy		if (!req->ns)
754275970Scy			return;
755275970Scy
756275970Scy		/* move a request from the waiting queue to the inflight queue */
757275970Scy		req->ns->requests_inflight++;
758275970Scy
759275970Scy		evdns_request_remove(req, &base->req_waiting_head);
760275970Scy
761275970Scy		base->global_requests_waiting--;
762275970Scy		base->global_requests_inflight++;
763275970Scy
764275970Scy		request_trans_id_set(req, transaction_id_pick(base));
765275970Scy
766275970Scy		evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
767275970Scy		evdns_request_transmit(req);
768275970Scy		evdns_transmit(base);
769275970Scy	}
770275970Scy}
771275970Scy
772275970Scy/* TODO(nickm) document */
773275970Scystruct deferred_reply_callback {
774275970Scy	struct event_callback deferred;
775275970Scy	struct evdns_request *handle;
776275970Scy	u8 request_type;
777275970Scy	u8 have_reply;
778275970Scy	u32 ttl;
779275970Scy	u32 err;
780275970Scy	evdns_callback_type user_callback;
781275970Scy	struct reply reply;
782275970Scy};
783275970Scy
784275970Scystatic void
785275970Scyreply_run_callback(struct event_callback *d, void *user_pointer)
786275970Scy{
787275970Scy	struct deferred_reply_callback *cb =
788275970Scy	    EVUTIL_UPCAST(d, struct deferred_reply_callback, deferred);
789275970Scy
790275970Scy	switch (cb->request_type) {
791275970Scy	case TYPE_A:
792275970Scy		if (cb->have_reply)
793275970Scy			cb->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
794275970Scy			    cb->reply.data.a.addrcount, cb->ttl,
795275970Scy			    cb->reply.data.a.addresses,
796275970Scy			    user_pointer);
797275970Scy		else
798275970Scy			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
799275970Scy		break;
800275970Scy	case TYPE_PTR:
801275970Scy		if (cb->have_reply) {
802275970Scy			char *name = cb->reply.data.ptr.name;
803275970Scy			cb->user_callback(DNS_ERR_NONE, DNS_PTR, 1, cb->ttl,
804275970Scy			    &name, user_pointer);
805275970Scy		} else {
806275970Scy			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
807275970Scy		}
808275970Scy		break;
809275970Scy	case TYPE_AAAA:
810275970Scy		if (cb->have_reply)
811275970Scy			cb->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
812275970Scy			    cb->reply.data.aaaa.addrcount, cb->ttl,
813275970Scy			    cb->reply.data.aaaa.addresses,
814275970Scy			    user_pointer);
815275970Scy		else
816275970Scy			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
817275970Scy		break;
818275970Scy	default:
819275970Scy		EVUTIL_ASSERT(0);
820275970Scy	}
821275970Scy
822275970Scy	if (cb->handle && cb->handle->pending_cb) {
823275970Scy		mm_free(cb->handle);
824275970Scy	}
825275970Scy
826275970Scy	mm_free(cb);
827275970Scy}
828275970Scy
829275970Scystatic void
830275970Scyreply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply)
831275970Scy{
832275970Scy	struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d));
833275970Scy
834275970Scy	if (!d) {
835275970Scy		event_warn("%s: Couldn't allocate space for deferred callback.",
836275970Scy		    __func__);
837275970Scy		return;
838275970Scy	}
839275970Scy
840275970Scy	ASSERT_LOCKED(req->base);
841275970Scy
842275970Scy	d->request_type = req->request_type;
843275970Scy	d->user_callback = req->user_callback;
844275970Scy	d->ttl = ttl;
845275970Scy	d->err = err;
846275970Scy	if (reply) {
847275970Scy		d->have_reply = 1;
848275970Scy		memcpy(&d->reply, reply, sizeof(struct reply));
849275970Scy	}
850275970Scy
851275970Scy	if (req->handle) {
852275970Scy		req->handle->pending_cb = 1;
853275970Scy		d->handle = req->handle;
854275970Scy	}
855275970Scy
856275970Scy	event_deferred_cb_init_(
857275970Scy	    &d->deferred,
858275970Scy	    event_get_priority(&req->timeout_event),
859275970Scy	    reply_run_callback,
860275970Scy	    req->user_pointer);
861275970Scy	event_deferred_cb_schedule_(
862275970Scy		req->base->event_base,
863275970Scy		&d->deferred);
864275970Scy}
865275970Scy
866275970Scy/* this processes a parsed reply packet */
867275970Scystatic void
868275970Scyreply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
869275970Scy	int error;
870275970Scy	char addrbuf[128];
871275970Scy	static const int error_codes[] = {
872275970Scy		DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
873275970Scy		DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
874275970Scy	};
875275970Scy
876275970Scy	ASSERT_LOCKED(req->base);
877275970Scy	ASSERT_VALID_REQUEST(req);
878275970Scy
879275970Scy	if (flags & 0x020f || !reply || !reply->have_answer) {
880275970Scy		/* there was an error */
881275970Scy		if (flags & 0x0200) {
882275970Scy			error = DNS_ERR_TRUNCATED;
883275970Scy		} else if (flags & 0x000f) {
884275970Scy			u16 error_code = (flags & 0x000f) - 1;
885275970Scy			if (error_code > 4) {
886275970Scy				error = DNS_ERR_UNKNOWN;
887275970Scy			} else {
888275970Scy				error = error_codes[error_code];
889275970Scy			}
890275970Scy		} else if (reply && !reply->have_answer) {
891275970Scy			error = DNS_ERR_NODATA;
892275970Scy		} else {
893275970Scy			error = DNS_ERR_UNKNOWN;
894275970Scy		}
895275970Scy
896275970Scy		switch (error) {
897275970Scy		case DNS_ERR_NOTIMPL:
898275970Scy		case DNS_ERR_REFUSED:
899275970Scy			/* we regard these errors as marking a bad nameserver */
900275970Scy			if (req->reissue_count < req->base->global_max_reissues) {
901275970Scy				char msg[64];
902275970Scy				evutil_snprintf(msg, sizeof(msg), "Bad response %d (%s)",
903275970Scy					 error, evdns_err_to_string(error));
904275970Scy				nameserver_failed(req->ns, msg);
905275970Scy				if (!request_reissue(req)) return;
906275970Scy			}
907275970Scy			break;
908275970Scy		case DNS_ERR_SERVERFAILED:
909275970Scy			/* rcode 2 (servfailed) sometimes means "we
910275970Scy			 * are broken" and sometimes (with some binds)
911275970Scy			 * means "that request was very confusing."
912275970Scy			 * Treat this as a timeout, not a failure.
913275970Scy			 */
914275970Scy			log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver"
915275970Scy				"at %s; will allow the request to time out.",
916275970Scy			    evutil_format_sockaddr_port_(
917275970Scy				    (struct sockaddr *)&req->ns->address,
918275970Scy				    addrbuf, sizeof(addrbuf)));
919275970Scy			/* Call the timeout function */
920275970Scy			evdns_request_timeout_callback(0, 0, req);
921275970Scy			return;
922275970Scy		default:
923275970Scy			/* we got a good reply from the nameserver: it is up. */
924275970Scy			if (req->handle == req->ns->probe_request) {
925275970Scy				/* Avoid double-free */
926275970Scy				req->ns->probe_request = NULL;
927275970Scy			}
928275970Scy
929275970Scy			nameserver_up(req->ns);
930275970Scy		}
931275970Scy
932275970Scy		if (req->handle->search_state &&
933275970Scy		    req->request_type != TYPE_PTR) {
934275970Scy			/* if we have a list of domains to search in,
935275970Scy			 * try the next one */
936275970Scy			if (!search_try_next(req->handle)) {
937275970Scy				/* a new request was issued so this
938275970Scy				 * request is finished and */
939275970Scy				/* the user callback will be made when
940275970Scy				 * that request (or a */
941275970Scy				/* child of it) finishes. */
942275970Scy				return;
943275970Scy			}
944275970Scy		}
945275970Scy
946275970Scy		/* all else failed. Pass the failure up */
947275970Scy		reply_schedule_callback(req, ttl, error, NULL);
948275970Scy		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
949275970Scy	} else {
950275970Scy		/* all ok, tell the user */
951275970Scy		reply_schedule_callback(req, ttl, 0, reply);
952275970Scy		if (req->handle == req->ns->probe_request)
953275970Scy			req->ns->probe_request = NULL; /* Avoid double-free */
954275970Scy		nameserver_up(req->ns);
955275970Scy		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
956275970Scy	}
957275970Scy}
958275970Scy
959275970Scystatic int
960275970Scyname_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
961275970Scy	int name_end = -1;
962275970Scy	int j = *idx;
963275970Scy	int ptr_count = 0;
964275970Scy#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&t32_, packet + j, 4); j += 4; x = ntohl(t32_); } while (0)
965275970Scy#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&t_, packet + j, 2); j += 2; x = ntohs(t_); } while (0)
966275970Scy#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while (0)
967275970Scy
968275970Scy	char *cp = name_out;
969275970Scy	const char *const end = name_out + name_out_len;
970275970Scy
971275970Scy	/* Normally, names are a series of length prefixed strings terminated */
972275970Scy	/* with a length of 0 (the lengths are u8's < 63). */
973275970Scy	/* However, the length can start with a pair of 1 bits and that */
974275970Scy	/* means that the next 14 bits are a pointer within the current */
975275970Scy	/* packet. */
976275970Scy
977275970Scy	for (;;) {
978275970Scy		u8 label_len;
979275970Scy		if (j >= length) return -1;
980275970Scy		GET8(label_len);
981275970Scy		if (!label_len) break;
982275970Scy		if (label_len & 0xc0) {
983275970Scy			u8 ptr_low;
984275970Scy			GET8(ptr_low);
985275970Scy			if (name_end < 0) name_end = j;
986275970Scy			j = (((int)label_len & 0x3f) << 8) + ptr_low;
987275970Scy			/* Make sure that the target offset is in-bounds. */
988275970Scy			if (j < 0 || j >= length) return -1;
989275970Scy			/* If we've jumped more times than there are characters in the
990275970Scy			 * message, we must have a loop. */
991275970Scy			if (++ptr_count > length) return -1;
992275970Scy			continue;
993275970Scy		}
994275970Scy		if (label_len > 63) return -1;
995275970Scy		if (cp != name_out) {
996275970Scy			if (cp + 1 >= end) return -1;
997275970Scy			*cp++ = '.';
998275970Scy		}
999275970Scy		if (cp + label_len >= end) return -1;
1000275970Scy		memcpy(cp, packet + j, label_len);
1001275970Scy		cp += label_len;
1002275970Scy		j += label_len;
1003275970Scy	}
1004275970Scy	if (cp >= end) return -1;
1005275970Scy	*cp = '\0';
1006275970Scy	if (name_end < 0)
1007275970Scy		*idx = j;
1008275970Scy	else
1009275970Scy		*idx = name_end;
1010275970Scy	return 0;
1011275970Scy err:
1012275970Scy	return -1;
1013275970Scy}
1014275970Scy
1015275970Scy/* parses a raw request from a nameserver */
1016275970Scystatic int
1017275970Scyreply_parse(struct evdns_base *base, u8 *packet, int length) {
1018275970Scy	int j = 0, k = 0;  /* index into packet */
1019275970Scy	u16 t_;	 /* used by the macros */
1020275970Scy	u32 t32_;  /* used by the macros */
1021275970Scy	char tmp_name[256], cmp_name[256]; /* used by the macros */
1022275970Scy	int name_matches = 0;
1023275970Scy
1024275970Scy	u16 trans_id, questions, answers, authority, additional, datalength;
1025275970Scy	u16 flags = 0;
1026275970Scy	u32 ttl, ttl_r = 0xffffffff;
1027275970Scy	struct reply reply;
1028275970Scy	struct request *req = NULL;
1029275970Scy	unsigned int i;
1030275970Scy
1031275970Scy	ASSERT_LOCKED(base);
1032275970Scy
1033275970Scy	GET16(trans_id);
1034275970Scy	GET16(flags);
1035275970Scy	GET16(questions);
1036275970Scy	GET16(answers);
1037275970Scy	GET16(authority);
1038275970Scy	GET16(additional);
1039275970Scy	(void) authority; /* suppress "unused variable" warnings. */
1040275970Scy	(void) additional; /* suppress "unused variable" warnings. */
1041275970Scy
1042275970Scy	req = request_find_from_trans_id(base, trans_id);
1043275970Scy	if (!req) return -1;
1044275970Scy	EVUTIL_ASSERT(req->base == base);
1045275970Scy
1046275970Scy	memset(&reply, 0, sizeof(reply));
1047275970Scy
1048275970Scy	/* If it's not an answer, it doesn't correspond to any request. */
1049275970Scy	if (!(flags & 0x8000)) return -1;  /* must be an answer */
1050275970Scy	if ((flags & 0x020f) && (flags & 0x020f) != DNS_ERR_NOTEXIST) {
1051275970Scy		/* there was an error and it's not NXDOMAIN */
1052275970Scy		goto err;
1053275970Scy	}
1054275970Scy	/* if (!answers) return; */  /* must have an answer of some form */
1055275970Scy
1056275970Scy	/* This macro skips a name in the DNS reply. */
1057275970Scy#define SKIP_NAME						\
1058275970Scy	do { tmp_name[0] = '\0';				\
1059275970Scy		if (name_parse(packet, length, &j, tmp_name,	\
1060275970Scy			sizeof(tmp_name))<0)			\
1061275970Scy			goto err;				\
1062275970Scy	} while (0)
1063275970Scy#define TEST_NAME							\
1064275970Scy	do { tmp_name[0] = '\0';					\
1065275970Scy		cmp_name[0] = '\0';					\
1066275970Scy		k = j;							\
1067275970Scy		if (name_parse(packet, length, &j, tmp_name,		\
1068275970Scy			sizeof(tmp_name))<0)				\
1069275970Scy			goto err;					\
1070275970Scy		if (name_parse(req->request, req->request_len, &k,	\
1071275970Scy			cmp_name, sizeof(cmp_name))<0)			\
1072275970Scy			goto err;					\
1073275970Scy		if (base->global_randomize_case) {			\
1074275970Scy			if (strcmp(tmp_name, cmp_name) == 0)		\
1075275970Scy				name_matches = 1;			\
1076275970Scy		} else {						\
1077275970Scy			if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0) \
1078275970Scy				name_matches = 1;			\
1079275970Scy		}							\
1080275970Scy	} while (0)
1081275970Scy
1082275970Scy	reply.type = req->request_type;
1083275970Scy
1084275970Scy	/* skip over each question in the reply */
1085275970Scy	for (i = 0; i < questions; ++i) {
1086275970Scy		/* the question looks like
1087275970Scy		 *   <label:name><u16:type><u16:class>
1088275970Scy		 */
1089275970Scy		TEST_NAME;
1090275970Scy		j += 4;
1091275970Scy		if (j > length) goto err;
1092275970Scy	}
1093275970Scy
1094275970Scy	if (!name_matches)
1095275970Scy		goto err;
1096275970Scy
1097275970Scy	/* now we have the answer section which looks like
1098275970Scy	 * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
1099275970Scy	 */
1100275970Scy
1101275970Scy	for (i = 0; i < answers; ++i) {
1102275970Scy		u16 type, class;
1103275970Scy
1104275970Scy		SKIP_NAME;
1105275970Scy		GET16(type);
1106275970Scy		GET16(class);
1107275970Scy		GET32(ttl);
1108275970Scy		GET16(datalength);
1109275970Scy
1110275970Scy		if (type == TYPE_A && class == CLASS_INET) {
1111275970Scy			int addrcount, addrtocopy;
1112275970Scy			if (req->request_type != TYPE_A) {
1113275970Scy				j += datalength; continue;
1114275970Scy			}
1115275970Scy			if ((datalength & 3) != 0) /* not an even number of As. */
1116275970Scy			    goto err;
1117275970Scy			addrcount = datalength >> 2;
1118275970Scy			addrtocopy = MIN(MAX_V4_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
1119275970Scy
1120275970Scy			ttl_r = MIN(ttl_r, ttl);
1121275970Scy			/* we only bother with the first four addresses. */
1122275970Scy			if (j + 4*addrtocopy > length) goto err;
1123275970Scy			memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
1124275970Scy				   packet + j, 4*addrtocopy);
1125275970Scy			j += 4*addrtocopy;
1126275970Scy			reply.data.a.addrcount += addrtocopy;
1127275970Scy			reply.have_answer = 1;
1128275970Scy			if (reply.data.a.addrcount == MAX_V4_ADDRS) break;
1129275970Scy		} else if (type == TYPE_PTR && class == CLASS_INET) {
1130275970Scy			if (req->request_type != TYPE_PTR) {
1131275970Scy				j += datalength; continue;
1132275970Scy			}
1133275970Scy			if (name_parse(packet, length, &j, reply.data.ptr.name,
1134275970Scy						   sizeof(reply.data.ptr.name))<0)
1135275970Scy				goto err;
1136275970Scy			ttl_r = MIN(ttl_r, ttl);
1137275970Scy			reply.have_answer = 1;
1138275970Scy			break;
1139275970Scy		} else if (type == TYPE_CNAME) {
1140275970Scy			char cname[HOST_NAME_MAX];
1141275970Scy			if (!req->put_cname_in_ptr || *req->put_cname_in_ptr) {
1142275970Scy				j += datalength; continue;
1143275970Scy			}
1144275970Scy			if (name_parse(packet, length, &j, cname,
1145275970Scy				sizeof(cname))<0)
1146275970Scy				goto err;
1147275970Scy			*req->put_cname_in_ptr = mm_strdup(cname);
1148275970Scy		} else if (type == TYPE_AAAA && class == CLASS_INET) {
1149275970Scy			int addrcount, addrtocopy;
1150275970Scy			if (req->request_type != TYPE_AAAA) {
1151275970Scy				j += datalength; continue;
1152275970Scy			}
1153275970Scy			if ((datalength & 15) != 0) /* not an even number of AAAAs. */
1154275970Scy				goto err;
1155275970Scy			addrcount = datalength >> 4;  /* each address is 16 bytes long */
1156275970Scy			addrtocopy = MIN(MAX_V6_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
1157275970Scy			ttl_r = MIN(ttl_r, ttl);
1158275970Scy
1159275970Scy			/* we only bother with the first four addresses. */
1160275970Scy			if (j + 16*addrtocopy > length) goto err;
1161275970Scy			memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
1162275970Scy				   packet + j, 16*addrtocopy);
1163275970Scy			reply.data.aaaa.addrcount += addrtocopy;
1164275970Scy			j += 16*addrtocopy;
1165275970Scy			reply.have_answer = 1;
1166275970Scy			if (reply.data.aaaa.addrcount == MAX_V6_ADDRS) break;
1167275970Scy		} else {
1168275970Scy			/* skip over any other type of resource */
1169275970Scy			j += datalength;
1170275970Scy		}
1171275970Scy	}
1172275970Scy
1173275970Scy	if (!reply.have_answer) {
1174275970Scy		for (i = 0; i < authority; ++i) {
1175275970Scy			u16 type, class;
1176275970Scy			SKIP_NAME;
1177275970Scy			GET16(type);
1178275970Scy			GET16(class);
1179275970Scy			GET32(ttl);
1180275970Scy			GET16(datalength);
1181275970Scy			if (type == TYPE_SOA && class == CLASS_INET) {
1182275970Scy				u32 serial, refresh, retry, expire, minimum;
1183275970Scy				SKIP_NAME;
1184275970Scy				SKIP_NAME;
1185275970Scy				GET32(serial);
1186275970Scy				GET32(refresh);
1187275970Scy				GET32(retry);
1188275970Scy				GET32(expire);
1189275970Scy				GET32(minimum);
1190275970Scy				(void)expire;
1191275970Scy				(void)retry;
1192275970Scy				(void)refresh;
1193275970Scy				(void)serial;
1194275970Scy				ttl_r = MIN(ttl_r, ttl);
1195275970Scy				ttl_r = MIN(ttl_r, minimum);
1196275970Scy			} else {
1197275970Scy				/* skip over any other type of resource */
1198275970Scy				j += datalength;
1199275970Scy			}
1200275970Scy		}
1201275970Scy	}
1202275970Scy
1203275970Scy	if (ttl_r == 0xffffffff)
1204275970Scy		ttl_r = 0;
1205275970Scy
1206275970Scy	reply_handle(req, flags, ttl_r, &reply);
1207275970Scy	return 0;
1208275970Scy err:
1209275970Scy	if (req)
1210275970Scy		reply_handle(req, flags, 0, NULL);
1211275970Scy	return -1;
1212275970Scy}
1213275970Scy
1214275970Scy/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
1215275970Scy/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
1216275970Scy/* callback. */
1217275970Scystatic int
1218275970Scyrequest_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, ev_socklen_t addrlen)
1219275970Scy{
1220275970Scy	int j = 0;	/* index into packet */
1221275970Scy	u16 t_;	 /* used by the macros */
1222275970Scy	char tmp_name[256]; /* used by the macros */
1223275970Scy
1224275970Scy	int i;
1225275970Scy	u16 trans_id, flags, questions, answers, authority, additional;
1226275970Scy	struct server_request *server_req = NULL;
1227275970Scy
1228275970Scy	ASSERT_LOCKED(port);
1229275970Scy
1230275970Scy	/* Get the header fields */
1231275970Scy	GET16(trans_id);
1232275970Scy	GET16(flags);
1233275970Scy	GET16(questions);
1234275970Scy	GET16(answers);
1235275970Scy	GET16(authority);
1236275970Scy	GET16(additional);
1237275970Scy	(void)answers;
1238275970Scy	(void)additional;
1239275970Scy	(void)authority;
1240275970Scy
1241275970Scy	if (flags & 0x8000) return -1; /* Must not be an answer. */
1242275970Scy	flags &= 0x0110; /* Only RD and CD get preserved. */
1243275970Scy
1244275970Scy	server_req = mm_malloc(sizeof(struct server_request));
1245275970Scy	if (server_req == NULL) return -1;
1246275970Scy	memset(server_req, 0, sizeof(struct server_request));
1247275970Scy
1248275970Scy	server_req->trans_id = trans_id;
1249275970Scy	memcpy(&server_req->addr, addr, addrlen);
1250275970Scy	server_req->addrlen = addrlen;
1251275970Scy
1252275970Scy	server_req->base.flags = flags;
1253275970Scy	server_req->base.nquestions = 0;
1254275970Scy	server_req->base.questions = mm_calloc(sizeof(struct evdns_server_question *), questions);
1255275970Scy	if (server_req->base.questions == NULL)
1256275970Scy		goto err;
1257275970Scy
1258275970Scy	for (i = 0; i < questions; ++i) {
1259275970Scy		u16 type, class;
1260275970Scy		struct evdns_server_question *q;
1261275970Scy		int namelen;
1262275970Scy		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
1263275970Scy			goto err;
1264275970Scy		GET16(type);
1265275970Scy		GET16(class);
1266275970Scy		namelen = (int)strlen(tmp_name);
1267275970Scy		q = mm_malloc(sizeof(struct evdns_server_question) + namelen);
1268275970Scy		if (!q)
1269275970Scy			goto err;
1270275970Scy		q->type = type;
1271275970Scy		q->dns_question_class = class;
1272275970Scy		memcpy(q->name, tmp_name, namelen+1);
1273275970Scy		server_req->base.questions[server_req->base.nquestions++] = q;
1274275970Scy	}
1275275970Scy
1276275970Scy	/* Ignore answers, authority, and additional. */
1277275970Scy
1278275970Scy	server_req->port = port;
1279275970Scy	port->refcnt++;
1280275970Scy
1281275970Scy	/* Only standard queries are supported. */
1282275970Scy	if (flags & 0x7800) {
1283275970Scy		evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
1284275970Scy		return -1;
1285275970Scy	}
1286275970Scy
1287275970Scy	port->user_callback(&(server_req->base), port->user_data);
1288275970Scy
1289275970Scy	return 0;
1290275970Scyerr:
1291275970Scy	if (server_req) {
1292275970Scy		if (server_req->base.questions) {
1293275970Scy			for (i = 0; i < server_req->base.nquestions; ++i)
1294275970Scy				mm_free(server_req->base.questions[i]);
1295275970Scy			mm_free(server_req->base.questions);
1296275970Scy		}
1297275970Scy		mm_free(server_req);
1298275970Scy	}
1299275970Scy	return -1;
1300275970Scy
1301275970Scy#undef SKIP_NAME
1302275970Scy#undef GET32
1303275970Scy#undef GET16
1304275970Scy#undef GET8
1305275970Scy}
1306275970Scy
1307275970Scy
1308275970Scyvoid
1309275970Scyevdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
1310275970Scy{
1311275970Scy}
1312275970Scy
1313275970Scyvoid
1314275970Scyevdns_set_random_bytes_fn(void (*fn)(char *, size_t))
1315275970Scy{
1316275970Scy}
1317275970Scy
1318275970Scy/* Try to choose a strong transaction id which isn't already in flight */
1319275970Scystatic u16
1320275970Scytransaction_id_pick(struct evdns_base *base) {
1321275970Scy	ASSERT_LOCKED(base);
1322275970Scy	for (;;) {
1323275970Scy		u16 trans_id;
1324275970Scy		evutil_secure_rng_get_bytes(&trans_id, sizeof(trans_id));
1325275970Scy
1326275970Scy		if (trans_id == 0xffff) continue;
1327275970Scy		/* now check to see if that id is already inflight */
1328275970Scy		if (request_find_from_trans_id(base, trans_id) == NULL)
1329275970Scy			return trans_id;
1330275970Scy	}
1331275970Scy}
1332275970Scy
1333275970Scy/* choose a namesever to use. This function will try to ignore */
1334275970Scy/* nameservers which we think are down and load balance across the rest */
1335275970Scy/* by updating the server_head global each time. */
1336275970Scystatic struct nameserver *
1337275970Scynameserver_pick(struct evdns_base *base) {
1338275970Scy	struct nameserver *started_at = base->server_head, *picked;
1339275970Scy	ASSERT_LOCKED(base);
1340275970Scy	if (!base->server_head) return NULL;
1341275970Scy
1342275970Scy	/* if we don't have any good nameservers then there's no */
1343275970Scy	/* point in trying to find one. */
1344275970Scy	if (!base->global_good_nameservers) {
1345275970Scy		base->server_head = base->server_head->next;
1346275970Scy		return base->server_head;
1347275970Scy	}
1348275970Scy
1349275970Scy	/* remember that nameservers are in a circular list */
1350275970Scy	for (;;) {
1351275970Scy		if (base->server_head->state) {
1352275970Scy			/* we think this server is currently good */
1353275970Scy			picked = base->server_head;
1354275970Scy			base->server_head = base->server_head->next;
1355275970Scy			return picked;
1356275970Scy		}
1357275970Scy
1358275970Scy		base->server_head = base->server_head->next;
1359275970Scy		if (base->server_head == started_at) {
1360275970Scy			/* all the nameservers seem to be down */
1361275970Scy			/* so we just return this one and hope for the */
1362275970Scy			/* best */
1363275970Scy			EVUTIL_ASSERT(base->global_good_nameservers == 0);
1364275970Scy			picked = base->server_head;
1365275970Scy			base->server_head = base->server_head->next;
1366275970Scy			return picked;
1367275970Scy		}
1368275970Scy	}
1369275970Scy}
1370275970Scy
1371275970Scy/* this is called when a namesever socket is ready for reading */
1372275970Scystatic void
1373275970Scynameserver_read(struct nameserver *ns) {
1374275970Scy	struct sockaddr_storage ss;
1375275970Scy	ev_socklen_t addrlen = sizeof(ss);
1376275970Scy	u8 packet[1500];
1377275970Scy	char addrbuf[128];
1378275970Scy	ASSERT_LOCKED(ns->base);
1379275970Scy
1380275970Scy	for (;;) {
1381275970Scy		const int r = recvfrom(ns->socket, (void*)packet,
1382275970Scy		    sizeof(packet), 0,
1383275970Scy		    (struct sockaddr*)&ss, &addrlen);
1384275970Scy		if (r < 0) {
1385275970Scy			int err = evutil_socket_geterror(ns->socket);
1386275970Scy			if (EVUTIL_ERR_RW_RETRIABLE(err))
1387275970Scy				return;
1388275970Scy			nameserver_failed(ns,
1389275970Scy			    evutil_socket_error_to_string(err));
1390275970Scy			return;
1391275970Scy		}
1392275970Scy		if (evutil_sockaddr_cmp((struct sockaddr*)&ss,
1393275970Scy			(struct sockaddr*)&ns->address, 0)) {
1394275970Scy			log(EVDNS_LOG_WARN, "Address mismatch on received "
1395275970Scy			    "DNS packet.  Apparent source was %s",
1396275970Scy			    evutil_format_sockaddr_port_(
1397275970Scy				    (struct sockaddr *)&ss,
1398275970Scy				    addrbuf, sizeof(addrbuf)));
1399275970Scy			return;
1400275970Scy		}
1401275970Scy
1402275970Scy		ns->timedout = 0;
1403275970Scy		reply_parse(ns->base, packet, r);
1404275970Scy	}
1405275970Scy}
1406275970Scy
1407275970Scy/* Read a packet from a DNS client on a server port s, parse it, and */
1408275970Scy/* act accordingly. */
1409275970Scystatic void
1410275970Scyserver_port_read(struct evdns_server_port *s) {
1411275970Scy	u8 packet[1500];
1412275970Scy	struct sockaddr_storage addr;
1413275970Scy	ev_socklen_t addrlen;
1414275970Scy	int r;
1415275970Scy	ASSERT_LOCKED(s);
1416275970Scy
1417275970Scy	for (;;) {
1418275970Scy		addrlen = sizeof(struct sockaddr_storage);
1419275970Scy		r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0,
1420275970Scy					 (struct sockaddr*) &addr, &addrlen);
1421275970Scy		if (r < 0) {
1422275970Scy			int err = evutil_socket_geterror(s->socket);
1423275970Scy			if (EVUTIL_ERR_RW_RETRIABLE(err))
1424275970Scy				return;
1425275970Scy			log(EVDNS_LOG_WARN,
1426275970Scy			    "Error %s (%d) while reading request.",
1427275970Scy			    evutil_socket_error_to_string(err), err);
1428275970Scy			return;
1429275970Scy		}
1430275970Scy		request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
1431275970Scy	}
1432275970Scy}
1433275970Scy
1434275970Scy/* Try to write all pending replies on a given DNS server port. */
1435275970Scystatic void
1436275970Scyserver_port_flush(struct evdns_server_port *port)
1437275970Scy{
1438275970Scy	struct server_request *req = port->pending_replies;
1439275970Scy	ASSERT_LOCKED(port);
1440275970Scy	while (req) {
1441275970Scy		int r = sendto(port->socket, req->response, (int)req->response_len, 0,
1442275970Scy			   (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
1443275970Scy		if (r < 0) {
1444275970Scy			int err = evutil_socket_geterror(port->socket);
1445275970Scy			if (EVUTIL_ERR_RW_RETRIABLE(err))
1446275970Scy				return;
1447275970Scy			log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", evutil_socket_error_to_string(err), err);
1448275970Scy		}
1449275970Scy		if (server_request_free(req)) {
1450275970Scy			/* we released the last reference to req->port. */
1451275970Scy			return;
1452275970Scy		} else {
1453275970Scy			EVUTIL_ASSERT(req != port->pending_replies);
1454275970Scy			req = port->pending_replies;
1455275970Scy		}
1456275970Scy	}
1457275970Scy
1458275970Scy	/* We have no more pending requests; stop listening for 'writeable' events. */
1459275970Scy	(void) event_del(&port->event);
1460275970Scy	event_assign(&port->event, port->event_base,
1461275970Scy				 port->socket, EV_READ | EV_PERSIST,
1462275970Scy				 server_port_ready_callback, port);
1463275970Scy
1464275970Scy	if (event_add(&port->event, NULL) < 0) {
1465275970Scy		log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
1466275970Scy		/* ???? Do more? */
1467275970Scy	}
1468275970Scy}
1469275970Scy
1470275970Scy/* set if we are waiting for the ability to write to this server. */
1471275970Scy/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
1472275970Scy/* we stop these events. */
1473275970Scystatic void
1474275970Scynameserver_write_waiting(struct nameserver *ns, char waiting) {
1475275970Scy	ASSERT_LOCKED(ns->base);
1476275970Scy	if (ns->write_waiting == waiting) return;
1477275970Scy
1478275970Scy	ns->write_waiting = waiting;
1479275970Scy	(void) event_del(&ns->event);
1480275970Scy	event_assign(&ns->event, ns->base->event_base,
1481275970Scy	    ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
1482275970Scy	    nameserver_ready_callback, ns);
1483275970Scy	if (event_add(&ns->event, NULL) < 0) {
1484275970Scy		char addrbuf[128];
1485275970Scy		log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
1486275970Scy		    evutil_format_sockaddr_port_(
1487275970Scy			    (struct sockaddr *)&ns->address,
1488275970Scy			    addrbuf, sizeof(addrbuf)));
1489275970Scy		/* ???? Do more? */
1490275970Scy	}
1491275970Scy}
1492275970Scy
1493275970Scy/* a callback function. Called by libevent when the kernel says that */
1494275970Scy/* a nameserver socket is ready for writing or reading */
1495275970Scystatic void
1496275970Scynameserver_ready_callback(evutil_socket_t fd, short events, void *arg) {
1497275970Scy	struct nameserver *ns = (struct nameserver *) arg;
1498275970Scy	(void)fd;
1499275970Scy
1500275970Scy	EVDNS_LOCK(ns->base);
1501275970Scy	if (events & EV_WRITE) {
1502275970Scy		ns->choked = 0;
1503275970Scy		if (!evdns_transmit(ns->base)) {
1504275970Scy			nameserver_write_waiting(ns, 0);
1505275970Scy		}
1506275970Scy	}
1507275970Scy	if (events & EV_READ) {
1508275970Scy		nameserver_read(ns);
1509275970Scy	}
1510275970Scy	EVDNS_UNLOCK(ns->base);
1511275970Scy}
1512275970Scy
1513275970Scy/* a callback function. Called by libevent when the kernel says that */
1514275970Scy/* a server socket is ready for writing or reading. */
1515275970Scystatic void
1516275970Scyserver_port_ready_callback(evutil_socket_t fd, short events, void *arg) {
1517275970Scy	struct evdns_server_port *port = (struct evdns_server_port *) arg;
1518275970Scy	(void) fd;
1519275970Scy
1520275970Scy	EVDNS_LOCK(port);
1521275970Scy	if (events & EV_WRITE) {
1522275970Scy		port->choked = 0;
1523275970Scy		server_port_flush(port);
1524275970Scy	}
1525275970Scy	if (events & EV_READ) {
1526275970Scy		server_port_read(port);
1527275970Scy	}
1528275970Scy	EVDNS_UNLOCK(port);
1529275970Scy}
1530275970Scy
1531275970Scy/* This is an inefficient representation; only use it via the dnslabel_table_*
1532275970Scy * functions, so that is can be safely replaced with something smarter later. */
1533275970Scy#define MAX_LABELS 128
1534275970Scy/* Structures used to implement name compression */
1535275970Scystruct dnslabel_entry { char *v; off_t pos; };
1536275970Scystruct dnslabel_table {
1537275970Scy	int n_labels; /* number of current entries */
1538275970Scy	/* map from name to position in message */
1539275970Scy	struct dnslabel_entry labels[MAX_LABELS];
1540275970Scy};
1541275970Scy
1542275970Scy/* Initialize dnslabel_table. */
1543275970Scystatic void
1544275970Scydnslabel_table_init(struct dnslabel_table *table)
1545275970Scy{
1546275970Scy	table->n_labels = 0;
1547275970Scy}
1548275970Scy
1549275970Scy/* Free all storage held by table, but not the table itself. */
1550275970Scystatic void
1551275970Scydnslabel_clear(struct dnslabel_table *table)
1552275970Scy{
1553275970Scy	int i;
1554275970Scy	for (i = 0; i < table->n_labels; ++i)
1555275970Scy		mm_free(table->labels[i].v);
1556275970Scy	table->n_labels = 0;
1557275970Scy}
1558275970Scy
1559275970Scy/* return the position of the label in the current message, or -1 if the label */
1560275970Scy/* hasn't been used yet. */
1561275970Scystatic int
1562275970Scydnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
1563275970Scy{
1564275970Scy	int i;
1565275970Scy	for (i = 0; i < table->n_labels; ++i) {
1566275970Scy		if (!strcmp(label, table->labels[i].v))
1567275970Scy			return table->labels[i].pos;
1568275970Scy	}
1569275970Scy	return -1;
1570275970Scy}
1571275970Scy
1572275970Scy/* remember that we've used the label at position pos */
1573275970Scystatic int
1574275970Scydnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
1575275970Scy{
1576275970Scy	char *v;
1577275970Scy	int p;
1578275970Scy	if (table->n_labels == MAX_LABELS)
1579275970Scy		return (-1);
1580275970Scy	v = mm_strdup(label);
1581275970Scy	if (v == NULL)
1582275970Scy		return (-1);
1583275970Scy	p = table->n_labels++;
1584275970Scy	table->labels[p].v = v;
1585275970Scy	table->labels[p].pos = pos;
1586275970Scy
1587275970Scy	return (0);
1588275970Scy}
1589275970Scy
1590275970Scy/* Converts a string to a length-prefixed set of DNS labels, starting */
1591275970Scy/* at buf[j]. name and buf must not overlap. name_len should be the length */
1592275970Scy/* of name.	 table is optional, and is used for compression. */
1593275970Scy/* */
1594275970Scy/* Input: abc.def */
1595275970Scy/* Output: <3>abc<3>def<0> */
1596275970Scy/* */
1597275970Scy/* Returns the first index after the encoded name, or negative on error. */
1598275970Scy/*	 -1	 label was > 63 bytes */
1599275970Scy/*	 -2	 name too long to fit in buffer. */
1600275970Scy/* */
1601275970Scystatic off_t
1602275970Scydnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
1603275970Scy				  const char *name, const size_t name_len,
1604275970Scy				  struct dnslabel_table *table) {
1605275970Scy	const char *end = name + name_len;
1606275970Scy	int ref = 0;
1607275970Scy	u16 t_;
1608275970Scy
1609275970Scy#define APPEND16(x) do {						\
1610275970Scy		if (j + 2 > (off_t)buf_len)				\
1611275970Scy			goto overflow;					\
1612275970Scy		t_ = htons(x);						\
1613275970Scy		memcpy(buf + j, &t_, 2);				\
1614275970Scy		j += 2;							\
1615275970Scy	} while (0)
1616275970Scy#define APPEND32(x) do {						\
1617275970Scy		if (j + 4 > (off_t)buf_len)				\
1618275970Scy			goto overflow;					\
1619275970Scy		t32_ = htonl(x);					\
1620275970Scy		memcpy(buf + j, &t32_, 4);				\
1621275970Scy		j += 4;							\
1622275970Scy	} while (0)
1623275970Scy
1624275970Scy	if (name_len > 255) return -2;
1625275970Scy
1626275970Scy	for (;;) {
1627275970Scy		const char *const start = name;
1628275970Scy		if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
1629275970Scy			APPEND16(ref | 0xc000);
1630275970Scy			return j;
1631275970Scy		}
1632275970Scy		name = strchr(name, '.');
1633275970Scy		if (!name) {
1634275970Scy			const size_t label_len = end - start;
1635275970Scy			if (label_len > 63) return -1;
1636275970Scy			if ((size_t)(j+label_len+1) > buf_len) return -2;
1637275970Scy			if (table) dnslabel_table_add(table, start, j);
1638275970Scy			buf[j++] = (ev_uint8_t)label_len;
1639275970Scy
1640275970Scy			memcpy(buf + j, start, label_len);
1641275970Scy			j += (int) label_len;
1642275970Scy			break;
1643275970Scy		} else {
1644275970Scy			/* append length of the label. */
1645275970Scy			const size_t label_len = name - start;
1646275970Scy			if (label_len > 63) return -1;
1647275970Scy			if ((size_t)(j+label_len+1) > buf_len) return -2;
1648275970Scy			if (table) dnslabel_table_add(table, start, j);
1649275970Scy			buf[j++] = (ev_uint8_t)label_len;
1650275970Scy
1651275970Scy			memcpy(buf + j, start, label_len);
1652275970Scy			j += (int) label_len;
1653275970Scy			/* hop over the '.' */
1654275970Scy			name++;
1655275970Scy		}
1656275970Scy	}
1657275970Scy
1658275970Scy	/* the labels must be terminated by a 0. */
1659275970Scy	/* It's possible that the name ended in a . */
1660275970Scy	/* in which case the zero is already there */
1661275970Scy	if (!j || buf[j-1]) buf[j++] = 0;
1662275970Scy	return j;
1663275970Scy overflow:
1664275970Scy	return (-2);
1665275970Scy}
1666275970Scy
1667275970Scy/* Finds the length of a dns request for a DNS name of the given */
1668275970Scy/* length. The actual request may be smaller than the value returned */
1669275970Scy/* here */
1670275970Scystatic size_t
1671275970Scyevdns_request_len(const size_t name_len) {
1672275970Scy	return 96 + /* length of the DNS standard header */
1673275970Scy		name_len + 2 +
1674275970Scy		4;  /* space for the resource type */
1675275970Scy}
1676275970Scy
1677275970Scy/* build a dns request packet into buf. buf should be at least as long */
1678275970Scy/* as evdns_request_len told you it should be. */
1679275970Scy/* */
1680275970Scy/* Returns the amount of space used. Negative on error. */
1681275970Scystatic int
1682275970Scyevdns_request_data_build(const char *const name, const size_t name_len,
1683275970Scy    const u16 trans_id, const u16 type, const u16 class,
1684275970Scy    u8 *const buf, size_t buf_len) {
1685275970Scy	off_t j = 0;  /* current offset into buf */
1686275970Scy	u16 t_;	 /* used by the macros */
1687275970Scy
1688275970Scy	APPEND16(trans_id);
1689275970Scy	APPEND16(0x0100);  /* standard query, recusion needed */
1690275970Scy	APPEND16(1);  /* one question */
1691275970Scy	APPEND16(0);  /* no answers */
1692275970Scy	APPEND16(0);  /* no authority */
1693275970Scy	APPEND16(0);  /* no additional */
1694275970Scy
1695275970Scy	j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
1696275970Scy	if (j < 0) {
1697275970Scy		return (int)j;
1698275970Scy	}
1699275970Scy
1700275970Scy	APPEND16(type);
1701275970Scy	APPEND16(class);
1702275970Scy
1703275970Scy	return (int)j;
1704275970Scy overflow:
1705275970Scy	return (-1);
1706275970Scy}
1707275970Scy
1708275970Scy/* exported function */
1709275970Scystruct evdns_server_port *
1710275970Scyevdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
1711275970Scy{
1712275970Scy	struct evdns_server_port *port;
1713275970Scy	if (flags)
1714275970Scy		return NULL; /* flags not yet implemented */
1715275970Scy	if (!(port = mm_malloc(sizeof(struct evdns_server_port))))
1716275970Scy		return NULL;
1717275970Scy	memset(port, 0, sizeof(struct evdns_server_port));
1718275970Scy
1719275970Scy
1720275970Scy	port->socket = socket;
1721275970Scy	port->refcnt = 1;
1722275970Scy	port->choked = 0;
1723275970Scy	port->closing = 0;
1724275970Scy	port->user_callback = cb;
1725275970Scy	port->user_data = user_data;
1726275970Scy	port->pending_replies = NULL;
1727275970Scy	port->event_base = base;
1728275970Scy
1729275970Scy	event_assign(&port->event, port->event_base,
1730275970Scy				 port->socket, EV_READ | EV_PERSIST,
1731275970Scy				 server_port_ready_callback, port);
1732275970Scy	if (event_add(&port->event, NULL) < 0) {
1733275970Scy		mm_free(port);
1734275970Scy		return NULL;
1735275970Scy	}
1736275970Scy	EVTHREAD_ALLOC_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
1737275970Scy	return port;
1738275970Scy}
1739275970Scy
1740275970Scystruct evdns_server_port *
1741275970Scyevdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
1742275970Scy{
1743275970Scy	return evdns_add_server_port_with_base(NULL, socket, flags, cb, user_data);
1744275970Scy}
1745275970Scy
1746275970Scy/* exported function */
1747275970Scyvoid
1748275970Scyevdns_close_server_port(struct evdns_server_port *port)
1749275970Scy{
1750275970Scy	EVDNS_LOCK(port);
1751275970Scy	if (--port->refcnt == 0) {
1752275970Scy		EVDNS_UNLOCK(port);
1753275970Scy		server_port_free(port);
1754275970Scy	} else {
1755275970Scy		port->closing = 1;
1756275970Scy	}
1757275970Scy}
1758275970Scy
1759275970Scy/* exported function */
1760275970Scyint
1761275970Scyevdns_server_request_add_reply(struct evdns_server_request *req_, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data)
1762275970Scy{
1763275970Scy	struct server_request *req = TO_SERVER_REQUEST(req_);
1764275970Scy	struct server_reply_item **itemp, *item;
1765275970Scy	int *countp;
1766275970Scy	int result = -1;
1767275970Scy
1768275970Scy	EVDNS_LOCK(req->port);
1769275970Scy	if (req->response) /* have we already answered? */
1770275970Scy		goto done;
1771275970Scy
1772275970Scy	switch (section) {
1773275970Scy	case EVDNS_ANSWER_SECTION:
1774275970Scy		itemp = &req->answer;
1775275970Scy		countp = &req->n_answer;
1776275970Scy		break;
1777275970Scy	case EVDNS_AUTHORITY_SECTION:
1778275970Scy		itemp = &req->authority;
1779275970Scy		countp = &req->n_authority;
1780275970Scy		break;
1781275970Scy	case EVDNS_ADDITIONAL_SECTION:
1782275970Scy		itemp = &req->additional;
1783275970Scy		countp = &req->n_additional;
1784275970Scy		break;
1785275970Scy	default:
1786275970Scy		goto done;
1787275970Scy	}
1788275970Scy	while (*itemp) {
1789275970Scy		itemp = &((*itemp)->next);
1790275970Scy	}
1791275970Scy	item = mm_malloc(sizeof(struct server_reply_item));
1792275970Scy	if (!item)
1793275970Scy		goto done;
1794275970Scy	item->next = NULL;
1795275970Scy	if (!(item->name = mm_strdup(name))) {
1796275970Scy		mm_free(item);
1797275970Scy		goto done;
1798275970Scy	}
1799275970Scy	item->type = type;
1800275970Scy	item->dns_question_class = class;
1801275970Scy	item->ttl = ttl;
1802275970Scy	item->is_name = is_name != 0;
1803275970Scy	item->datalen = 0;
1804275970Scy	item->data = NULL;
1805275970Scy	if (data) {
1806275970Scy		if (item->is_name) {
1807275970Scy			if (!(item->data = mm_strdup(data))) {
1808275970Scy				mm_free(item->name);
1809275970Scy				mm_free(item);
1810275970Scy				goto done;
1811275970Scy			}
1812275970Scy			item->datalen = (u16)-1;
1813275970Scy		} else {
1814275970Scy			if (!(item->data = mm_malloc(datalen))) {
1815275970Scy				mm_free(item->name);
1816275970Scy				mm_free(item);
1817275970Scy				goto done;
1818275970Scy			}
1819275970Scy			item->datalen = datalen;
1820275970Scy			memcpy(item->data, data, datalen);
1821275970Scy		}
1822275970Scy	}
1823275970Scy
1824275970Scy	*itemp = item;
1825275970Scy	++(*countp);
1826275970Scy	result = 0;
1827275970Scydone:
1828275970Scy	EVDNS_UNLOCK(req->port);
1829275970Scy	return result;
1830275970Scy}
1831275970Scy
1832275970Scy/* exported function */
1833275970Scyint
1834275970Scyevdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
1835275970Scy{
1836275970Scy	return evdns_server_request_add_reply(
1837275970Scy		  req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
1838275970Scy		  ttl, n*4, 0, addrs);
1839275970Scy}
1840275970Scy
1841275970Scy/* exported function */
1842275970Scyint
1843275970Scyevdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
1844275970Scy{
1845275970Scy	return evdns_server_request_add_reply(
1846275970Scy		  req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
1847275970Scy		  ttl, n*16, 0, addrs);
1848275970Scy}
1849275970Scy
1850275970Scy/* exported function */
1851275970Scyint
1852275970Scyevdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
1853275970Scy{
1854275970Scy	u32 a;
1855275970Scy	char buf[32];
1856275970Scy	if (in && inaddr_name)
1857275970Scy		return -1;
1858275970Scy	else if (!in && !inaddr_name)
1859275970Scy		return -1;
1860275970Scy	if (in) {
1861275970Scy		a = ntohl(in->s_addr);
1862275970Scy		evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
1863275970Scy				(int)(u8)((a	)&0xff),
1864275970Scy				(int)(u8)((a>>8 )&0xff),
1865275970Scy				(int)(u8)((a>>16)&0xff),
1866275970Scy				(int)(u8)((a>>24)&0xff));
1867275970Scy		inaddr_name = buf;
1868275970Scy	}
1869275970Scy	return evdns_server_request_add_reply(
1870275970Scy		  req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
1871275970Scy		  ttl, -1, 1, hostname);
1872275970Scy}
1873275970Scy
1874275970Scy/* exported function */
1875275970Scyint
1876275970Scyevdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
1877275970Scy{
1878275970Scy	return evdns_server_request_add_reply(
1879275970Scy		  req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
1880275970Scy		  ttl, -1, 1, cname);
1881275970Scy}
1882275970Scy
1883275970Scy/* exported function */
1884275970Scyvoid
1885275970Scyevdns_server_request_set_flags(struct evdns_server_request *exreq, int flags)
1886275970Scy{
1887275970Scy	struct server_request *req = TO_SERVER_REQUEST(exreq);
1888275970Scy	req->base.flags &= ~(EVDNS_FLAGS_AA|EVDNS_FLAGS_RD);
1889275970Scy	req->base.flags |= flags;
1890275970Scy}
1891275970Scy
1892275970Scystatic int
1893275970Scyevdns_server_request_format_response(struct server_request *req, int err)
1894275970Scy{
1895275970Scy	unsigned char buf[1500];
1896275970Scy	size_t buf_len = sizeof(buf);
1897275970Scy	off_t j = 0, r;
1898275970Scy	u16 t_;
1899275970Scy	u32 t32_;
1900275970Scy	int i;
1901275970Scy	u16 flags;
1902275970Scy	struct dnslabel_table table;
1903275970Scy
1904275970Scy	if (err < 0 || err > 15) return -1;
1905275970Scy
1906275970Scy	/* Set response bit and error code; copy OPCODE and RD fields from
1907275970Scy	 * question; copy RA and AA if set by caller. */
1908275970Scy	flags = req->base.flags;
1909275970Scy	flags |= (0x8000 | err);
1910275970Scy
1911275970Scy	dnslabel_table_init(&table);
1912275970Scy	APPEND16(req->trans_id);
1913275970Scy	APPEND16(flags);
1914275970Scy	APPEND16(req->base.nquestions);
1915275970Scy	APPEND16(req->n_answer);
1916275970Scy	APPEND16(req->n_authority);
1917275970Scy	APPEND16(req->n_additional);
1918275970Scy
1919275970Scy	/* Add questions. */
1920275970Scy	for (i=0; i < req->base.nquestions; ++i) {
1921275970Scy		const char *s = req->base.questions[i]->name;
1922275970Scy		j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
1923275970Scy		if (j < 0) {
1924275970Scy			dnslabel_clear(&table);
1925275970Scy			return (int) j;
1926275970Scy		}
1927275970Scy		APPEND16(req->base.questions[i]->type);
1928275970Scy		APPEND16(req->base.questions[i]->dns_question_class);
1929275970Scy	}
1930275970Scy
1931275970Scy	/* Add answer, authority, and additional sections. */
1932275970Scy	for (i=0; i<3; ++i) {
1933275970Scy		struct server_reply_item *item;
1934275970Scy		if (i==0)
1935275970Scy			item = req->answer;
1936275970Scy		else if (i==1)
1937275970Scy			item = req->authority;
1938275970Scy		else
1939275970Scy			item = req->additional;
1940275970Scy		while (item) {
1941275970Scy			r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
1942275970Scy			if (r < 0)
1943275970Scy				goto overflow;
1944275970Scy			j = r;
1945275970Scy
1946275970Scy			APPEND16(item->type);
1947275970Scy			APPEND16(item->dns_question_class);
1948275970Scy			APPEND32(item->ttl);
1949275970Scy			if (item->is_name) {
1950275970Scy				off_t len_idx = j, name_start;
1951275970Scy				j += 2;
1952275970Scy				name_start = j;
1953275970Scy				r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
1954275970Scy				if (r < 0)
1955275970Scy					goto overflow;
1956275970Scy				j = r;
1957275970Scy				t_ = htons( (short) (j-name_start) );
1958275970Scy				memcpy(buf+len_idx, &t_, 2);
1959275970Scy			} else {
1960275970Scy				APPEND16(item->datalen);
1961275970Scy				if (j+item->datalen > (off_t)buf_len)
1962275970Scy					goto overflow;
1963275970Scy				memcpy(buf+j, item->data, item->datalen);
1964275970Scy				j += item->datalen;
1965275970Scy			}
1966275970Scy			item = item->next;
1967275970Scy		}
1968275970Scy	}
1969275970Scy
1970275970Scy	if (j > 512) {
1971275970Scyoverflow:
1972275970Scy		j = 512;
1973275970Scy		buf[2] |= 0x02; /* set the truncated bit. */
1974275970Scy	}
1975275970Scy
1976275970Scy	req->response_len = j;
1977275970Scy
1978275970Scy	if (!(req->response = mm_malloc(req->response_len))) {
1979275970Scy		server_request_free_answers(req);
1980275970Scy		dnslabel_clear(&table);
1981275970Scy		return (-1);
1982275970Scy	}
1983275970Scy	memcpy(req->response, buf, req->response_len);
1984275970Scy	server_request_free_answers(req);
1985275970Scy	dnslabel_clear(&table);
1986275970Scy	return (0);
1987275970Scy}
1988275970Scy
1989275970Scy/* exported function */
1990275970Scyint
1991275970Scyevdns_server_request_respond(struct evdns_server_request *req_, int err)
1992275970Scy{
1993275970Scy	struct server_request *req = TO_SERVER_REQUEST(req_);
1994275970Scy	struct evdns_server_port *port = req->port;
1995275970Scy	int r = -1;
1996275970Scy
1997275970Scy	EVDNS_LOCK(port);
1998275970Scy	if (!req->response) {
1999275970Scy		if ((r = evdns_server_request_format_response(req, err))<0)
2000275970Scy			goto done;
2001275970Scy	}
2002275970Scy
2003275970Scy	r = sendto(port->socket, req->response, (int)req->response_len, 0,
2004275970Scy			   (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
2005275970Scy	if (r<0) {
2006275970Scy		int sock_err = evutil_socket_geterror(port->socket);
2007275970Scy		if (EVUTIL_ERR_RW_RETRIABLE(sock_err))
2008275970Scy			goto done;
2009275970Scy
2010275970Scy		if (port->pending_replies) {
2011275970Scy			req->prev_pending = port->pending_replies->prev_pending;
2012275970Scy			req->next_pending = port->pending_replies;
2013275970Scy			req->prev_pending->next_pending =
2014275970Scy				req->next_pending->prev_pending = req;
2015275970Scy		} else {
2016275970Scy			req->prev_pending = req->next_pending = req;
2017275970Scy			port->pending_replies = req;
2018275970Scy			port->choked = 1;
2019275970Scy
2020275970Scy			(void) event_del(&port->event);
2021275970Scy			event_assign(&port->event, port->event_base, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
2022275970Scy
2023275970Scy			if (event_add(&port->event, NULL) < 0) {
2024275970Scy				log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
2025275970Scy			}
2026275970Scy
2027275970Scy		}
2028275970Scy
2029275970Scy		r = 1;
2030275970Scy		goto done;
2031275970Scy	}
2032275970Scy	if (server_request_free(req)) {
2033275970Scy		r = 0;
2034275970Scy		goto done;
2035275970Scy	}
2036275970Scy
2037275970Scy	if (port->pending_replies)
2038275970Scy		server_port_flush(port);
2039275970Scy
2040275970Scy	r = 0;
2041275970Scydone:
2042275970Scy	EVDNS_UNLOCK(port);
2043275970Scy	return r;
2044275970Scy}
2045275970Scy
2046275970Scy/* Free all storage held by RRs in req. */
2047275970Scystatic void
2048275970Scyserver_request_free_answers(struct server_request *req)
2049275970Scy{
2050275970Scy	struct server_reply_item *victim, *next, **list;
2051275970Scy	int i;
2052275970Scy	for (i = 0; i < 3; ++i) {
2053275970Scy		if (i==0)
2054275970Scy			list = &req->answer;
2055275970Scy		else if (i==1)
2056275970Scy			list = &req->authority;
2057275970Scy		else
2058275970Scy			list = &req->additional;
2059275970Scy
2060275970Scy		victim = *list;
2061275970Scy		while (victim) {
2062275970Scy			next = victim->next;
2063275970Scy			mm_free(victim->name);
2064275970Scy			if (victim->data)
2065275970Scy				mm_free(victim->data);
2066275970Scy			mm_free(victim);
2067275970Scy			victim = next;
2068275970Scy		}
2069275970Scy		*list = NULL;
2070275970Scy	}
2071275970Scy}
2072275970Scy
2073275970Scy/* Free all storage held by req, and remove links to it. */
2074275970Scy/* return true iff we just wound up freeing the server_port. */
2075275970Scystatic int
2076275970Scyserver_request_free(struct server_request *req)
2077275970Scy{
2078275970Scy	int i, rc=1, lock=0;
2079275970Scy	if (req->base.questions) {
2080275970Scy		for (i = 0; i < req->base.nquestions; ++i)
2081275970Scy			mm_free(req->base.questions[i]);
2082275970Scy		mm_free(req->base.questions);
2083275970Scy	}
2084275970Scy
2085275970Scy	if (req->port) {
2086275970Scy		EVDNS_LOCK(req->port);
2087275970Scy		lock=1;
2088275970Scy		if (req->port->pending_replies == req) {
2089275970Scy			if (req->next_pending && req->next_pending != req)
2090275970Scy				req->port->pending_replies = req->next_pending;
2091275970Scy			else
2092275970Scy				req->port->pending_replies = NULL;
2093275970Scy		}
2094275970Scy		rc = --req->port->refcnt;
2095275970Scy	}
2096275970Scy
2097275970Scy	if (req->response) {
2098275970Scy		mm_free(req->response);
2099275970Scy	}
2100275970Scy
2101275970Scy	server_request_free_answers(req);
2102275970Scy
2103275970Scy	if (req->next_pending && req->next_pending != req) {
2104275970Scy		req->next_pending->prev_pending = req->prev_pending;
2105275970Scy		req->prev_pending->next_pending = req->next_pending;
2106275970Scy	}
2107275970Scy
2108275970Scy	if (rc == 0) {
2109275970Scy		EVDNS_UNLOCK(req->port); /* ????? nickm */
2110275970Scy		server_port_free(req->port);
2111275970Scy		mm_free(req);
2112275970Scy		return (1);
2113275970Scy	}
2114275970Scy	if (lock)
2115275970Scy		EVDNS_UNLOCK(req->port);
2116275970Scy	mm_free(req);
2117275970Scy	return (0);
2118275970Scy}
2119275970Scy
2120275970Scy/* Free all storage held by an evdns_server_port.  Only called when  */
2121275970Scystatic void
2122275970Scyserver_port_free(struct evdns_server_port *port)
2123275970Scy{
2124275970Scy	EVUTIL_ASSERT(port);
2125275970Scy	EVUTIL_ASSERT(!port->refcnt);
2126275970Scy	EVUTIL_ASSERT(!port->pending_replies);
2127275970Scy	if (port->socket > 0) {
2128275970Scy		evutil_closesocket(port->socket);
2129275970Scy		port->socket = -1;
2130275970Scy	}
2131275970Scy	(void) event_del(&port->event);
2132275970Scy	event_debug_unassign(&port->event);
2133275970Scy	EVTHREAD_FREE_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
2134275970Scy	mm_free(port);
2135275970Scy}
2136275970Scy
2137275970Scy/* exported function */
2138275970Scyint
2139275970Scyevdns_server_request_drop(struct evdns_server_request *req_)
2140275970Scy{
2141275970Scy	struct server_request *req = TO_SERVER_REQUEST(req_);
2142275970Scy	server_request_free(req);
2143275970Scy	return 0;
2144275970Scy}
2145275970Scy
2146275970Scy/* exported function */
2147275970Scyint
2148275970Scyevdns_server_request_get_requesting_addr(struct evdns_server_request *req_, struct sockaddr *sa, int addr_len)
2149275970Scy{
2150275970Scy	struct server_request *req = TO_SERVER_REQUEST(req_);
2151275970Scy	if (addr_len < (int)req->addrlen)
2152275970Scy		return -1;
2153275970Scy	memcpy(sa, &(req->addr), req->addrlen);
2154275970Scy	return req->addrlen;
2155275970Scy}
2156275970Scy
2157275970Scy#undef APPEND16
2158275970Scy#undef APPEND32
2159275970Scy
2160275970Scy/* this is a libevent callback function which is called when a request */
2161275970Scy/* has timed out. */
2162275970Scystatic void
2163275970Scyevdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
2164275970Scy	struct request *const req = (struct request *) arg;
2165275970Scy	struct evdns_base *base = req->base;
2166275970Scy
2167275970Scy	(void) fd;
2168275970Scy	(void) events;
2169275970Scy
2170275970Scy	log(EVDNS_LOG_DEBUG, "Request %p timed out", arg);
2171275970Scy	EVDNS_LOCK(base);
2172275970Scy
2173275970Scy	if (req->tx_count >= req->base->global_max_retransmits) {
2174285612Sdelphij		struct nameserver *ns = req->ns;
2175275970Scy		/* this request has failed */
2176275970Scy		log(EVDNS_LOG_DEBUG, "Giving up on request %p; tx_count==%d",
2177275970Scy		    arg, req->tx_count);
2178275970Scy		reply_schedule_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
2179285612Sdelphij
2180275970Scy		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
2181285612Sdelphij		nameserver_failed(ns, "request timed out.");
2182275970Scy	} else {
2183275970Scy		/* retransmit it */
2184275970Scy		log(EVDNS_LOG_DEBUG, "Retransmitting request %p; tx_count==%d",
2185275970Scy		    arg, req->tx_count);
2186275970Scy		(void) evtimer_del(&req->timeout_event);
2187285612Sdelphij		request_swap_ns(req, nameserver_pick(base));
2188275970Scy		evdns_request_transmit(req);
2189285612Sdelphij
2190285612Sdelphij		req->ns->timedout++;
2191285612Sdelphij		if (req->ns->timedout > req->base->global_max_nameserver_timeout) {
2192285612Sdelphij			req->ns->timedout = 0;
2193285612Sdelphij			nameserver_failed(req->ns, "request timed out.");
2194285612Sdelphij		}
2195275970Scy	}
2196285612Sdelphij
2197275970Scy	EVDNS_UNLOCK(base);
2198275970Scy}
2199275970Scy
2200275970Scy/* try to send a request to a given server. */
2201275970Scy/* */
2202275970Scy/* return: */
2203275970Scy/*   0 ok */
2204275970Scy/*   1 temporary failure */
2205275970Scy/*   2 other failure */
2206275970Scystatic int
2207275970Scyevdns_request_transmit_to(struct request *req, struct nameserver *server) {
2208275970Scy	int r;
2209275970Scy	ASSERT_LOCKED(req->base);
2210275970Scy	ASSERT_VALID_REQUEST(req);
2211275970Scy
2212275970Scy	if (server->requests_inflight == 1 &&
2213275970Scy		req->base->disable_when_inactive &&
2214275970Scy		event_add(&server->event, NULL) < 0) {
2215275970Scy		return 1;
2216275970Scy	}
2217275970Scy
2218275970Scy	r = sendto(server->socket, (void*)req->request, req->request_len, 0,
2219275970Scy	    (struct sockaddr *)&server->address, server->addrlen);
2220275970Scy	if (r < 0) {
2221275970Scy		int err = evutil_socket_geterror(server->socket);
2222275970Scy		if (EVUTIL_ERR_RW_RETRIABLE(err))
2223275970Scy			return 1;
2224275970Scy		nameserver_failed(req->ns, evutil_socket_error_to_string(err));
2225275970Scy		return 2;
2226275970Scy	} else if (r != (int)req->request_len) {
2227275970Scy		return 1;  /* short write */
2228275970Scy	} else {
2229275970Scy		return 0;
2230275970Scy	}
2231275970Scy}
2232275970Scy
2233275970Scy/* try to send a request, updating the fields of the request */
2234275970Scy/* as needed */
2235275970Scy/* */
2236275970Scy/* return: */
2237275970Scy/*   0 ok */
2238275970Scy/*   1 failed */
2239275970Scystatic int
2240275970Scyevdns_request_transmit(struct request *req) {
2241275970Scy	int retcode = 0, r;
2242275970Scy
2243275970Scy	ASSERT_LOCKED(req->base);
2244275970Scy	ASSERT_VALID_REQUEST(req);
2245275970Scy	/* if we fail to send this packet then this flag marks it */
2246275970Scy	/* for evdns_transmit */
2247275970Scy	req->transmit_me = 1;
2248275970Scy	EVUTIL_ASSERT(req->trans_id != 0xffff);
2249275970Scy
2250275970Scy	if (!req->ns)
2251275970Scy	{
2252275970Scy		/* unable to transmit request if no nameservers */
2253275970Scy		return 1;
2254275970Scy	}
2255275970Scy
2256275970Scy	if (req->ns->choked) {
2257275970Scy		/* don't bother trying to write to a socket */
2258275970Scy		/* which we have had EAGAIN from */
2259275970Scy		return 1;
2260275970Scy	}
2261275970Scy
2262275970Scy	r = evdns_request_transmit_to(req, req->ns);
2263275970Scy	switch (r) {
2264275970Scy	case 1:
2265275970Scy		/* temp failure */
2266275970Scy		req->ns->choked = 1;
2267275970Scy		nameserver_write_waiting(req->ns, 1);
2268275970Scy		return 1;
2269275970Scy	case 2:
2270275970Scy		/* failed to transmit the request entirely. */
2271275970Scy		retcode = 1;
2272275970Scy		/* fall through: we'll set a timeout, which will time out,
2273275970Scy		 * and make us retransmit the request anyway. */
2274275970Scy	default:
2275275970Scy		/* all ok */
2276275970Scy		log(EVDNS_LOG_DEBUG,
2277275970Scy		    "Setting timeout for request %p, sent to nameserver %p", req, req->ns);
2278275970Scy		if (evtimer_add(&req->timeout_event, &req->base->global_timeout) < 0) {
2279275970Scy			log(EVDNS_LOG_WARN,
2280275970Scy		      "Error from libevent when adding timer for request %p",
2281275970Scy			    req);
2282275970Scy			/* ???? Do more? */
2283275970Scy		}
2284275970Scy		req->tx_count++;
2285275970Scy		req->transmit_me = 0;
2286275970Scy		return retcode;
2287275970Scy	}
2288275970Scy}
2289275970Scy
2290275970Scystatic void
2291275970Scynameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
2292275970Scy	struct nameserver *const ns = (struct nameserver *) arg;
2293275970Scy	(void) type;
2294275970Scy	(void) count;
2295275970Scy	(void) ttl;
2296275970Scy	(void) addresses;
2297275970Scy
2298275970Scy	if (result == DNS_ERR_CANCEL) {
2299275970Scy		/* We canceled this request because the nameserver came up
2300275970Scy		 * for some other reason.  Do not change our opinion about
2301275970Scy		 * the nameserver. */
2302275970Scy		return;
2303275970Scy	}
2304275970Scy
2305275970Scy	EVDNS_LOCK(ns->base);
2306275970Scy	ns->probe_request = NULL;
2307275970Scy	if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
2308275970Scy		/* this is a good reply */
2309275970Scy		nameserver_up(ns);
2310275970Scy	} else {
2311275970Scy		nameserver_probe_failed(ns);
2312275970Scy	}
2313275970Scy	EVDNS_UNLOCK(ns->base);
2314275970Scy}
2315275970Scy
2316275970Scystatic void
2317275970Scynameserver_send_probe(struct nameserver *const ns) {
2318275970Scy	struct evdns_request *handle;
2319275970Scy	struct request *req;
2320275970Scy	char addrbuf[128];
2321275970Scy	/* here we need to send a probe to a given nameserver */
2322275970Scy	/* in the hope that it is up now. */
2323275970Scy
2324275970Scy	ASSERT_LOCKED(ns->base);
2325275970Scy	log(EVDNS_LOG_DEBUG, "Sending probe to %s",
2326275970Scy	    evutil_format_sockaddr_port_(
2327275970Scy		    (struct sockaddr *)&ns->address,
2328275970Scy		    addrbuf, sizeof(addrbuf)));
2329275970Scy	handle = mm_calloc(1, sizeof(*handle));
2330275970Scy	if (!handle) return;
2331275970Scy	req = request_new(ns->base, handle, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
2332275970Scy	if (!req) {
2333275970Scy		mm_free(handle);
2334275970Scy		return;
2335275970Scy	}
2336275970Scy	ns->probe_request = handle;
2337275970Scy	/* we force this into the inflight queue no matter what */
2338275970Scy	request_trans_id_set(req, transaction_id_pick(ns->base));
2339275970Scy	req->ns = ns;
2340275970Scy	request_submit(req);
2341275970Scy}
2342275970Scy
2343275970Scy/* returns: */
2344275970Scy/*   0 didn't try to transmit anything */
2345275970Scy/*   1 tried to transmit something */
2346275970Scystatic int
2347275970Scyevdns_transmit(struct evdns_base *base) {
2348275970Scy	char did_try_to_transmit = 0;
2349275970Scy	int i;
2350275970Scy
2351275970Scy	ASSERT_LOCKED(base);
2352275970Scy	for (i = 0; i < base->n_req_heads; ++i) {
2353275970Scy		if (base->req_heads[i]) {
2354275970Scy			struct request *const started_at = base->req_heads[i], *req = started_at;
2355275970Scy			/* first transmit all the requests which are currently waiting */
2356275970Scy			do {
2357275970Scy				if (req->transmit_me) {
2358275970Scy					did_try_to_transmit = 1;
2359275970Scy					evdns_request_transmit(req);
2360275970Scy				}
2361275970Scy
2362275970Scy				req = req->next;
2363275970Scy			} while (req != started_at);
2364275970Scy		}
2365275970Scy	}
2366275970Scy
2367275970Scy	return did_try_to_transmit;
2368275970Scy}
2369275970Scy
2370275970Scy/* exported function */
2371275970Scyint
2372275970Scyevdns_base_count_nameservers(struct evdns_base *base)
2373275970Scy{
2374275970Scy	const struct nameserver *server;
2375275970Scy	int n = 0;
2376275970Scy
2377275970Scy	EVDNS_LOCK(base);
2378275970Scy	server = base->server_head;
2379275970Scy	if (!server)
2380275970Scy		goto done;
2381275970Scy	do {
2382275970Scy		++n;
2383275970Scy		server = server->next;
2384275970Scy	} while (server != base->server_head);
2385275970Scydone:
2386275970Scy	EVDNS_UNLOCK(base);
2387275970Scy	return n;
2388275970Scy}
2389275970Scy
2390275970Scyint
2391275970Scyevdns_count_nameservers(void)
2392275970Scy{
2393275970Scy	return evdns_base_count_nameservers(current_base);
2394275970Scy}
2395275970Scy
2396275970Scy/* exported function */
2397275970Scyint
2398275970Scyevdns_base_clear_nameservers_and_suspend(struct evdns_base *base)
2399275970Scy{
2400275970Scy	struct nameserver *server, *started_at;
2401275970Scy	int i;
2402275970Scy
2403275970Scy	EVDNS_LOCK(base);
2404275970Scy	server = base->server_head;
2405275970Scy	started_at = base->server_head;
2406275970Scy	if (!server) {
2407275970Scy		EVDNS_UNLOCK(base);
2408275970Scy		return 0;
2409275970Scy	}
2410275970Scy	while (1) {
2411275970Scy		struct nameserver *next = server->next;
2412275970Scy		(void) event_del(&server->event);
2413275970Scy		if (evtimer_initialized(&server->timeout_event))
2414275970Scy			(void) evtimer_del(&server->timeout_event);
2415275970Scy		if (server->probe_request) {
2416275970Scy			evdns_cancel_request(server->base, server->probe_request);
2417275970Scy			server->probe_request = NULL;
2418275970Scy		}
2419275970Scy		if (server->socket >= 0)
2420275970Scy			evutil_closesocket(server->socket);
2421275970Scy		mm_free(server);
2422275970Scy		if (next == started_at)
2423275970Scy			break;
2424275970Scy		server = next;
2425275970Scy	}
2426275970Scy	base->server_head = NULL;
2427275970Scy	base->global_good_nameservers = 0;
2428275970Scy
2429275970Scy	for (i = 0; i < base->n_req_heads; ++i) {
2430275970Scy		struct request *req, *req_started_at;
2431275970Scy		req = req_started_at = base->req_heads[i];
2432275970Scy		while (req) {
2433275970Scy			struct request *next = req->next;
2434275970Scy			req->tx_count = req->reissue_count = 0;
2435275970Scy			req->ns = NULL;
2436275970Scy			/* ???? What to do about searches? */
2437275970Scy			(void) evtimer_del(&req->timeout_event);
2438275970Scy			req->trans_id = 0;
2439275970Scy			req->transmit_me = 0;
2440275970Scy
2441275970Scy			base->global_requests_waiting++;
2442275970Scy			evdns_request_insert(req, &base->req_waiting_head);
2443275970Scy			/* We want to insert these suspended elements at the front of
2444275970Scy			 * the waiting queue, since they were pending before any of
2445275970Scy			 * the waiting entries were added.  This is a circular list,
2446275970Scy			 * so we can just shift the start back by one.*/
2447275970Scy			base->req_waiting_head = base->req_waiting_head->prev;
2448275970Scy
2449275970Scy			if (next == req_started_at)
2450275970Scy				break;
2451275970Scy			req = next;
2452275970Scy		}
2453275970Scy		base->req_heads[i] = NULL;
2454275970Scy	}
2455275970Scy
2456275970Scy	base->global_requests_inflight = 0;
2457275970Scy
2458275970Scy	EVDNS_UNLOCK(base);
2459275970Scy	return 0;
2460275970Scy}
2461275970Scy
2462275970Scyint
2463275970Scyevdns_clear_nameservers_and_suspend(void)
2464275970Scy{
2465275970Scy	return evdns_base_clear_nameservers_and_suspend(current_base);
2466275970Scy}
2467275970Scy
2468275970Scy
2469275970Scy/* exported function */
2470275970Scyint
2471275970Scyevdns_base_resume(struct evdns_base *base)
2472275970Scy{
2473275970Scy	EVDNS_LOCK(base);
2474275970Scy	evdns_requests_pump_waiting_queue(base);
2475275970Scy	EVDNS_UNLOCK(base);
2476275970Scy
2477275970Scy	return 0;
2478275970Scy}
2479275970Scy
2480275970Scyint
2481275970Scyevdns_resume(void)
2482275970Scy{
2483275970Scy	return evdns_base_resume(current_base);
2484275970Scy}
2485275970Scy
2486275970Scystatic int
2487275970Scyevdns_nameserver_add_impl_(struct evdns_base *base, const struct sockaddr *address, int addrlen) {
2488275970Scy	/* first check to see if we already have this nameserver */
2489275970Scy
2490275970Scy	const struct nameserver *server = base->server_head, *const started_at = base->server_head;
2491275970Scy	struct nameserver *ns;
2492275970Scy	int err = 0;
2493275970Scy	char addrbuf[128];
2494275970Scy
2495275970Scy	ASSERT_LOCKED(base);
2496275970Scy	if (server) {
2497275970Scy		do {
2498275970Scy			if (!evutil_sockaddr_cmp((struct sockaddr*)&server->address, address, 1)) return 3;
2499275970Scy			server = server->next;
2500275970Scy		} while (server != started_at);
2501275970Scy	}
2502275970Scy	if (addrlen > (int)sizeof(ns->address)) {
2503275970Scy		log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
2504275970Scy		return 2;
2505275970Scy	}
2506275970Scy
2507275970Scy	ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver));
2508275970Scy	if (!ns) return -1;
2509275970Scy
2510275970Scy	memset(ns, 0, sizeof(struct nameserver));
2511275970Scy	ns->base = base;
2512275970Scy
2513275970Scy	evtimer_assign(&ns->timeout_event, ns->base->event_base, nameserver_prod_callback, ns);
2514275970Scy
2515275970Scy	ns->socket = evutil_socket_(address->sa_family,
2516275970Scy	    SOCK_DGRAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
2517275970Scy	if (ns->socket < 0) { err = 1; goto out1; }
2518275970Scy
2519275970Scy	if (base->global_outgoing_addrlen &&
2520275970Scy	    !evutil_sockaddr_is_loopback_(address)) {
2521275970Scy		if (bind(ns->socket,
2522275970Scy			(struct sockaddr*)&base->global_outgoing_address,
2523275970Scy			base->global_outgoing_addrlen) < 0) {
2524275970Scy			log(EVDNS_LOG_WARN,"Couldn't bind to outgoing address");
2525275970Scy			err = 2;
2526275970Scy			goto out2;
2527275970Scy		}
2528275970Scy	}
2529275970Scy
2530275970Scy	memcpy(&ns->address, address, addrlen);
2531275970Scy	ns->addrlen = addrlen;
2532275970Scy	ns->state = 1;
2533275970Scy	event_assign(&ns->event, ns->base->event_base, ns->socket,
2534275970Scy				 EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
2535275970Scy	if (!base->disable_when_inactive && event_add(&ns->event, NULL) < 0) {
2536275970Scy		err = 2;
2537275970Scy		goto out2;
2538275970Scy	}
2539275970Scy
2540275970Scy	log(EVDNS_LOG_DEBUG, "Added nameserver %s as %p",
2541275970Scy	    evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), ns);
2542275970Scy
2543275970Scy	/* insert this nameserver into the list of them */
2544275970Scy	if (!base->server_head) {
2545275970Scy		ns->next = ns->prev = ns;
2546275970Scy		base->server_head = ns;
2547275970Scy	} else {
2548275970Scy		ns->next = base->server_head->next;
2549275970Scy		ns->prev = base->server_head;
2550275970Scy		base->server_head->next = ns;
2551275970Scy		ns->next->prev = ns;
2552275970Scy	}
2553275970Scy
2554275970Scy	base->global_good_nameservers++;
2555275970Scy
2556275970Scy	return 0;
2557275970Scy
2558275970Scyout2:
2559275970Scy	evutil_closesocket(ns->socket);
2560275970Scyout1:
2561275970Scy	event_debug_unassign(&ns->event);
2562275970Scy	mm_free(ns);
2563275970Scy	log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d",
2564275970Scy	    evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), err);
2565275970Scy	return err;
2566275970Scy}
2567275970Scy
2568275970Scy/* exported function */
2569275970Scyint
2570275970Scyevdns_base_nameserver_add(struct evdns_base *base, unsigned long int address)
2571275970Scy{
2572275970Scy	struct sockaddr_in sin;
2573275970Scy	int res;
2574275970Scy	memset(&sin, 0, sizeof(sin));
2575275970Scy	sin.sin_addr.s_addr = address;
2576275970Scy	sin.sin_port = htons(53);
2577275970Scy	sin.sin_family = AF_INET;
2578275970Scy	EVDNS_LOCK(base);
2579275970Scy	res = evdns_nameserver_add_impl_(base, (struct sockaddr*)&sin, sizeof(sin));
2580275970Scy	EVDNS_UNLOCK(base);
2581275970Scy	return res;
2582275970Scy}
2583275970Scy
2584275970Scyint
2585275970Scyevdns_nameserver_add(unsigned long int address) {
2586275970Scy	if (!current_base)
2587275970Scy		current_base = evdns_base_new(NULL, 0);
2588275970Scy	return evdns_base_nameserver_add(current_base, address);
2589275970Scy}
2590275970Scy
2591275970Scystatic void
2592275970Scysockaddr_setport(struct sockaddr *sa, ev_uint16_t port)
2593275970Scy{
2594275970Scy	if (sa->sa_family == AF_INET) {
2595275970Scy		((struct sockaddr_in *)sa)->sin_port = htons(port);
2596275970Scy	} else if (sa->sa_family == AF_INET6) {
2597275970Scy		((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
2598275970Scy	}
2599275970Scy}
2600275970Scy
2601275970Scystatic ev_uint16_t
2602275970Scysockaddr_getport(struct sockaddr *sa)
2603275970Scy{
2604275970Scy	if (sa->sa_family == AF_INET) {
2605275970Scy		return ntohs(((struct sockaddr_in *)sa)->sin_port);
2606275970Scy	} else if (sa->sa_family == AF_INET6) {
2607275970Scy		return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
2608275970Scy	} else {
2609275970Scy		return 0;
2610275970Scy	}
2611275970Scy}
2612275970Scy
2613275970Scy/* exported function */
2614275970Scyint
2615275970Scyevdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) {
2616275970Scy	struct sockaddr_storage ss;
2617275970Scy	struct sockaddr *sa;
2618275970Scy	int len = sizeof(ss);
2619275970Scy	int res;
2620275970Scy	if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss,
2621275970Scy		&len)) {
2622275970Scy		log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s",
2623275970Scy			ip_as_string);
2624275970Scy		return 4;
2625275970Scy	}
2626275970Scy	sa = (struct sockaddr *) &ss;
2627275970Scy	if (sockaddr_getport(sa) == 0)
2628275970Scy		sockaddr_setport(sa, 53);
2629275970Scy
2630275970Scy	EVDNS_LOCK(base);
2631275970Scy	res = evdns_nameserver_add_impl_(base, sa, len);
2632275970Scy	EVDNS_UNLOCK(base);
2633275970Scy	return res;
2634275970Scy}
2635275970Scy
2636275970Scyint
2637275970Scyevdns_nameserver_ip_add(const char *ip_as_string) {
2638275970Scy	if (!current_base)
2639275970Scy		current_base = evdns_base_new(NULL, 0);
2640275970Scy	return evdns_base_nameserver_ip_add(current_base, ip_as_string);
2641275970Scy}
2642275970Scy
2643275970Scyint
2644275970Scyevdns_base_nameserver_sockaddr_add(struct evdns_base *base,
2645275970Scy    const struct sockaddr *sa, ev_socklen_t len, unsigned flags)
2646275970Scy{
2647275970Scy	int res;
2648275970Scy	EVUTIL_ASSERT(base);
2649275970Scy	EVDNS_LOCK(base);
2650275970Scy	res = evdns_nameserver_add_impl_(base, sa, len);
2651275970Scy	EVDNS_UNLOCK(base);
2652275970Scy	return res;
2653275970Scy}
2654275970Scy
2655285612Sdelphijint
2656285612Sdelphijevdns_base_get_nameserver_addr(struct evdns_base *base, int idx,
2657285612Sdelphij    struct sockaddr *sa, ev_socklen_t len)
2658285612Sdelphij{
2659285612Sdelphij	int result = -1;
2660285612Sdelphij	int i;
2661285612Sdelphij	struct nameserver *server;
2662285612Sdelphij	EVDNS_LOCK(base);
2663285612Sdelphij	server = base->server_head;
2664285612Sdelphij	for (i = 0; i < idx && server; ++i, server = server->next) {
2665285612Sdelphij		if (server->next == base->server_head)
2666285612Sdelphij			goto done;
2667285612Sdelphij	}
2668285612Sdelphij	if (! server)
2669285612Sdelphij		goto done;
2670285612Sdelphij
2671285612Sdelphij	if (server->addrlen > len) {
2672285612Sdelphij		result = (int) server->addrlen;
2673285612Sdelphij		goto done;
2674285612Sdelphij	}
2675285612Sdelphij
2676285612Sdelphij	memcpy(sa, &server->address, server->addrlen);
2677285612Sdelphij	result = (int) server->addrlen;
2678285612Sdelphijdone:
2679285612Sdelphij	EVDNS_UNLOCK(base);
2680285612Sdelphij	return result;
2681285612Sdelphij}
2682285612Sdelphij
2683275970Scy/* remove from the queue */
2684275970Scystatic void
2685275970Scyevdns_request_remove(struct request *req, struct request **head)
2686275970Scy{
2687275970Scy	ASSERT_LOCKED(req->base);
2688275970Scy	ASSERT_VALID_REQUEST(req);
2689275970Scy
2690275970Scy#if 0
2691275970Scy	{
2692275970Scy		struct request *ptr;
2693275970Scy		int found = 0;
2694275970Scy		EVUTIL_ASSERT(*head != NULL);
2695275970Scy
2696275970Scy		ptr = *head;
2697275970Scy		do {
2698275970Scy			if (ptr == req) {
2699275970Scy				found = 1;
2700275970Scy				break;
2701275970Scy			}
2702275970Scy			ptr = ptr->next;
2703275970Scy		} while (ptr != *head);
2704275970Scy		EVUTIL_ASSERT(found);
2705275970Scy
2706275970Scy		EVUTIL_ASSERT(req->next);
2707275970Scy	}
2708275970Scy#endif
2709275970Scy
2710275970Scy	if (req->next == req) {
2711275970Scy		/* only item in the list */
2712275970Scy		*head = NULL;
2713275970Scy	} else {
2714275970Scy		req->next->prev = req->prev;
2715275970Scy		req->prev->next = req->next;
2716275970Scy		if (*head == req) *head = req->next;
2717275970Scy	}
2718275970Scy	req->next = req->prev = NULL;
2719275970Scy}
2720275970Scy
2721275970Scy/* insert into the tail of the queue */
2722275970Scystatic void
2723275970Scyevdns_request_insert(struct request *req, struct request **head) {
2724275970Scy	ASSERT_LOCKED(req->base);
2725275970Scy	ASSERT_VALID_REQUEST(req);
2726275970Scy	if (!*head) {
2727275970Scy		*head = req;
2728275970Scy		req->next = req->prev = req;
2729275970Scy		return;
2730275970Scy	}
2731275970Scy
2732275970Scy	req->prev = (*head)->prev;
2733275970Scy	req->prev->next = req;
2734275970Scy	req->next = *head;
2735275970Scy	(*head)->prev = req;
2736275970Scy}
2737275970Scy
2738275970Scystatic int
2739275970Scystring_num_dots(const char *s) {
2740275970Scy	int count = 0;
2741275970Scy	while ((s = strchr(s, '.'))) {
2742275970Scy		s++;
2743275970Scy		count++;
2744275970Scy	}
2745275970Scy	return count;
2746275970Scy}
2747275970Scy
2748275970Scystatic struct request *
2749275970Scyrequest_new(struct evdns_base *base, struct evdns_request *handle, int type,
2750275970Scy	    const char *name, int flags, evdns_callback_type callback,
2751275970Scy	    void *user_ptr) {
2752275970Scy
2753275970Scy	const char issuing_now =
2754275970Scy	    (base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0;
2755275970Scy
2756275970Scy	const size_t name_len = strlen(name);
2757275970Scy	const size_t request_max_len = evdns_request_len(name_len);
2758275970Scy	const u16 trans_id = issuing_now ? transaction_id_pick(base) : 0xffff;
2759275970Scy	/* the request data is alloced in a single block with the header */
2760275970Scy	struct request *const req =
2761275970Scy	    mm_malloc(sizeof(struct request) + request_max_len);
2762275970Scy	int rlen;
2763275970Scy	char namebuf[256];
2764275970Scy	(void) flags;
2765275970Scy
2766275970Scy	ASSERT_LOCKED(base);
2767275970Scy
2768275970Scy	if (!req) return NULL;
2769275970Scy
2770275970Scy	if (name_len >= sizeof(namebuf)) {
2771275970Scy		mm_free(req);
2772275970Scy		return NULL;
2773275970Scy	}
2774275970Scy
2775275970Scy	memset(req, 0, sizeof(struct request));
2776275970Scy	req->base = base;
2777275970Scy
2778275970Scy	evtimer_assign(&req->timeout_event, req->base->event_base, evdns_request_timeout_callback, req);
2779275970Scy
2780275970Scy	if (base->global_randomize_case) {
2781275970Scy		unsigned i;
2782275970Scy		char randbits[(sizeof(namebuf)+7)/8];
2783275970Scy		strlcpy(namebuf, name, sizeof(namebuf));
2784275970Scy		evutil_secure_rng_get_bytes(randbits, (name_len+7)/8);
2785275970Scy		for (i = 0; i < name_len; ++i) {
2786275970Scy			if (EVUTIL_ISALPHA_(namebuf[i])) {
2787275970Scy				if ((randbits[i >> 3] & (1<<(i & 7))))
2788275970Scy					namebuf[i] |= 0x20;
2789275970Scy				else
2790275970Scy					namebuf[i] &= ~0x20;
2791275970Scy			}
2792275970Scy		}
2793275970Scy		name = namebuf;
2794275970Scy	}
2795275970Scy
2796275970Scy	/* request data lives just after the header */
2797275970Scy	req->request = ((u8 *) req) + sizeof(struct request);
2798275970Scy	/* denotes that the request data shouldn't be free()ed */
2799275970Scy	req->request_appended = 1;
2800275970Scy	rlen = evdns_request_data_build(name, name_len, trans_id,
2801275970Scy	    type, CLASS_INET, req->request, request_max_len);
2802275970Scy	if (rlen < 0)
2803275970Scy		goto err1;
2804275970Scy
2805275970Scy	req->request_len = rlen;
2806275970Scy	req->trans_id = trans_id;
2807275970Scy	req->tx_count = 0;
2808275970Scy	req->request_type = type;
2809275970Scy	req->user_pointer = user_ptr;
2810275970Scy	req->user_callback = callback;
2811275970Scy	req->ns = issuing_now ? nameserver_pick(base) : NULL;
2812275970Scy	req->next = req->prev = NULL;
2813275970Scy	req->handle = handle;
2814275970Scy	if (handle) {
2815275970Scy		handle->current_req = req;
2816275970Scy		handle->base = base;
2817275970Scy	}
2818275970Scy
2819275970Scy	return req;
2820275970Scyerr1:
2821275970Scy	mm_free(req);
2822275970Scy	return NULL;
2823275970Scy}
2824275970Scy
2825275970Scystatic void
2826275970Scyrequest_submit(struct request *const req) {
2827275970Scy	struct evdns_base *base = req->base;
2828275970Scy	ASSERT_LOCKED(base);
2829275970Scy	ASSERT_VALID_REQUEST(req);
2830275970Scy	if (req->ns) {
2831275970Scy		/* if it has a nameserver assigned then this is going */
2832275970Scy		/* straight into the inflight queue */
2833275970Scy		evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
2834275970Scy
2835275970Scy		base->global_requests_inflight++;
2836275970Scy		req->ns->requests_inflight++;
2837275970Scy
2838275970Scy		evdns_request_transmit(req);
2839275970Scy	} else {
2840275970Scy		evdns_request_insert(req, &base->req_waiting_head);
2841275970Scy		base->global_requests_waiting++;
2842275970Scy	}
2843275970Scy}
2844275970Scy
2845275970Scy/* exported function */
2846275970Scyvoid
2847275970Scyevdns_cancel_request(struct evdns_base *base, struct evdns_request *handle)
2848275970Scy{
2849275970Scy	struct request *req;
2850275970Scy
2851275970Scy	if (!handle->current_req)
2852275970Scy		return;
2853275970Scy
2854275970Scy	if (!base) {
2855275970Scy		/* This redundancy is silly; can we fix it? (Not for 2.0) XXXX */
2856275970Scy		base = handle->base;
2857275970Scy		if (!base)
2858275970Scy			base = handle->current_req->base;
2859275970Scy	}
2860275970Scy
2861275970Scy	EVDNS_LOCK(base);
2862275970Scy	if (handle->pending_cb) {
2863275970Scy		EVDNS_UNLOCK(base);
2864275970Scy		return;
2865275970Scy	}
2866275970Scy
2867275970Scy	req = handle->current_req;
2868275970Scy	ASSERT_VALID_REQUEST(req);
2869275970Scy
2870275970Scy	reply_schedule_callback(req, 0, DNS_ERR_CANCEL, NULL);
2871275970Scy	if (req->ns) {
2872275970Scy		/* remove from inflight queue */
2873275970Scy		request_finished(req, &REQ_HEAD(base, req->trans_id), 1);
2874275970Scy	} else {
2875275970Scy		/* remove from global_waiting head */
2876275970Scy		request_finished(req, &base->req_waiting_head, 1);
2877275970Scy	}
2878275970Scy	EVDNS_UNLOCK(base);
2879275970Scy}
2880275970Scy
2881275970Scy/* exported function */
2882275970Scystruct evdns_request *
2883275970Scyevdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags,
2884275970Scy    evdns_callback_type callback, void *ptr) {
2885275970Scy	struct evdns_request *handle;
2886275970Scy	struct request *req;
2887275970Scy	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
2888275970Scy	handle = mm_calloc(1, sizeof(*handle));
2889275970Scy	if (handle == NULL)
2890275970Scy		return NULL;
2891275970Scy	EVDNS_LOCK(base);
2892275970Scy	if (flags & DNS_QUERY_NO_SEARCH) {
2893275970Scy		req =
2894275970Scy			request_new(base, handle, TYPE_A, name, flags,
2895275970Scy				    callback, ptr);
2896275970Scy		if (req)
2897275970Scy			request_submit(req);
2898275970Scy	} else {
2899275970Scy		search_request_new(base, handle, TYPE_A, name, flags,
2900275970Scy		    callback, ptr);
2901275970Scy	}
2902275970Scy	if (handle->current_req == NULL) {
2903275970Scy		mm_free(handle);
2904275970Scy		handle = NULL;
2905275970Scy	}
2906275970Scy	EVDNS_UNLOCK(base);
2907275970Scy	return handle;
2908275970Scy}
2909275970Scy
2910275970Scyint evdns_resolve_ipv4(const char *name, int flags,
2911275970Scy					   evdns_callback_type callback, void *ptr)
2912275970Scy{
2913275970Scy	return evdns_base_resolve_ipv4(current_base, name, flags, callback, ptr)
2914275970Scy		? 0 : -1;
2915275970Scy}
2916275970Scy
2917275970Scy
2918275970Scy/* exported function */
2919275970Scystruct evdns_request *
2920275970Scyevdns_base_resolve_ipv6(struct evdns_base *base,
2921275970Scy    const char *name, int flags,
2922275970Scy    evdns_callback_type callback, void *ptr)
2923275970Scy{
2924275970Scy	struct evdns_request *handle;
2925275970Scy	struct request *req;
2926275970Scy	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
2927275970Scy	handle = mm_calloc(1, sizeof(*handle));
2928275970Scy	if (handle == NULL)
2929275970Scy		return NULL;
2930275970Scy	EVDNS_LOCK(base);
2931275970Scy	if (flags & DNS_QUERY_NO_SEARCH) {
2932275970Scy		req = request_new(base, handle, TYPE_AAAA, name, flags,
2933275970Scy				  callback, ptr);
2934275970Scy		if (req)
2935275970Scy			request_submit(req);
2936275970Scy	} else {
2937275970Scy		search_request_new(base, handle, TYPE_AAAA, name, flags,
2938275970Scy		    callback, ptr);
2939275970Scy	}
2940275970Scy	if (handle->current_req == NULL) {
2941275970Scy		mm_free(handle);
2942275970Scy		handle = NULL;
2943275970Scy	}
2944275970Scy	EVDNS_UNLOCK(base);
2945275970Scy	return handle;
2946275970Scy}
2947275970Scy
2948275970Scyint evdns_resolve_ipv6(const char *name, int flags,
2949275970Scy    evdns_callback_type callback, void *ptr) {
2950275970Scy	return evdns_base_resolve_ipv6(current_base, name, flags, callback, ptr)
2951275970Scy		? 0 : -1;
2952275970Scy}
2953275970Scy
2954275970Scystruct evdns_request *
2955275970Scyevdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
2956275970Scy	char buf[32];
2957275970Scy	struct evdns_request *handle;
2958275970Scy	struct request *req;
2959275970Scy	u32 a;
2960275970Scy	EVUTIL_ASSERT(in);
2961275970Scy	a = ntohl(in->s_addr);
2962275970Scy	evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
2963275970Scy			(int)(u8)((a	)&0xff),
2964275970Scy			(int)(u8)((a>>8 )&0xff),
2965275970Scy			(int)(u8)((a>>16)&0xff),
2966275970Scy			(int)(u8)((a>>24)&0xff));
2967275970Scy	handle = mm_calloc(1, sizeof(*handle));
2968275970Scy	if (handle == NULL)
2969275970Scy		return NULL;
2970275970Scy	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
2971275970Scy	EVDNS_LOCK(base);
2972275970Scy	req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
2973275970Scy	if (req)
2974275970Scy		request_submit(req);
2975275970Scy	if (handle->current_req == NULL) {
2976275970Scy		mm_free(handle);
2977275970Scy		handle = NULL;
2978275970Scy	}
2979275970Scy	EVDNS_UNLOCK(base);
2980275970Scy	return (handle);
2981275970Scy}
2982275970Scy
2983275970Scyint evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
2984275970Scy	return evdns_base_resolve_reverse(current_base, in, flags, callback, ptr)
2985275970Scy		? 0 : -1;
2986275970Scy}
2987275970Scy
2988275970Scystruct evdns_request *
2989275970Scyevdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
2990275970Scy	/* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
2991275970Scy	char buf[73];
2992275970Scy	char *cp;
2993275970Scy	struct evdns_request *handle;
2994275970Scy	struct request *req;
2995275970Scy	int i;
2996275970Scy	EVUTIL_ASSERT(in);
2997275970Scy	cp = buf;
2998275970Scy	for (i=15; i >= 0; --i) {
2999275970Scy		u8 byte = in->s6_addr[i];
3000275970Scy		*cp++ = "0123456789abcdef"[byte & 0x0f];
3001275970Scy		*cp++ = '.';
3002275970Scy		*cp++ = "0123456789abcdef"[byte >> 4];
3003275970Scy		*cp++ = '.';
3004275970Scy	}
3005275970Scy	EVUTIL_ASSERT(cp + strlen("ip6.arpa") < buf+sizeof(buf));
3006275970Scy	memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
3007275970Scy	handle = mm_calloc(1, sizeof(*handle));
3008275970Scy	if (handle == NULL)
3009275970Scy		return NULL;
3010275970Scy	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
3011275970Scy	EVDNS_LOCK(base);
3012275970Scy	req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
3013275970Scy	if (req)
3014275970Scy		request_submit(req);
3015275970Scy	if (handle->current_req == NULL) {
3016275970Scy		mm_free(handle);
3017275970Scy		handle = NULL;
3018275970Scy	}
3019275970Scy	EVDNS_UNLOCK(base);
3020275970Scy	return (handle);
3021275970Scy}
3022275970Scy
3023275970Scyint evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
3024275970Scy	return evdns_base_resolve_reverse_ipv6(current_base, in, flags, callback, ptr)
3025275970Scy		? 0 : -1;
3026275970Scy}
3027275970Scy
3028275970Scy/* ================================================================= */
3029275970Scy/* Search support */
3030275970Scy/* */
3031275970Scy/* the libc resolver has support for searching a number of domains */
3032275970Scy/* to find a name. If nothing else then it takes the single domain */
3033275970Scy/* from the gethostname() call. */
3034275970Scy/* */
3035275970Scy/* It can also be configured via the domain and search options in a */
3036275970Scy/* resolv.conf. */
3037275970Scy/* */
3038275970Scy/* The ndots option controls how many dots it takes for the resolver */
3039275970Scy/* to decide that a name is non-local and so try a raw lookup first. */
3040275970Scy
3041275970Scystruct search_domain {
3042275970Scy	int len;
3043275970Scy	struct search_domain *next;
3044275970Scy	/* the text string is appended to this structure */
3045275970Scy};
3046275970Scy
3047275970Scystruct search_state {
3048275970Scy	int refcount;
3049275970Scy	int ndots;
3050275970Scy	int num_domains;
3051275970Scy	struct search_domain *head;
3052275970Scy};
3053275970Scy
3054275970Scystatic void
3055275970Scysearch_state_decref(struct search_state *const state) {
3056275970Scy	if (!state) return;
3057275970Scy	state->refcount--;
3058275970Scy	if (!state->refcount) {
3059275970Scy		struct search_domain *next, *dom;
3060275970Scy		for (dom = state->head; dom; dom = next) {
3061275970Scy			next = dom->next;
3062275970Scy			mm_free(dom);
3063275970Scy		}
3064275970Scy		mm_free(state);
3065275970Scy	}
3066275970Scy}
3067275970Scy
3068275970Scystatic struct search_state *
3069275970Scysearch_state_new(void) {
3070275970Scy	struct search_state *state = (struct search_state *) mm_malloc(sizeof(struct search_state));
3071275970Scy	if (!state) return NULL;
3072275970Scy	memset(state, 0, sizeof(struct search_state));
3073275970Scy	state->refcount = 1;
3074275970Scy	state->ndots = 1;
3075275970Scy
3076275970Scy	return state;
3077275970Scy}
3078275970Scy
3079275970Scystatic void
3080275970Scysearch_postfix_clear(struct evdns_base *base) {
3081275970Scy	search_state_decref(base->global_search_state);
3082275970Scy
3083275970Scy	base->global_search_state = search_state_new();
3084275970Scy}
3085275970Scy
3086275970Scy/* exported function */
3087275970Scyvoid
3088275970Scyevdns_base_search_clear(struct evdns_base *base)
3089275970Scy{
3090275970Scy	EVDNS_LOCK(base);
3091275970Scy	search_postfix_clear(base);
3092275970Scy	EVDNS_UNLOCK(base);
3093275970Scy}
3094275970Scy
3095275970Scyvoid
3096275970Scyevdns_search_clear(void) {
3097275970Scy	evdns_base_search_clear(current_base);
3098275970Scy}
3099275970Scy
3100275970Scystatic void
3101275970Scysearch_postfix_add(struct evdns_base *base, const char *domain) {
3102275970Scy	size_t domain_len;
3103275970Scy	struct search_domain *sdomain;
3104275970Scy	while (domain[0] == '.') domain++;
3105275970Scy	domain_len = strlen(domain);
3106275970Scy
3107275970Scy	ASSERT_LOCKED(base);
3108275970Scy	if (!base->global_search_state) base->global_search_state = search_state_new();
3109275970Scy	if (!base->global_search_state) return;
3110275970Scy	base->global_search_state->num_domains++;
3111275970Scy
3112275970Scy	sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len);
3113275970Scy	if (!sdomain) return;
3114275970Scy	memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
3115275970Scy	sdomain->next = base->global_search_state->head;
3116275970Scy	sdomain->len = (int) domain_len;
3117275970Scy
3118275970Scy	base->global_search_state->head = sdomain;
3119275970Scy}
3120275970Scy
3121275970Scy/* reverse the order of members in the postfix list. This is needed because, */
3122275970Scy/* when parsing resolv.conf we push elements in the wrong order */
3123275970Scystatic void
3124275970Scysearch_reverse(struct evdns_base *base) {
3125275970Scy	struct search_domain *cur, *prev = NULL, *next;
3126275970Scy	ASSERT_LOCKED(base);
3127275970Scy	cur = base->global_search_state->head;
3128275970Scy	while (cur) {
3129275970Scy		next = cur->next;
3130275970Scy		cur->next = prev;
3131275970Scy		prev = cur;
3132275970Scy		cur = next;
3133275970Scy	}
3134275970Scy
3135275970Scy	base->global_search_state->head = prev;
3136275970Scy}
3137275970Scy
3138275970Scy/* exported function */
3139275970Scyvoid
3140275970Scyevdns_base_search_add(struct evdns_base *base, const char *domain) {
3141275970Scy	EVDNS_LOCK(base);
3142275970Scy	search_postfix_add(base, domain);
3143275970Scy	EVDNS_UNLOCK(base);
3144275970Scy}
3145275970Scyvoid
3146275970Scyevdns_search_add(const char *domain) {
3147275970Scy	evdns_base_search_add(current_base, domain);
3148275970Scy}
3149275970Scy
3150275970Scy/* exported function */
3151275970Scyvoid
3152275970Scyevdns_base_search_ndots_set(struct evdns_base *base, const int ndots) {
3153275970Scy	EVDNS_LOCK(base);
3154275970Scy	if (!base->global_search_state) base->global_search_state = search_state_new();
3155275970Scy	if (base->global_search_state)
3156275970Scy		base->global_search_state->ndots = ndots;
3157275970Scy	EVDNS_UNLOCK(base);
3158275970Scy}
3159275970Scyvoid
3160275970Scyevdns_search_ndots_set(const int ndots) {
3161275970Scy	evdns_base_search_ndots_set(current_base, ndots);
3162275970Scy}
3163275970Scy
3164275970Scystatic void
3165275970Scysearch_set_from_hostname(struct evdns_base *base) {
3166275970Scy	char hostname[HOST_NAME_MAX + 1], *domainname;
3167275970Scy
3168275970Scy	ASSERT_LOCKED(base);
3169275970Scy	search_postfix_clear(base);
3170275970Scy	if (gethostname(hostname, sizeof(hostname))) return;
3171275970Scy	domainname = strchr(hostname, '.');
3172275970Scy	if (!domainname) return;
3173275970Scy	search_postfix_add(base, domainname);
3174275970Scy}
3175275970Scy
3176275970Scy/* warning: returns malloced string */
3177275970Scystatic char *
3178275970Scysearch_make_new(const struct search_state *const state, int n, const char *const base_name) {
3179275970Scy	const size_t base_len = strlen(base_name);
3180275970Scy	const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
3181275970Scy	struct search_domain *dom;
3182275970Scy
3183275970Scy	for (dom = state->head; dom; dom = dom->next) {
3184275970Scy		if (!n--) {
3185275970Scy			/* this is the postfix we want */
3186275970Scy			/* the actual postfix string is kept at the end of the structure */
3187275970Scy			const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
3188275970Scy			const int postfix_len = dom->len;
3189275970Scy			char *const newname = (char *) mm_malloc(base_len + need_to_append_dot + postfix_len + 1);
3190275970Scy			if (!newname) return NULL;
3191275970Scy			memcpy(newname, base_name, base_len);
3192275970Scy			if (need_to_append_dot) newname[base_len] = '.';
3193275970Scy			memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
3194275970Scy			newname[base_len + need_to_append_dot + postfix_len] = 0;
3195275970Scy			return newname;
3196275970Scy		}
3197275970Scy	}
3198275970Scy
3199275970Scy	/* we ran off the end of the list and still didn't find the requested string */
3200275970Scy	EVUTIL_ASSERT(0);
3201275970Scy	return NULL; /* unreachable; stops warnings in some compilers. */
3202275970Scy}
3203275970Scy
3204275970Scystatic struct request *
3205275970Scysearch_request_new(struct evdns_base *base, struct evdns_request *handle,
3206275970Scy		   int type, const char *const name, int flags,
3207275970Scy		   evdns_callback_type user_callback, void *user_arg) {
3208275970Scy	ASSERT_LOCKED(base);
3209275970Scy	EVUTIL_ASSERT(type == TYPE_A || type == TYPE_AAAA);
3210275970Scy	EVUTIL_ASSERT(handle->current_req == NULL);
3211275970Scy	if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
3212275970Scy	     base->global_search_state &&
3213275970Scy		 base->global_search_state->num_domains) {
3214275970Scy		/* we have some domains to search */
3215275970Scy		struct request *req;
3216275970Scy		if (string_num_dots(name) >= base->global_search_state->ndots) {
3217275970Scy			req = request_new(base, handle, type, name, flags, user_callback, user_arg);
3218275970Scy			if (!req) return NULL;
3219275970Scy			handle->search_index = -1;
3220275970Scy		} else {
3221275970Scy			char *const new_name = search_make_new(base->global_search_state, 0, name);
3222275970Scy			if (!new_name) return NULL;
3223275970Scy			req = request_new(base, handle, type, new_name, flags, user_callback, user_arg);
3224275970Scy			mm_free(new_name);
3225275970Scy			if (!req) return NULL;
3226275970Scy			handle->search_index = 0;
3227275970Scy		}
3228275970Scy		EVUTIL_ASSERT(handle->search_origname == NULL);
3229275970Scy		handle->search_origname = mm_strdup(name);
3230275970Scy		if (handle->search_origname == NULL) {
3231275970Scy			/* XXX Should we dealloc req? If yes, how? */
3232275970Scy			if (req)
3233275970Scy				mm_free(req);
3234275970Scy			return NULL;
3235275970Scy		}
3236275970Scy		handle->search_state = base->global_search_state;
3237275970Scy		handle->search_flags = flags;
3238275970Scy		base->global_search_state->refcount++;
3239275970Scy		request_submit(req);
3240275970Scy		return req;
3241275970Scy	} else {
3242275970Scy		struct request *const req = request_new(base, handle, type, name, flags, user_callback, user_arg);
3243275970Scy		if (!req) return NULL;
3244275970Scy		request_submit(req);
3245275970Scy		return req;
3246275970Scy	}
3247275970Scy}
3248275970Scy
3249275970Scy/* this is called when a request has failed to find a name. We need to check */
3250275970Scy/* if it is part of a search and, if so, try the next name in the list */
3251275970Scy/* returns: */
3252275970Scy/*   0 another request has been submitted */
3253275970Scy/*   1 no more requests needed */
3254275970Scystatic int
3255275970Scysearch_try_next(struct evdns_request *const handle) {
3256275970Scy	struct request *req = handle->current_req;
3257275970Scy	struct evdns_base *base = req->base;
3258275970Scy	struct request *newreq;
3259275970Scy	ASSERT_LOCKED(base);
3260275970Scy	if (handle->search_state) {
3261275970Scy		/* it is part of a search */
3262275970Scy		char *new_name;
3263275970Scy		handle->search_index++;
3264275970Scy		if (handle->search_index >= handle->search_state->num_domains) {
3265275970Scy			/* no more postfixes to try, however we may need to try */
3266275970Scy			/* this name without a postfix */
3267275970Scy			if (string_num_dots(handle->search_origname) < handle->search_state->ndots) {
3268275970Scy				/* yep, we need to try it raw */
3269275970Scy				newreq = request_new(base, NULL, req->request_type, handle->search_origname, handle->search_flags, req->user_callback, req->user_pointer);
3270275970Scy				log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", handle->search_origname);
3271275970Scy				if (newreq) {
3272275970Scy					search_request_finished(handle);
3273275970Scy					goto submit_next;
3274275970Scy				}
3275275970Scy			}
3276275970Scy			return 1;
3277275970Scy		}
3278275970Scy
3279275970Scy		new_name = search_make_new(handle->search_state, handle->search_index, handle->search_origname);
3280275970Scy		if (!new_name) return 1;
3281275970Scy		log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, handle->search_index);
3282275970Scy		newreq = request_new(base, NULL, req->request_type, new_name, handle->search_flags, req->user_callback, req->user_pointer);
3283275970Scy		mm_free(new_name);
3284275970Scy		if (!newreq) return 1;
3285275970Scy		goto submit_next;
3286275970Scy	}
3287275970Scy	return 1;
3288275970Scy
3289275970Scysubmit_next:
3290275970Scy	request_finished(req, &REQ_HEAD(req->base, req->trans_id), 0);
3291275970Scy	handle->current_req = newreq;
3292275970Scy	newreq->handle = handle;
3293275970Scy	request_submit(newreq);
3294275970Scy	return 0;
3295275970Scy}
3296275970Scy
3297275970Scystatic void
3298275970Scysearch_request_finished(struct evdns_request *const handle) {
3299275970Scy	ASSERT_LOCKED(handle->current_req->base);
3300275970Scy	if (handle->search_state) {
3301275970Scy		search_state_decref(handle->search_state);
3302275970Scy		handle->search_state = NULL;
3303275970Scy	}
3304275970Scy	if (handle->search_origname) {
3305275970Scy		mm_free(handle->search_origname);
3306275970Scy		handle->search_origname = NULL;
3307275970Scy	}
3308275970Scy}
3309275970Scy
3310275970Scy/* ================================================================= */
3311275970Scy/* Parsing resolv.conf files */
3312275970Scy
3313275970Scystatic void
3314275970Scyevdns_resolv_set_defaults(struct evdns_base *base, int flags) {
3315275970Scy	/* if the file isn't found then we assume a local resolver */
3316275970Scy	ASSERT_LOCKED(base);
3317275970Scy	if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base);
3318275970Scy	if (flags & DNS_OPTION_NAMESERVERS) evdns_base_nameserver_ip_add(base,"127.0.0.1");
3319275970Scy}
3320275970Scy
3321275970Scy#ifndef EVENT__HAVE_STRTOK_R
3322275970Scystatic char *
3323275970Scystrtok_r(char *s, const char *delim, char **state) {
3324275970Scy	char *cp, *start;
3325275970Scy	start = cp = s ? s : *state;
3326275970Scy	if (!cp)
3327275970Scy		return NULL;
3328275970Scy	while (*cp && !strchr(delim, *cp))
3329275970Scy		++cp;
3330275970Scy	if (!*cp) {
3331275970Scy		if (cp == start)
3332275970Scy			return NULL;
3333275970Scy		*state = NULL;
3334275970Scy		return start;
3335275970Scy	} else {
3336275970Scy		*cp++ = '\0';
3337275970Scy		*state = cp;
3338275970Scy		return start;
3339275970Scy	}
3340275970Scy}
3341275970Scy#endif
3342275970Scy
3343275970Scy/* helper version of atoi which returns -1 on error */
3344275970Scystatic int
3345275970Scystrtoint(const char *const str)
3346275970Scy{
3347275970Scy	char *endptr;
3348275970Scy	const int r = strtol(str, &endptr, 10);
3349275970Scy	if (*endptr) return -1;
3350275970Scy	return r;
3351275970Scy}
3352275970Scy
3353275970Scy/* Parse a number of seconds into a timeval; return -1 on error. */
3354275970Scystatic int
3355285612Sdelphijevdns_strtotimeval(const char *const str, struct timeval *out)
3356275970Scy{
3357275970Scy	double d;
3358275970Scy	char *endptr;
3359275970Scy	d = strtod(str, &endptr);
3360275970Scy	if (*endptr) return -1;
3361275970Scy	if (d < 0) return -1;
3362275970Scy	out->tv_sec = (int) d;
3363275970Scy	out->tv_usec = (int) ((d - (int) d)*1000000);
3364275970Scy	if (out->tv_sec == 0 && out->tv_usec < 1000) /* less than 1 msec */
3365275970Scy		return -1;
3366275970Scy	return 0;
3367275970Scy}
3368275970Scy
3369275970Scy/* helper version of atoi that returns -1 on error and clips to bounds. */
3370275970Scystatic int
3371275970Scystrtoint_clipped(const char *const str, int min, int max)
3372275970Scy{
3373275970Scy	int r = strtoint(str);
3374275970Scy	if (r == -1)
3375275970Scy		return r;
3376275970Scy	else if (r<min)
3377275970Scy		return min;
3378275970Scy	else if (r>max)
3379275970Scy		return max;
3380275970Scy	else
3381275970Scy		return r;
3382275970Scy}
3383275970Scy
3384275970Scystatic int
3385275970Scyevdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
3386275970Scy{
3387275970Scy	int old_n_heads = base->n_req_heads, n_heads;
3388275970Scy	struct request **old_heads = base->req_heads, **new_heads, *req;
3389275970Scy	int i;
3390275970Scy
3391275970Scy	ASSERT_LOCKED(base);
3392275970Scy	if (maxinflight < 1)
3393275970Scy		maxinflight = 1;
3394275970Scy	n_heads = (maxinflight+4) / 5;
3395275970Scy	EVUTIL_ASSERT(n_heads > 0);
3396275970Scy	new_heads = mm_calloc(n_heads, sizeof(struct request*));
3397275970Scy	if (!new_heads)
3398275970Scy		return (-1);
3399275970Scy	if (old_heads) {
3400275970Scy		for (i = 0; i < old_n_heads; ++i) {
3401275970Scy			while (old_heads[i]) {
3402275970Scy				req = old_heads[i];
3403275970Scy				evdns_request_remove(req, &old_heads[i]);
3404275970Scy				evdns_request_insert(req, &new_heads[req->trans_id % n_heads]);
3405275970Scy			}
3406275970Scy		}
3407275970Scy		mm_free(old_heads);
3408275970Scy	}
3409275970Scy	base->req_heads = new_heads;
3410275970Scy	base->n_req_heads = n_heads;
3411275970Scy	base->global_max_requests_inflight = maxinflight;
3412275970Scy	return (0);
3413275970Scy}
3414275970Scy
3415275970Scy/* exported function */
3416275970Scyint
3417275970Scyevdns_base_set_option(struct evdns_base *base,
3418275970Scy    const char *option, const char *val)
3419275970Scy{
3420275970Scy	int res;
3421275970Scy	EVDNS_LOCK(base);
3422275970Scy	res = evdns_base_set_option_impl(base, option, val, DNS_OPTIONS_ALL);
3423275970Scy	EVDNS_UNLOCK(base);
3424275970Scy	return res;
3425275970Scy}
3426275970Scy
3427275970Scystatic inline int
3428275970Scystr_matches_option(const char *s1, const char *optionname)
3429275970Scy{
3430275970Scy	/* Option names are given as "option:" We accept either 'option' in
3431275970Scy	 * s1, or 'option:randomjunk'.  The latter form is to implement the
3432275970Scy	 * resolv.conf parser. */
3433275970Scy	size_t optlen = strlen(optionname);
3434275970Scy	size_t slen = strlen(s1);
3435275970Scy	if (slen == optlen || slen == optlen - 1)
3436275970Scy		return !strncmp(s1, optionname, slen);
3437275970Scy	else if (slen > optlen)
3438275970Scy		return !strncmp(s1, optionname, optlen);
3439275970Scy	else
3440275970Scy		return 0;
3441275970Scy}
3442275970Scy
3443275970Scystatic int
3444275970Scyevdns_base_set_option_impl(struct evdns_base *base,
3445275970Scy    const char *option, const char *val, int flags)
3446275970Scy{
3447275970Scy	ASSERT_LOCKED(base);
3448275970Scy	if (str_matches_option(option, "ndots:")) {
3449275970Scy		const int ndots = strtoint(val);
3450275970Scy		if (ndots == -1) return -1;
3451275970Scy		if (!(flags & DNS_OPTION_SEARCH)) return 0;
3452275970Scy		log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
3453275970Scy		if (!base->global_search_state) base->global_search_state = search_state_new();
3454275970Scy		if (!base->global_search_state) return -1;
3455275970Scy		base->global_search_state->ndots = ndots;
3456275970Scy	} else if (str_matches_option(option, "timeout:")) {
3457275970Scy		struct timeval tv;
3458285612Sdelphij		if (evdns_strtotimeval(val, &tv) == -1) return -1;
3459275970Scy		if (!(flags & DNS_OPTION_MISC)) return 0;
3460275970Scy		log(EVDNS_LOG_DEBUG, "Setting timeout to %s", val);
3461275970Scy		memcpy(&base->global_timeout, &tv, sizeof(struct timeval));
3462275970Scy	} else if (str_matches_option(option, "getaddrinfo-allow-skew:")) {
3463275970Scy		struct timeval tv;
3464285612Sdelphij		if (evdns_strtotimeval(val, &tv) == -1) return -1;
3465275970Scy		if (!(flags & DNS_OPTION_MISC)) return 0;
3466275970Scy		log(EVDNS_LOG_DEBUG, "Setting getaddrinfo-allow-skew to %s",
3467275970Scy		    val);
3468275970Scy		memcpy(&base->global_getaddrinfo_allow_skew, &tv,
3469275970Scy		    sizeof(struct timeval));
3470275970Scy	} else if (str_matches_option(option, "max-timeouts:")) {
3471275970Scy		const int maxtimeout = strtoint_clipped(val, 1, 255);
3472275970Scy		if (maxtimeout == -1) return -1;
3473275970Scy		if (!(flags & DNS_OPTION_MISC)) return 0;
3474275970Scy		log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
3475275970Scy			maxtimeout);
3476275970Scy		base->global_max_nameserver_timeout = maxtimeout;
3477275970Scy	} else if (str_matches_option(option, "max-inflight:")) {
3478275970Scy		const int maxinflight = strtoint_clipped(val, 1, 65000);
3479275970Scy		if (maxinflight == -1) return -1;
3480275970Scy		if (!(flags & DNS_OPTION_MISC)) return 0;
3481275970Scy		log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
3482275970Scy			maxinflight);
3483275970Scy		evdns_base_set_max_requests_inflight(base, maxinflight);
3484275970Scy	} else if (str_matches_option(option, "attempts:")) {
3485275970Scy		int retries = strtoint(val);
3486275970Scy		if (retries == -1) return -1;
3487275970Scy		if (retries > 255) retries = 255;
3488275970Scy		if (!(flags & DNS_OPTION_MISC)) return 0;
3489275970Scy		log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
3490275970Scy		base->global_max_retransmits = retries;
3491275970Scy	} else if (str_matches_option(option, "randomize-case:")) {
3492275970Scy		int randcase = strtoint(val);
3493275970Scy		if (!(flags & DNS_OPTION_MISC)) return 0;
3494275970Scy		base->global_randomize_case = randcase;
3495275970Scy	} else if (str_matches_option(option, "bind-to:")) {
3496275970Scy		/* XXX This only applies to successive nameservers, not
3497275970Scy		 * to already-configured ones.	We might want to fix that. */
3498275970Scy		int len = sizeof(base->global_outgoing_address);
3499275970Scy		if (!(flags & DNS_OPTION_NAMESERVERS)) return 0;
3500275970Scy		if (evutil_parse_sockaddr_port(val,
3501275970Scy			(struct sockaddr*)&base->global_outgoing_address, &len))
3502275970Scy			return -1;
3503275970Scy		base->global_outgoing_addrlen = len;
3504275970Scy	} else if (str_matches_option(option, "initial-probe-timeout:")) {
3505275970Scy		struct timeval tv;
3506285612Sdelphij		if (evdns_strtotimeval(val, &tv) == -1) return -1;
3507275970Scy		if (tv.tv_sec > 3600)
3508275970Scy			tv.tv_sec = 3600;
3509275970Scy		if (!(flags & DNS_OPTION_MISC)) return 0;
3510275970Scy		log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s",
3511275970Scy		    val);
3512275970Scy		memcpy(&base->global_nameserver_probe_initial_timeout, &tv,
3513275970Scy		    sizeof(tv));
3514275970Scy	}
3515275970Scy	return 0;
3516275970Scy}
3517275970Scy
3518275970Scyint
3519275970Scyevdns_set_option(const char *option, const char *val, int flags)
3520275970Scy{
3521275970Scy	if (!current_base)
3522275970Scy		current_base = evdns_base_new(NULL, 0);
3523275970Scy	return evdns_base_set_option(current_base, option, val);
3524275970Scy}
3525275970Scy
3526275970Scystatic void
3527275970Scyresolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) {
3528275970Scy	char *strtok_state;
3529275970Scy	static const char *const delims = " \t";
3530275970Scy#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
3531275970Scy
3532275970Scy
3533275970Scy	char *const first_token = strtok_r(start, delims, &strtok_state);
3534275970Scy	ASSERT_LOCKED(base);
3535275970Scy	if (!first_token) return;
3536275970Scy
3537275970Scy	if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
3538275970Scy		const char *const nameserver = NEXT_TOKEN;
3539275970Scy
3540275970Scy		if (nameserver)
3541275970Scy			evdns_base_nameserver_ip_add(base, nameserver);
3542275970Scy	} else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
3543275970Scy		const char *const domain = NEXT_TOKEN;
3544275970Scy		if (domain) {
3545275970Scy			search_postfix_clear(base);
3546275970Scy			search_postfix_add(base, domain);
3547275970Scy		}
3548275970Scy	} else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
3549275970Scy		const char *domain;
3550275970Scy		search_postfix_clear(base);
3551275970Scy
3552275970Scy		while ((domain = NEXT_TOKEN)) {
3553275970Scy			search_postfix_add(base, domain);
3554275970Scy		}
3555275970Scy		search_reverse(base);
3556275970Scy	} else if (!strcmp(first_token, "options")) {
3557275970Scy		const char *option;
3558275970Scy		while ((option = NEXT_TOKEN)) {
3559275970Scy			const char *val = strchr(option, ':');
3560275970Scy			evdns_base_set_option_impl(base, option, val ? val+1 : "", flags);
3561275970Scy		}
3562275970Scy	}
3563275970Scy#undef NEXT_TOKEN
3564275970Scy}
3565275970Scy
3566275970Scy/* exported function */
3567275970Scy/* returns: */
3568275970Scy/*   0 no errors */
3569275970Scy/*   1 failed to open file */
3570275970Scy/*   2 failed to stat file */
3571275970Scy/*   3 file too large */
3572275970Scy/*   4 out of memory */
3573275970Scy/*   5 short read from file */
3574275970Scyint
3575275970Scyevdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename) {
3576275970Scy	int res;
3577275970Scy	EVDNS_LOCK(base);
3578275970Scy	res = evdns_base_resolv_conf_parse_impl(base, flags, filename);
3579275970Scy	EVDNS_UNLOCK(base);
3580275970Scy	return res;
3581275970Scy}
3582275970Scy
3583275970Scystatic char *
3584275970Scyevdns_get_default_hosts_filename(void)
3585275970Scy{
3586275970Scy#ifdef _WIN32
3587275970Scy	/* Windows is a little coy about where it puts its configuration
3588275970Scy	 * files.  Sure, they're _usually_ in C:\windows\system32, but
3589275970Scy	 * there's no reason in principle they couldn't be in
3590275970Scy	 * W:\hoboken chicken emergency\
3591275970Scy	 */
3592275970Scy	char path[MAX_PATH+1];
3593275970Scy	static const char hostfile[] = "\\drivers\\etc\\hosts";
3594275970Scy	char *path_out;
3595275970Scy	size_t len_out;
3596275970Scy
3597275970Scy	if (! SHGetSpecialFolderPathA(NULL, path, CSIDL_SYSTEM, 0))
3598275970Scy		return NULL;
3599285612Sdelphij	len_out = strlen(path)+strlen(hostfile)+1;
3600285612Sdelphij	path_out = mm_malloc(len_out);
3601275970Scy	evutil_snprintf(path_out, len_out, "%s%s", path, hostfile);
3602275970Scy	return path_out;
3603275970Scy#else
3604275970Scy	return mm_strdup("/etc/hosts");
3605275970Scy#endif
3606275970Scy}
3607275970Scy
3608275970Scystatic int
3609275970Scyevdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) {
3610275970Scy	size_t n;
3611275970Scy	char *resolv;
3612275970Scy	char *start;
3613275970Scy	int err = 0;
3614275970Scy
3615275970Scy	log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
3616275970Scy
3617275970Scy	if (flags & DNS_OPTION_HOSTSFILE) {
3618275970Scy		char *fname = evdns_get_default_hosts_filename();
3619275970Scy		evdns_base_load_hosts(base, fname);
3620275970Scy		if (fname)
3621275970Scy			mm_free(fname);
3622275970Scy	}
3623275970Scy
3624275970Scy	if ((err = evutil_read_file_(filename, &resolv, &n, 0)) < 0) {
3625275970Scy		if (err == -1) {
3626275970Scy			/* No file. */
3627275970Scy			evdns_resolv_set_defaults(base, flags);
3628275970Scy			return 1;
3629275970Scy		} else {
3630275970Scy			return 2;
3631275970Scy		}
3632275970Scy	}
3633275970Scy
3634275970Scy	start = resolv;
3635275970Scy	for (;;) {
3636275970Scy		char *const newline = strchr(start, '\n');
3637275970Scy		if (!newline) {
3638275970Scy			resolv_conf_parse_line(base, start, flags);
3639275970Scy			break;
3640275970Scy		} else {
3641275970Scy			*newline = 0;
3642275970Scy			resolv_conf_parse_line(base, start, flags);
3643275970Scy			start = newline + 1;
3644275970Scy		}
3645275970Scy	}
3646275970Scy
3647275970Scy	if (!base->server_head && (flags & DNS_OPTION_NAMESERVERS)) {
3648275970Scy		/* no nameservers were configured. */
3649275970Scy		evdns_base_nameserver_ip_add(base, "127.0.0.1");
3650275970Scy		err = 6;
3651275970Scy	}
3652275970Scy	if (flags & DNS_OPTION_SEARCH && (!base->global_search_state || base->global_search_state->num_domains == 0)) {
3653275970Scy		search_set_from_hostname(base);
3654275970Scy	}
3655275970Scy
3656275970Scy	mm_free(resolv);
3657275970Scy	return err;
3658275970Scy}
3659275970Scy
3660275970Scyint
3661275970Scyevdns_resolv_conf_parse(int flags, const char *const filename) {
3662275970Scy	if (!current_base)
3663275970Scy		current_base = evdns_base_new(NULL, 0);
3664275970Scy	return evdns_base_resolv_conf_parse(current_base, flags, filename);
3665275970Scy}
3666275970Scy
3667275970Scy
3668275970Scy#ifdef _WIN32
3669275970Scy/* Add multiple nameservers from a space-or-comma-separated list. */
3670275970Scystatic int
3671275970Scyevdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
3672275970Scy	const char *addr;
3673275970Scy	char *buf;
3674275970Scy	int r;
3675275970Scy	ASSERT_LOCKED(base);
3676275970Scy	while (*ips) {
3677275970Scy		while (isspace(*ips) || *ips == ',' || *ips == '\t')
3678275970Scy			++ips;
3679275970Scy		addr = ips;
3680275970Scy		while (isdigit(*ips) || *ips == '.' || *ips == ':' ||
3681275970Scy		    *ips=='[' || *ips==']')
3682275970Scy			++ips;
3683275970Scy		buf = mm_malloc(ips-addr+1);
3684275970Scy		if (!buf) return 4;
3685275970Scy		memcpy(buf, addr, ips-addr);
3686275970Scy		buf[ips-addr] = '\0';
3687275970Scy		r = evdns_base_nameserver_ip_add(base, buf);
3688275970Scy		mm_free(buf);
3689275970Scy		if (r) return r;
3690275970Scy	}
3691275970Scy	return 0;
3692275970Scy}
3693275970Scy
3694275970Scytypedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
3695275970Scy
3696275970Scy/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
3697275970Scy/* figure out what our nameservers are. */
3698275970Scystatic int
3699275970Scyload_nameservers_with_getnetworkparams(struct evdns_base *base)
3700275970Scy{
3701275970Scy	/* Based on MSDN examples and inspection of  c-ares code. */
3702275970Scy	FIXED_INFO *fixed;
3703275970Scy	HMODULE handle = 0;
3704275970Scy	ULONG size = sizeof(FIXED_INFO);
3705275970Scy	void *buf = NULL;
3706275970Scy	int status = 0, r, added_any;
3707275970Scy	IP_ADDR_STRING *ns;
3708275970Scy	GetNetworkParams_fn_t fn;
3709275970Scy
3710275970Scy	ASSERT_LOCKED(base);
3711275970Scy	if (!(handle = evutil_load_windows_system_library_(
3712275970Scy			TEXT("iphlpapi.dll")))) {
3713275970Scy		log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
3714275970Scy		status = -1;
3715275970Scy		goto done;
3716275970Scy	}
3717275970Scy	if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
3718275970Scy		log(EVDNS_LOG_WARN, "Could not get address of function.");
3719275970Scy		status = -1;
3720275970Scy		goto done;
3721275970Scy	}
3722275970Scy
3723275970Scy	buf = mm_malloc(size);
3724275970Scy	if (!buf) { status = 4; goto done; }
3725275970Scy	fixed = buf;
3726275970Scy	r = fn(fixed, &size);
3727275970Scy	if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
3728275970Scy		status = -1;
3729275970Scy		goto done;
3730275970Scy	}
3731275970Scy	if (r != ERROR_SUCCESS) {
3732275970Scy		mm_free(buf);
3733275970Scy		buf = mm_malloc(size);
3734275970Scy		if (!buf) { status = 4; goto done; }
3735275970Scy		fixed = buf;
3736275970Scy		r = fn(fixed, &size);
3737275970Scy		if (r != ERROR_SUCCESS) {
3738275970Scy			log(EVDNS_LOG_DEBUG, "fn() failed.");
3739275970Scy			status = -1;
3740275970Scy			goto done;
3741275970Scy		}
3742275970Scy	}
3743275970Scy
3744275970Scy	EVUTIL_ASSERT(fixed);
3745275970Scy	added_any = 0;
3746275970Scy	ns = &(fixed->DnsServerList);
3747275970Scy	while (ns) {
3748275970Scy		r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String);
3749275970Scy		if (r) {
3750275970Scy			log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
3751275970Scy				(ns->IpAddress.String),(int)GetLastError());
3752275970Scy			status = r;
3753275970Scy		} else {
3754275970Scy			++added_any;
3755275970Scy			log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
3756275970Scy		}
3757275970Scy
3758275970Scy		ns = ns->Next;
3759275970Scy	}
3760275970Scy
3761275970Scy	if (!added_any) {
3762275970Scy		log(EVDNS_LOG_DEBUG, "No nameservers added.");
3763275970Scy		if (status == 0)
3764275970Scy			status = -1;
3765275970Scy	} else {
3766275970Scy		status = 0;
3767275970Scy	}
3768275970Scy
3769275970Scy done:
3770275970Scy	if (buf)
3771275970Scy		mm_free(buf);
3772275970Scy	if (handle)
3773275970Scy		FreeLibrary(handle);
3774275970Scy	return status;
3775275970Scy}
3776275970Scy
3777275970Scystatic int
3778275970Scyconfig_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey)
3779275970Scy{
3780275970Scy	char *buf;
3781275970Scy	DWORD bufsz = 0, type = 0;
3782275970Scy	int status = 0;
3783275970Scy
3784275970Scy	ASSERT_LOCKED(base);
3785275970Scy	if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
3786275970Scy	    != ERROR_MORE_DATA)
3787275970Scy		return -1;
3788275970Scy	if (!(buf = mm_malloc(bufsz)))
3789275970Scy		return -1;
3790275970Scy
3791275970Scy	if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
3792275970Scy	    == ERROR_SUCCESS && bufsz > 1) {
3793275970Scy		status = evdns_nameserver_ip_add_line(base,buf);
3794275970Scy	}
3795275970Scy
3796275970Scy	mm_free(buf);
3797275970Scy	return status;
3798275970Scy}
3799275970Scy
3800275970Scy#define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\")
3801275970Scy#define WIN_NS_9X_KEY  SERVICES_KEY TEXT("VxD\\MSTCP")
3802275970Scy#define WIN_NS_NT_KEY  SERVICES_KEY TEXT("Tcpip\\Parameters")
3803275970Scy
3804275970Scystatic int
3805275970Scyload_nameservers_from_registry(struct evdns_base *base)
3806275970Scy{
3807275970Scy	int found = 0;
3808275970Scy	int r;
3809275970Scy#define TRY(k, name) \
3810275970Scy	if (!found && config_nameserver_from_reg_key(base,k,TEXT(name)) == 0) { \
3811275970Scy		log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
3812275970Scy		found = 1;						\
3813275970Scy	} else if (!found) {						\
3814275970Scy		log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
3815275970Scy		    #k,#name);						\
3816275970Scy	}
3817275970Scy
3818275970Scy	ASSERT_LOCKED(base);
3819275970Scy
3820275970Scy	if (((int)GetVersion()) > 0) { /* NT */
3821275970Scy		HKEY nt_key = 0, interfaces_key = 0;
3822275970Scy
3823275970Scy		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
3824275970Scy				 KEY_READ, &nt_key) != ERROR_SUCCESS) {
3825275970Scy			log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
3826275970Scy			return -1;
3827275970Scy		}
3828275970Scy		r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0,
3829275970Scy			     KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
3830275970Scy			     &interfaces_key);
3831275970Scy		if (r != ERROR_SUCCESS) {
3832275970Scy			log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
3833275970Scy			return -1;
3834275970Scy		}
3835275970Scy		TRY(nt_key, "NameServer");
3836275970Scy		TRY(nt_key, "DhcpNameServer");
3837275970Scy		TRY(interfaces_key, "NameServer");
3838275970Scy		TRY(interfaces_key, "DhcpNameServer");
3839275970Scy		RegCloseKey(interfaces_key);
3840275970Scy		RegCloseKey(nt_key);
3841275970Scy	} else {
3842275970Scy		HKEY win_key = 0;
3843275970Scy		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
3844275970Scy				 KEY_READ, &win_key) != ERROR_SUCCESS) {
3845275970Scy			log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
3846275970Scy			return -1;
3847275970Scy		}
3848275970Scy		TRY(win_key, "NameServer");
3849275970Scy		RegCloseKey(win_key);
3850275970Scy	}
3851275970Scy
3852275970Scy	if (found == 0) {
3853275970Scy		log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
3854275970Scy	}
3855275970Scy
3856275970Scy	return found ? 0 : -1;
3857275970Scy#undef TRY
3858275970Scy}
3859275970Scy
3860275970Scyint
3861275970Scyevdns_base_config_windows_nameservers(struct evdns_base *base)
3862275970Scy{
3863275970Scy	int r;
3864275970Scy	char *fname;
3865275970Scy	if (base == NULL)
3866275970Scy		base = current_base;
3867275970Scy	if (base == NULL)
3868275970Scy		return -1;
3869275970Scy	EVDNS_LOCK(base);
3870285612Sdelphij	fname = evdns_get_default_hosts_filename();
3871285612Sdelphij	log(EVDNS_LOG_DEBUG, "Loading hosts entries from %s", fname);
3872285612Sdelphij	evdns_base_load_hosts(base, fname);
3873285612Sdelphij	if (fname)
3874285612Sdelphij		mm_free(fname);
3875285612Sdelphij
3876275970Scy	if (load_nameservers_with_getnetworkparams(base) == 0) {
3877275970Scy		EVDNS_UNLOCK(base);
3878275970Scy		return 0;
3879275970Scy	}
3880275970Scy	r = load_nameservers_from_registry(base);
3881275970Scy
3882275970Scy	EVDNS_UNLOCK(base);
3883275970Scy	return r;
3884275970Scy}
3885275970Scy
3886275970Scyint
3887275970Scyevdns_config_windows_nameservers(void)
3888275970Scy{
3889275970Scy	if (!current_base) {
3890275970Scy		current_base = evdns_base_new(NULL, 1);
3891275970Scy		return current_base == NULL ? -1 : 0;
3892275970Scy	} else {
3893275970Scy		return evdns_base_config_windows_nameservers(current_base);
3894275970Scy	}
3895275970Scy}
3896275970Scy#endif
3897275970Scy
3898275970Scystruct evdns_base *
3899275970Scyevdns_base_new(struct event_base *event_base, int flags)
3900275970Scy{
3901275970Scy	struct evdns_base *base;
3902275970Scy
3903275970Scy	if (evutil_secure_rng_init() < 0) {
3904275970Scy		log(EVDNS_LOG_WARN, "Unable to seed random number generator; "
3905275970Scy		    "DNS can't run.");
3906275970Scy		return NULL;
3907275970Scy	}
3908275970Scy
3909275970Scy	/* Give the evutil library a hook into its evdns-enabled
3910275970Scy	 * functionality.  We can't just call evdns_getaddrinfo directly or
3911275970Scy	 * else libevent-core will depend on libevent-extras. */
3912275970Scy	evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo);
3913275970Scy
3914275970Scy	base = mm_malloc(sizeof(struct evdns_base));
3915275970Scy	if (base == NULL)
3916275970Scy		return (NULL);
3917275970Scy	memset(base, 0, sizeof(struct evdns_base));
3918275970Scy	base->req_waiting_head = NULL;
3919275970Scy
3920275970Scy	EVTHREAD_ALLOC_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
3921275970Scy	EVDNS_LOCK(base);
3922275970Scy
3923275970Scy	/* Set max requests inflight and allocate req_heads. */
3924275970Scy	base->req_heads = NULL;
3925275970Scy
3926275970Scy	evdns_base_set_max_requests_inflight(base, 64);
3927275970Scy
3928275970Scy	base->server_head = NULL;
3929275970Scy	base->event_base = event_base;
3930275970Scy	base->global_good_nameservers = base->global_requests_inflight =
3931275970Scy		base->global_requests_waiting = 0;
3932275970Scy
3933275970Scy	base->global_timeout.tv_sec = 5;
3934275970Scy	base->global_timeout.tv_usec = 0;
3935275970Scy	base->global_max_reissues = 1;
3936275970Scy	base->global_max_retransmits = 3;
3937275970Scy	base->global_max_nameserver_timeout = 3;
3938275970Scy	base->global_search_state = NULL;
3939275970Scy	base->global_randomize_case = 1;
3940275970Scy	base->global_getaddrinfo_allow_skew.tv_sec = 3;
3941275970Scy	base->global_getaddrinfo_allow_skew.tv_usec = 0;
3942275970Scy	base->global_nameserver_probe_initial_timeout.tv_sec = 10;
3943275970Scy	base->global_nameserver_probe_initial_timeout.tv_usec = 0;
3944275970Scy
3945275970Scy	TAILQ_INIT(&base->hostsdb);
3946275970Scy
3947275970Scy#define EVDNS_BASE_ALL_FLAGS (0x8001)
3948275970Scy	if (flags & ~EVDNS_BASE_ALL_FLAGS) {
3949275970Scy		flags = EVDNS_BASE_INITIALIZE_NAMESERVERS;
3950275970Scy		log(EVDNS_LOG_WARN,
3951275970Scy		    "Unrecognized flag passed to evdns_base_new(). Assuming "
3952275970Scy		    "you meant EVDNS_BASE_INITIALIZE_NAMESERVERS.");
3953275970Scy	}
3954275970Scy#undef EVDNS_BASE_ALL_FLAGS
3955275970Scy
3956275970Scy	if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) {
3957275970Scy		int r;
3958275970Scy#ifdef _WIN32
3959275970Scy		r = evdns_base_config_windows_nameservers(base);
3960275970Scy#else
3961275970Scy		r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
3962275970Scy#endif
3963275970Scy		if (r == -1) {
3964275970Scy			evdns_base_free_and_unlock(base, 0);
3965275970Scy			return NULL;
3966275970Scy		}
3967275970Scy	}
3968275970Scy	if (flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE) {
3969275970Scy		base->disable_when_inactive = 1;
3970275970Scy	}
3971275970Scy
3972275970Scy	EVDNS_UNLOCK(base);
3973275970Scy	return base;
3974275970Scy}
3975275970Scy
3976275970Scyint
3977275970Scyevdns_init(void)
3978275970Scy{
3979275970Scy	struct evdns_base *base = evdns_base_new(NULL, 1);
3980275970Scy	if (base) {
3981275970Scy		current_base = base;
3982275970Scy		return 0;
3983275970Scy	} else {
3984275970Scy		return -1;
3985275970Scy	}
3986275970Scy}
3987275970Scy
3988275970Scyconst char *
3989275970Scyevdns_err_to_string(int err)
3990275970Scy{
3991275970Scy    switch (err) {
3992275970Scy	case DNS_ERR_NONE: return "no error";
3993275970Scy	case DNS_ERR_FORMAT: return "misformatted query";
3994275970Scy	case DNS_ERR_SERVERFAILED: return "server failed";
3995275970Scy	case DNS_ERR_NOTEXIST: return "name does not exist";
3996275970Scy	case DNS_ERR_NOTIMPL: return "query not implemented";
3997275970Scy	case DNS_ERR_REFUSED: return "refused";
3998275970Scy
3999275970Scy	case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
4000275970Scy	case DNS_ERR_UNKNOWN: return "unknown";
4001275970Scy	case DNS_ERR_TIMEOUT: return "request timed out";
4002275970Scy	case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
4003275970Scy	case DNS_ERR_CANCEL: return "dns request canceled";
4004275970Scy	case DNS_ERR_NODATA: return "no records in the reply";
4005275970Scy	default: return "[Unknown error code]";
4006275970Scy    }
4007275970Scy}
4008275970Scy
4009275970Scystatic void
4010275970Scyevdns_nameserver_free(struct nameserver *server)
4011275970Scy{
4012275970Scy	if (server->socket >= 0)
4013275970Scy	evutil_closesocket(server->socket);
4014275970Scy	(void) event_del(&server->event);
4015275970Scy	event_debug_unassign(&server->event);
4016275970Scy	if (server->state == 0)
4017275970Scy		(void) event_del(&server->timeout_event);
4018285612Sdelphij	if (server->probe_request) {
4019285612Sdelphij		evdns_cancel_request(server->base, server->probe_request);
4020285612Sdelphij		server->probe_request = NULL;
4021285612Sdelphij	}
4022275970Scy	event_debug_unassign(&server->timeout_event);
4023275970Scy	mm_free(server);
4024275970Scy}
4025275970Scy
4026275970Scystatic void
4027275970Scyevdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
4028275970Scy{
4029275970Scy	struct nameserver *server, *server_next;
4030275970Scy	struct search_domain *dom, *dom_next;
4031275970Scy	int i;
4032275970Scy
4033275970Scy	/* Requires that we hold the lock. */
4034275970Scy
4035275970Scy	/* TODO(nickm) we might need to refcount here. */
4036275970Scy
4037285612Sdelphij	for (server = base->server_head; server; server = server_next) {
4038285612Sdelphij		server_next = server->next;
4039285612Sdelphij		evdns_nameserver_free(server);
4040285612Sdelphij		if (server_next == base->server_head)
4041285612Sdelphij			break;
4042285612Sdelphij	}
4043285612Sdelphij	base->server_head = NULL;
4044285612Sdelphij	base->global_good_nameservers = 0;
4045285612Sdelphij
4046275970Scy	for (i = 0; i < base->n_req_heads; ++i) {
4047275970Scy		while (base->req_heads[i]) {
4048275970Scy			if (fail_requests)
4049275970Scy				reply_schedule_callback(base->req_heads[i], 0, DNS_ERR_SHUTDOWN, NULL);
4050275970Scy			request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1);
4051275970Scy		}
4052275970Scy	}
4053275970Scy	while (base->req_waiting_head) {
4054275970Scy		if (fail_requests)
4055275970Scy			reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
4056275970Scy		request_finished(base->req_waiting_head, &base->req_waiting_head, 1);
4057275970Scy	}
4058275970Scy	base->global_requests_inflight = base->global_requests_waiting = 0;
4059275970Scy
4060275970Scy
4061275970Scy	if (base->global_search_state) {
4062275970Scy		for (dom = base->global_search_state->head; dom; dom = dom_next) {
4063275970Scy			dom_next = dom->next;
4064275970Scy			mm_free(dom);
4065275970Scy		}
4066275970Scy		mm_free(base->global_search_state);
4067275970Scy		base->global_search_state = NULL;
4068275970Scy	}
4069275970Scy
4070275970Scy	{
4071275970Scy		struct hosts_entry *victim;
4072275970Scy		while ((victim = TAILQ_FIRST(&base->hostsdb))) {
4073275970Scy			TAILQ_REMOVE(&base->hostsdb, victim, next);
4074275970Scy			mm_free(victim);
4075275970Scy		}
4076275970Scy	}
4077275970Scy
4078275970Scy	mm_free(base->req_heads);
4079275970Scy
4080275970Scy	EVDNS_UNLOCK(base);
4081275970Scy	EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
4082275970Scy
4083275970Scy	mm_free(base);
4084275970Scy}
4085275970Scy
4086275970Scyvoid
4087275970Scyevdns_base_free(struct evdns_base *base, int fail_requests)
4088275970Scy{
4089275970Scy	EVDNS_LOCK(base);
4090275970Scy	evdns_base_free_and_unlock(base, fail_requests);
4091275970Scy}
4092275970Scy
4093275970Scyvoid
4094275970Scyevdns_base_clear_host_addresses(struct evdns_base *base)
4095275970Scy{
4096275970Scy	struct hosts_entry *victim;
4097275970Scy	EVDNS_LOCK(base);
4098275970Scy	while ((victim = TAILQ_FIRST(&base->hostsdb))) {
4099275970Scy		TAILQ_REMOVE(&base->hostsdb, victim, next);
4100275970Scy		mm_free(victim);
4101275970Scy	}
4102275970Scy	EVDNS_UNLOCK(base);
4103275970Scy}
4104275970Scy
4105275970Scyvoid
4106275970Scyevdns_shutdown(int fail_requests)
4107275970Scy{
4108275970Scy	if (current_base) {
4109275970Scy		struct evdns_base *b = current_base;
4110275970Scy		current_base = NULL;
4111275970Scy		evdns_base_free(b, fail_requests);
4112275970Scy	}
4113275970Scy	evdns_log_fn = NULL;
4114275970Scy}
4115275970Scy
4116275970Scystatic int
4117275970Scyevdns_base_parse_hosts_line(struct evdns_base *base, char *line)
4118275970Scy{
4119275970Scy	char *strtok_state;
4120275970Scy	static const char *const delims = " \t";
4121275970Scy	char *const addr = strtok_r(line, delims, &strtok_state);
4122275970Scy	char *hostname, *hash;
4123275970Scy	struct sockaddr_storage ss;
4124275970Scy	int socklen = sizeof(ss);
4125275970Scy	ASSERT_LOCKED(base);
4126275970Scy
4127275970Scy#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
4128275970Scy
4129275970Scy	if (!addr || *addr == '#')
4130275970Scy		return 0;
4131275970Scy
4132275970Scy	memset(&ss, 0, sizeof(ss));
4133275970Scy	if (evutil_parse_sockaddr_port(addr, (struct sockaddr*)&ss, &socklen)<0)
4134275970Scy		return -1;
4135275970Scy	if (socklen > (int)sizeof(struct sockaddr_in6))
4136275970Scy		return -1;
4137275970Scy
4138275970Scy	if (sockaddr_getport((struct sockaddr*)&ss))
4139275970Scy		return -1;
4140275970Scy
4141275970Scy	while ((hostname = NEXT_TOKEN)) {
4142275970Scy		struct hosts_entry *he;
4143275970Scy		size_t namelen;
4144275970Scy		if ((hash = strchr(hostname, '#'))) {
4145275970Scy			if (hash == hostname)
4146275970Scy				return 0;
4147275970Scy			*hash = '\0';
4148275970Scy		}
4149275970Scy
4150275970Scy		namelen = strlen(hostname);
4151275970Scy
4152275970Scy		he = mm_calloc(1, sizeof(struct hosts_entry)+namelen);
4153275970Scy		if (!he)
4154275970Scy			return -1;
4155275970Scy		EVUTIL_ASSERT(socklen <= (int)sizeof(he->addr));
4156275970Scy		memcpy(&he->addr, &ss, socklen);
4157275970Scy		memcpy(he->hostname, hostname, namelen+1);
4158275970Scy		he->addrlen = socklen;
4159275970Scy
4160275970Scy		TAILQ_INSERT_TAIL(&base->hostsdb, he, next);
4161275970Scy
4162275970Scy		if (hash)
4163275970Scy			return 0;
4164275970Scy	}
4165275970Scy
4166275970Scy	return 0;
4167275970Scy#undef NEXT_TOKEN
4168275970Scy}
4169275970Scy
4170275970Scystatic int
4171275970Scyevdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname)
4172275970Scy{
4173275970Scy	char *str=NULL, *cp, *eol;
4174275970Scy	size_t len;
4175275970Scy	int err=0;
4176275970Scy
4177275970Scy	ASSERT_LOCKED(base);
4178275970Scy
4179275970Scy	if (hosts_fname == NULL ||
4180275970Scy	    (err = evutil_read_file_(hosts_fname, &str, &len, 0)) < 0) {
4181275970Scy		char tmp[64];
4182275970Scy		strlcpy(tmp, "127.0.0.1   localhost", sizeof(tmp));
4183275970Scy		evdns_base_parse_hosts_line(base, tmp);
4184275970Scy		strlcpy(tmp, "::1   localhost", sizeof(tmp));
4185275970Scy		evdns_base_parse_hosts_line(base, tmp);
4186275970Scy		return err ? -1 : 0;
4187275970Scy	}
4188275970Scy
4189275970Scy	/* This will break early if there is a NUL in the hosts file.
4190275970Scy	 * Probably not a problem.*/
4191275970Scy	cp = str;
4192275970Scy	for (;;) {
4193275970Scy		eol = strchr(cp, '\n');
4194275970Scy
4195275970Scy		if (eol) {
4196275970Scy			*eol = '\0';
4197275970Scy			evdns_base_parse_hosts_line(base, cp);
4198275970Scy			cp = eol+1;
4199275970Scy		} else {
4200275970Scy			evdns_base_parse_hosts_line(base, cp);
4201275970Scy			break;
4202275970Scy		}
4203275970Scy	}
4204275970Scy
4205275970Scy	mm_free(str);
4206275970Scy	return 0;
4207275970Scy}
4208275970Scy
4209275970Scyint
4210275970Scyevdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname)
4211275970Scy{
4212275970Scy	int res;
4213275970Scy	if (!base)
4214275970Scy		base = current_base;
4215275970Scy	EVDNS_LOCK(base);
4216275970Scy	res = evdns_base_load_hosts_impl(base, hosts_fname);
4217275970Scy	EVDNS_UNLOCK(base);
4218275970Scy	return res;
4219275970Scy}
4220275970Scy
4221275970Scy/* A single request for a getaddrinfo, either v4 or v6. */
4222275970Scystruct getaddrinfo_subrequest {
4223275970Scy	struct evdns_request *r;
4224275970Scy	ev_uint32_t type;
4225275970Scy};
4226275970Scy
4227275970Scy/* State data used to implement an in-progress getaddrinfo. */
4228275970Scystruct evdns_getaddrinfo_request {
4229275970Scy	struct evdns_base *evdns_base;
4230275970Scy	/* Copy of the modified 'hints' data that we'll use to build
4231275970Scy	 * answers. */
4232275970Scy	struct evutil_addrinfo hints;
4233275970Scy	/* The callback to invoke when we're done */
4234275970Scy	evdns_getaddrinfo_cb user_cb;
4235275970Scy	/* User-supplied data to give to the callback. */
4236275970Scy	void *user_data;
4237275970Scy	/* The port to use when building sockaddrs. */
4238275970Scy	ev_uint16_t port;
4239275970Scy	/* The sub_request for an A record (if any) */
4240275970Scy	struct getaddrinfo_subrequest ipv4_request;
4241275970Scy	/* The sub_request for an AAAA record (if any) */
4242275970Scy	struct getaddrinfo_subrequest ipv6_request;
4243275970Scy
4244275970Scy	/* The cname result that we were told (if any) */
4245275970Scy	char *cname_result;
4246275970Scy
4247275970Scy	/* If we have one request answered and one request still inflight,
4248275970Scy	 * then this field holds the answer from the first request... */
4249275970Scy	struct evutil_addrinfo *pending_result;
4250275970Scy	/* And this event is a timeout that will tell us to cancel the second
4251275970Scy	 * request if it's taking a long time. */
4252275970Scy	struct event timeout;
4253275970Scy
4254275970Scy	/* And this field holds the error code from the first request... */
4255275970Scy	int pending_error;
4256275970Scy	/* If this is set, the user canceled this request. */
4257275970Scy	unsigned user_canceled : 1;
4258275970Scy	/* If this is set, the user can no longer cancel this request; we're
4259275970Scy	 * just waiting for the free. */
4260275970Scy	unsigned request_done : 1;
4261275970Scy};
4262275970Scy
4263275970Scy/* Convert an evdns errors to the equivalent getaddrinfo error. */
4264275970Scystatic int
4265275970Scyevdns_err_to_getaddrinfo_err(int e1)
4266275970Scy{
4267275970Scy	/* XXX Do this better! */
4268275970Scy	if (e1 == DNS_ERR_NONE)
4269275970Scy		return 0;
4270275970Scy	else if (e1 == DNS_ERR_NOTEXIST)
4271275970Scy		return EVUTIL_EAI_NONAME;
4272275970Scy	else
4273275970Scy		return EVUTIL_EAI_FAIL;
4274275970Scy}
4275275970Scy
4276275970Scy/* Return the more informative of two getaddrinfo errors. */
4277275970Scystatic int
4278275970Scygetaddrinfo_merge_err(int e1, int e2)
4279275970Scy{
4280275970Scy	/* XXXX be cleverer here. */
4281275970Scy	if (e1 == 0)
4282275970Scy		return e2;
4283275970Scy	else
4284275970Scy		return e1;
4285275970Scy}
4286275970Scy
4287275970Scystatic void
4288275970Scyfree_getaddrinfo_request(struct evdns_getaddrinfo_request *data)
4289275970Scy{
4290275970Scy	/* DO NOT CALL this if either of the requests is pending.  Only once
4291275970Scy	 * both callbacks have been invoked is it safe to free the request */
4292275970Scy	if (data->pending_result)
4293275970Scy		evutil_freeaddrinfo(data->pending_result);
4294275970Scy	if (data->cname_result)
4295275970Scy		mm_free(data->cname_result);
4296275970Scy	event_del(&data->timeout);
4297275970Scy	mm_free(data);
4298275970Scy	return;
4299275970Scy}
4300275970Scy
4301275970Scystatic void
4302275970Scyadd_cname_to_reply(struct evdns_getaddrinfo_request *data,
4303275970Scy    struct evutil_addrinfo *ai)
4304275970Scy{
4305275970Scy	if (data->cname_result && ai) {
4306275970Scy		ai->ai_canonname = data->cname_result;
4307275970Scy		data->cname_result = NULL;
4308275970Scy	}
4309275970Scy}
4310275970Scy
4311275970Scy/* Callback: invoked when one request in a mixed-format A/AAAA getaddrinfo
4312275970Scy * request has finished, but the other one took too long to answer. Pass
4313275970Scy * along the answer we got, and cancel the other request.
4314275970Scy */
4315275970Scystatic void
4316275970Scyevdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr)
4317275970Scy{
4318275970Scy	int v4_timedout = 0, v6_timedout = 0;
4319275970Scy	struct evdns_getaddrinfo_request *data = ptr;
4320275970Scy
4321275970Scy	/* Cancel any pending requests, and note which one */
4322275970Scy	if (data->ipv4_request.r) {
4323275970Scy		/* XXXX This does nothing if the request's callback is already
4324275970Scy		 * running (pending_cb is set). */
4325275970Scy		evdns_cancel_request(NULL, data->ipv4_request.r);
4326275970Scy		v4_timedout = 1;
4327275970Scy		EVDNS_LOCK(data->evdns_base);
4328275970Scy		++data->evdns_base->getaddrinfo_ipv4_timeouts;
4329275970Scy		EVDNS_UNLOCK(data->evdns_base);
4330275970Scy	}
4331275970Scy	if (data->ipv6_request.r) {
4332275970Scy		/* XXXX This does nothing if the request's callback is already
4333275970Scy		 * running (pending_cb is set). */
4334275970Scy		evdns_cancel_request(NULL, data->ipv6_request.r);
4335275970Scy		v6_timedout = 1;
4336275970Scy		EVDNS_LOCK(data->evdns_base);
4337275970Scy		++data->evdns_base->getaddrinfo_ipv6_timeouts;
4338275970Scy		EVDNS_UNLOCK(data->evdns_base);
4339275970Scy	}
4340275970Scy
4341275970Scy	/* We only use this timeout callback when we have an answer for
4342275970Scy	 * one address. */
4343275970Scy	EVUTIL_ASSERT(!v4_timedout || !v6_timedout);
4344275970Scy
4345275970Scy	/* Report the outcome of the other request that didn't time out. */
4346275970Scy	if (data->pending_result) {
4347275970Scy		add_cname_to_reply(data, data->pending_result);
4348275970Scy		data->user_cb(0, data->pending_result, data->user_data);
4349275970Scy		data->pending_result = NULL;
4350275970Scy	} else {
4351275970Scy		int e = data->pending_error;
4352275970Scy		if (!e)
4353275970Scy			e = EVUTIL_EAI_AGAIN;
4354275970Scy		data->user_cb(e, NULL, data->user_data);
4355275970Scy	}
4356275970Scy
4357275970Scy	data->user_cb = NULL; /* prevent double-call if evdns callbacks are
4358275970Scy			       * in-progress. XXXX It would be better if this
4359275970Scy			       * weren't necessary. */
4360275970Scy
4361275970Scy	if (!v4_timedout && !v6_timedout) {
4362275970Scy		/* should be impossible? XXXX */
4363275970Scy		free_getaddrinfo_request(data);
4364275970Scy	}
4365275970Scy}
4366275970Scy
4367275970Scystatic int
4368275970Scyevdns_getaddrinfo_set_timeout(struct evdns_base *evdns_base,
4369275970Scy    struct evdns_getaddrinfo_request *data)
4370275970Scy{
4371275970Scy	return event_add(&data->timeout, &evdns_base->global_getaddrinfo_allow_skew);
4372275970Scy}
4373275970Scy
4374275970Scystatic inline int
4375275970Scyevdns_result_is_answer(int result)
4376275970Scy{
4377275970Scy	return (result != DNS_ERR_NOTIMPL && result != DNS_ERR_REFUSED &&
4378275970Scy	    result != DNS_ERR_SERVERFAILED && result != DNS_ERR_CANCEL);
4379275970Scy}
4380275970Scy
4381275970Scystatic void
4382275970Scyevdns_getaddrinfo_gotresolve(int result, char type, int count,
4383275970Scy    int ttl, void *addresses, void *arg)
4384275970Scy{
4385275970Scy	int i;
4386275970Scy	struct getaddrinfo_subrequest *req = arg;
4387275970Scy	struct getaddrinfo_subrequest *other_req;
4388275970Scy	struct evdns_getaddrinfo_request *data;
4389275970Scy
4390275970Scy	struct evutil_addrinfo *res;
4391275970Scy
4392275970Scy	struct sockaddr_in sin;
4393275970Scy	struct sockaddr_in6 sin6;
4394275970Scy	struct sockaddr *sa;
4395275970Scy	int socklen, addrlen;
4396275970Scy	void *addrp;
4397275970Scy	int err;
4398275970Scy	int user_canceled;
4399275970Scy
4400275970Scy	EVUTIL_ASSERT(req->type == DNS_IPv4_A || req->type == DNS_IPv6_AAAA);
4401275970Scy	if (req->type == DNS_IPv4_A) {
4402275970Scy		data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv4_request);
4403275970Scy		other_req = &data->ipv6_request;
4404275970Scy	} else {
4405275970Scy		data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv6_request);
4406275970Scy		other_req = &data->ipv4_request;
4407275970Scy	}
4408275970Scy
4409275970Scy	EVDNS_LOCK(data->evdns_base);
4410275970Scy	if (evdns_result_is_answer(result)) {
4411275970Scy		if (req->type == DNS_IPv4_A)
4412275970Scy			++data->evdns_base->getaddrinfo_ipv4_answered;
4413275970Scy		else
4414275970Scy			++data->evdns_base->getaddrinfo_ipv6_answered;
4415275970Scy	}
4416275970Scy	user_canceled = data->user_canceled;
4417275970Scy	if (other_req->r == NULL)
4418275970Scy		data->request_done = 1;
4419275970Scy	EVDNS_UNLOCK(data->evdns_base);
4420275970Scy
4421275970Scy	req->r = NULL;
4422275970Scy
4423275970Scy	if (result == DNS_ERR_CANCEL && ! user_canceled) {
4424275970Scy		/* Internal cancel request from timeout or internal error.
4425275970Scy		 * we already answered the user. */
4426275970Scy		if (other_req->r == NULL)
4427275970Scy			free_getaddrinfo_request(data);
4428275970Scy		return;
4429275970Scy	}
4430275970Scy
4431275970Scy	if (data->user_cb == NULL) {
4432275970Scy		/* We already answered.  XXXX This shouldn't be needed; see
4433275970Scy		 * comments in evdns_getaddrinfo_timeout_cb */
4434275970Scy		free_getaddrinfo_request(data);
4435275970Scy		return;
4436275970Scy	}
4437275970Scy
4438275970Scy	if (result == DNS_ERR_NONE) {
4439275970Scy		if (count == 0)
4440275970Scy			err = EVUTIL_EAI_NODATA;
4441275970Scy		else
4442275970Scy			err = 0;
4443275970Scy	} else {
4444275970Scy		err = evdns_err_to_getaddrinfo_err(result);
4445275970Scy	}
4446275970Scy
4447275970Scy	if (err) {
4448275970Scy		/* Looks like we got an error. */
4449275970Scy		if (other_req->r) {
4450275970Scy			/* The other request is still working; maybe it will
4451275970Scy			 * succeed. */
4452275970Scy			/* XXXX handle failure from set_timeout */
4453275970Scy			evdns_getaddrinfo_set_timeout(data->evdns_base, data);
4454275970Scy			data->pending_error = err;
4455275970Scy			return;
4456275970Scy		}
4457275970Scy
4458275970Scy		if (user_canceled) {
4459275970Scy			data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
4460275970Scy		} else if (data->pending_result) {
4461275970Scy			/* If we have an answer waiting, and we weren't
4462275970Scy			 * canceled, ignore this error. */
4463275970Scy			add_cname_to_reply(data, data->pending_result);
4464275970Scy			data->user_cb(0, data->pending_result, data->user_data);
4465275970Scy			data->pending_result = NULL;
4466275970Scy		} else {
4467275970Scy			if (data->pending_error)
4468275970Scy				err = getaddrinfo_merge_err(err,
4469275970Scy				    data->pending_error);
4470275970Scy			data->user_cb(err, NULL, data->user_data);
4471275970Scy		}
4472275970Scy		free_getaddrinfo_request(data);
4473275970Scy		return;
4474275970Scy	} else if (user_canceled) {
4475275970Scy		if (other_req->r) {
4476275970Scy			/* The other request is still working; let it hit this
4477275970Scy			 * callback with EVUTIL_EAI_CANCEL callback and report
4478275970Scy			 * the failure. */
4479275970Scy			return;
4480275970Scy		}
4481275970Scy		data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
4482275970Scy		free_getaddrinfo_request(data);
4483275970Scy		return;
4484275970Scy	}
4485275970Scy
4486275970Scy	/* Looks like we got some answers. We should turn them into addrinfos
4487275970Scy	 * and then either queue those or return them all. */
4488275970Scy	EVUTIL_ASSERT(type == DNS_IPv4_A || type == DNS_IPv6_AAAA);
4489275970Scy
4490275970Scy	if (type == DNS_IPv4_A) {
4491275970Scy		memset(&sin, 0, sizeof(sin));
4492275970Scy		sin.sin_family = AF_INET;
4493275970Scy		sin.sin_port = htons(data->port);
4494275970Scy
4495275970Scy		sa = (struct sockaddr *)&sin;
4496275970Scy		socklen = sizeof(sin);
4497275970Scy		addrlen = 4;
4498275970Scy		addrp = &sin.sin_addr.s_addr;
4499275970Scy	} else {
4500275970Scy		memset(&sin6, 0, sizeof(sin6));
4501275970Scy		sin6.sin6_family = AF_INET6;
4502275970Scy		sin6.sin6_port = htons(data->port);
4503275970Scy
4504275970Scy		sa = (struct sockaddr *)&sin6;
4505275970Scy		socklen = sizeof(sin6);
4506275970Scy		addrlen = 16;
4507275970Scy		addrp = &sin6.sin6_addr.s6_addr;
4508275970Scy	}
4509275970Scy
4510275970Scy	res = NULL;
4511275970Scy	for (i=0; i < count; ++i) {
4512275970Scy		struct evutil_addrinfo *ai;
4513275970Scy		memcpy(addrp, ((char*)addresses)+i*addrlen, addrlen);
4514275970Scy		ai = evutil_new_addrinfo_(sa, socklen, &data->hints);
4515275970Scy		if (!ai) {
4516275970Scy			if (other_req->r) {
4517275970Scy				evdns_cancel_request(NULL, other_req->r);
4518275970Scy			}
4519275970Scy			data->user_cb(EVUTIL_EAI_MEMORY, NULL, data->user_data);
4520275970Scy			if (res)
4521275970Scy				evutil_freeaddrinfo(res);
4522275970Scy
4523275970Scy			if (other_req->r == NULL)
4524275970Scy				free_getaddrinfo_request(data);
4525275970Scy			return;
4526275970Scy		}
4527275970Scy		res = evutil_addrinfo_append_(res, ai);
4528275970Scy	}
4529275970Scy
4530275970Scy	if (other_req->r) {
4531275970Scy		/* The other request is still in progress; wait for it */
4532275970Scy		/* XXXX handle failure from set_timeout */
4533275970Scy		evdns_getaddrinfo_set_timeout(data->evdns_base, data);
4534275970Scy		data->pending_result = res;
4535275970Scy		return;
4536275970Scy	} else {
4537275970Scy		/* The other request is done or never started; append its
4538275970Scy		 * results (if any) and return them. */
4539275970Scy		if (data->pending_result) {
4540275970Scy			if (req->type == DNS_IPv4_A)
4541275970Scy				res = evutil_addrinfo_append_(res,
4542275970Scy				    data->pending_result);
4543275970Scy			else
4544275970Scy				res = evutil_addrinfo_append_(
4545275970Scy				    data->pending_result, res);
4546275970Scy			data->pending_result = NULL;
4547275970Scy		}
4548275970Scy
4549275970Scy		/* Call the user callback. */
4550275970Scy		add_cname_to_reply(data, res);
4551275970Scy		data->user_cb(0, res, data->user_data);
4552275970Scy
4553275970Scy		/* Free data. */
4554275970Scy		free_getaddrinfo_request(data);
4555275970Scy	}
4556275970Scy}
4557275970Scy
4558275970Scystatic struct hosts_entry *
4559275970Scyfind_hosts_entry(struct evdns_base *base, const char *hostname,
4560275970Scy    struct hosts_entry *find_after)
4561275970Scy{
4562275970Scy	struct hosts_entry *e;
4563275970Scy
4564275970Scy	if (find_after)
4565275970Scy		e = TAILQ_NEXT(find_after, next);
4566275970Scy	else
4567275970Scy		e = TAILQ_FIRST(&base->hostsdb);
4568275970Scy
4569275970Scy	for (; e; e = TAILQ_NEXT(e, next)) {
4570275970Scy		if (!evutil_ascii_strcasecmp(e->hostname, hostname))
4571275970Scy			return e;
4572275970Scy	}
4573275970Scy	return NULL;
4574275970Scy}
4575275970Scy
4576275970Scystatic int
4577275970Scyevdns_getaddrinfo_fromhosts(struct evdns_base *base,
4578275970Scy    const char *nodename, struct evutil_addrinfo *hints, ev_uint16_t port,
4579275970Scy    struct evutil_addrinfo **res)
4580275970Scy{
4581275970Scy	int n_found = 0;
4582275970Scy	struct hosts_entry *e;
4583275970Scy	struct evutil_addrinfo *ai=NULL;
4584275970Scy	int f = hints->ai_family;
4585275970Scy
4586275970Scy	EVDNS_LOCK(base);
4587275970Scy	for (e = find_hosts_entry(base, nodename, NULL); e;
4588275970Scy	    e = find_hosts_entry(base, nodename, e)) {
4589275970Scy		struct evutil_addrinfo *ai_new;
4590275970Scy		++n_found;
4591275970Scy		if ((e->addr.sa.sa_family == AF_INET && f == PF_INET6) ||
4592275970Scy		    (e->addr.sa.sa_family == AF_INET6 && f == PF_INET))
4593275970Scy			continue;
4594275970Scy		ai_new = evutil_new_addrinfo_(&e->addr.sa, e->addrlen, hints);
4595275970Scy		if (!ai_new) {
4596275970Scy			n_found = 0;
4597275970Scy			goto out;
4598275970Scy		}
4599275970Scy		sockaddr_setport(ai_new->ai_addr, port);
4600275970Scy		ai = evutil_addrinfo_append_(ai, ai_new);
4601275970Scy	}
4602275970Scy	EVDNS_UNLOCK(base);
4603275970Scyout:
4604275970Scy	if (n_found) {
4605275970Scy		/* Note that we return an empty answer if we found entries for
4606275970Scy		 * this hostname but none were of the right address type. */
4607275970Scy		*res = ai;
4608275970Scy		return 0;
4609275970Scy	} else {
4610275970Scy		if (ai)
4611275970Scy			evutil_freeaddrinfo(ai);
4612275970Scy		return -1;
4613275970Scy	}
4614275970Scy}
4615275970Scy
4616275970Scystruct evdns_getaddrinfo_request *
4617275970Scyevdns_getaddrinfo(struct evdns_base *dns_base,
4618275970Scy    const char *nodename, const char *servname,
4619275970Scy    const struct evutil_addrinfo *hints_in,
4620275970Scy    evdns_getaddrinfo_cb cb, void *arg)
4621275970Scy{
4622275970Scy	struct evdns_getaddrinfo_request *data;
4623275970Scy	struct evutil_addrinfo hints;
4624275970Scy	struct evutil_addrinfo *res = NULL;
4625275970Scy	int err;
4626275970Scy	int port = 0;
4627275970Scy	int want_cname = 0;
4628275970Scy
4629275970Scy	if (!dns_base) {
4630275970Scy		dns_base = current_base;
4631275970Scy		if (!dns_base) {
4632275970Scy			log(EVDNS_LOG_WARN,
4633275970Scy			    "Call to getaddrinfo_async with no "
4634275970Scy			    "evdns_base configured.");
4635275970Scy			cb(EVUTIL_EAI_FAIL, NULL, arg); /* ??? better error? */
4636275970Scy			return NULL;
4637275970Scy		}
4638275970Scy	}
4639275970Scy
4640275970Scy	/* If we _must_ answer this immediately, do so. */
4641275970Scy	if ((hints_in && (hints_in->ai_flags & EVUTIL_AI_NUMERICHOST))) {
4642275970Scy		res = NULL;
4643275970Scy		err = evutil_getaddrinfo(nodename, servname, hints_in, &res);
4644275970Scy		cb(err, res, arg);
4645275970Scy		return NULL;
4646275970Scy	}
4647275970Scy
4648275970Scy	if (hints_in) {
4649275970Scy		memcpy(&hints, hints_in, sizeof(hints));
4650275970Scy	} else {
4651275970Scy		memset(&hints, 0, sizeof(hints));
4652275970Scy		hints.ai_family = PF_UNSPEC;
4653275970Scy	}
4654275970Scy
4655275970Scy	evutil_adjust_hints_for_addrconfig_(&hints);
4656275970Scy
4657275970Scy	/* Now try to see if we _can_ answer immediately. */
4658275970Scy	/* (It would be nice to do this by calling getaddrinfo directly, with
4659275970Scy	 * AI_NUMERICHOST, on plaforms that have it, but we can't: there isn't
4660275970Scy	 * a reliable way to distinguish the "that wasn't a numeric host!" case
4661275970Scy	 * from any other EAI_NONAME cases.) */
4662275970Scy	err = evutil_getaddrinfo_common_(nodename, servname, &hints, &res, &port);
4663275970Scy	if (err != EVUTIL_EAI_NEED_RESOLVE) {
4664275970Scy		cb(err, res, arg);
4665275970Scy		return NULL;
4666275970Scy	}
4667275970Scy
4668275970Scy	/* If there is an entry in the hosts file, we should give it now. */
4669275970Scy	if (!evdns_getaddrinfo_fromhosts(dns_base, nodename, &hints, port, &res)) {
4670275970Scy		cb(0, res, arg);
4671275970Scy		return NULL;
4672275970Scy	}
4673275970Scy
4674275970Scy	/* Okay, things are serious now. We're going to need to actually
4675275970Scy	 * launch a request.
4676275970Scy	 */
4677275970Scy	data = mm_calloc(1,sizeof(struct evdns_getaddrinfo_request));
4678275970Scy	if (!data) {
4679275970Scy		cb(EVUTIL_EAI_MEMORY, NULL, arg);
4680275970Scy		return NULL;
4681275970Scy	}
4682275970Scy
4683275970Scy	memcpy(&data->hints, &hints, sizeof(data->hints));
4684275970Scy	data->port = (ev_uint16_t)port;
4685275970Scy	data->ipv4_request.type = DNS_IPv4_A;
4686275970Scy	data->ipv6_request.type = DNS_IPv6_AAAA;
4687275970Scy	data->user_cb = cb;
4688275970Scy	data->user_data = arg;
4689275970Scy	data->evdns_base = dns_base;
4690275970Scy
4691275970Scy	want_cname = (hints.ai_flags & EVUTIL_AI_CANONNAME);
4692275970Scy
4693275970Scy	/* If we are asked for a PF_UNSPEC address, we launch two requests in
4694275970Scy	 * parallel: one for an A address and one for an AAAA address.  We
4695275970Scy	 * can't send just one request, since many servers only answer one
4696275970Scy	 * question per DNS request.
4697275970Scy	 *
4698275970Scy	 * Once we have the answer to one request, we allow for a short
4699275970Scy	 * timeout before we report it, to see if the other one arrives.  If
4700275970Scy	 * they both show up in time, then we report both the answers.
4701275970Scy	 *
4702275970Scy	 * If too many addresses of one type time out or fail, we should stop
4703275970Scy	 * launching those requests. (XXX we don't do that yet.)
4704275970Scy	 */
4705275970Scy
4706275970Scy	if (hints.ai_family != PF_INET6) {
4707275970Scy		log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p",
4708275970Scy		    nodename, &data->ipv4_request);
4709275970Scy
4710275970Scy		data->ipv4_request.r = evdns_base_resolve_ipv4(dns_base,
4711275970Scy		    nodename, 0, evdns_getaddrinfo_gotresolve,
4712275970Scy		    &data->ipv4_request);
4713285612Sdelphij		if (want_cname && data->ipv4_request.r)
4714275970Scy			data->ipv4_request.r->current_req->put_cname_in_ptr =
4715275970Scy			    &data->cname_result;
4716275970Scy	}
4717275970Scy	if (hints.ai_family != PF_INET) {
4718275970Scy		log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv6 as %p",
4719275970Scy		    nodename, &data->ipv6_request);
4720275970Scy
4721275970Scy		data->ipv6_request.r = evdns_base_resolve_ipv6(dns_base,
4722275970Scy		    nodename, 0, evdns_getaddrinfo_gotresolve,
4723275970Scy		    &data->ipv6_request);
4724285612Sdelphij		if (want_cname && data->ipv6_request.r)
4725275970Scy			data->ipv6_request.r->current_req->put_cname_in_ptr =
4726275970Scy			    &data->cname_result;
4727275970Scy	}
4728275970Scy
4729275970Scy	evtimer_assign(&data->timeout, dns_base->event_base,
4730275970Scy	    evdns_getaddrinfo_timeout_cb, data);
4731275970Scy
4732275970Scy	if (data->ipv4_request.r || data->ipv6_request.r) {
4733275970Scy		return data;
4734275970Scy	} else {
4735275970Scy		mm_free(data);
4736275970Scy		cb(EVUTIL_EAI_FAIL, NULL, arg);
4737275970Scy		return NULL;
4738275970Scy	}
4739275970Scy}
4740275970Scy
4741275970Scyvoid
4742275970Scyevdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *data)
4743275970Scy{
4744275970Scy	EVDNS_LOCK(data->evdns_base);
4745275970Scy	if (data->request_done) {
4746275970Scy		EVDNS_UNLOCK(data->evdns_base);
4747275970Scy		return;
4748275970Scy	}
4749275970Scy	event_del(&data->timeout);
4750275970Scy	data->user_canceled = 1;
4751275970Scy	if (data->ipv4_request.r)
4752275970Scy		evdns_cancel_request(data->evdns_base, data->ipv4_request.r);
4753275970Scy	if (data->ipv6_request.r)
4754275970Scy		evdns_cancel_request(data->evdns_base, data->ipv6_request.r);
4755275970Scy	EVDNS_UNLOCK(data->evdns_base);
4756275970Scy}
4757