1290001Sglebius/* Copyright 2006-2007 Niels Provos
2290001Sglebius * Copyright 2007-2012 Nick Mathewson and Niels Provos
3290001Sglebius *
4290001Sglebius * Redistribution and use in source and binary forms, with or without
5290001Sglebius * modification, are permitted provided that the following conditions
6290001Sglebius * are met:
7290001Sglebius * 1. Redistributions of source code must retain the above copyright
8290001Sglebius *    notice, this list of conditions and the following disclaimer.
9290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright
10290001Sglebius *    notice, this list of conditions and the following disclaimer in the
11290001Sglebius *    documentation and/or other materials provided with the distribution.
12290001Sglebius * 3. The name of the author may not be used to endorse or promote products
13290001Sglebius *    derived from this software without specific prior written permission.
14290001Sglebius *
15290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25290001Sglebius */
26290001Sglebius
27290001Sglebius/* Based on software by Adam Langly. Adam's original message:
28290001Sglebius *
29290001Sglebius * Async DNS Library
30290001Sglebius * Adam Langley <agl@imperialviolet.org>
31290001Sglebius * http://www.imperialviolet.org/eventdns.html
32290001Sglebius * Public Domain code
33290001Sglebius *
34290001Sglebius * This software is Public Domain. To view a copy of the public domain dedication,
35290001Sglebius * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
36290001Sglebius * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
37290001Sglebius *
38290001Sglebius * I ask and expect, but do not require, that all derivative works contain an
39290001Sglebius * attribution similar to:
40290001Sglebius *	Parts developed by Adam Langley <agl@imperialviolet.org>
41290001Sglebius *
42290001Sglebius * You may wish to replace the word "Parts" with something else depending on
43290001Sglebius * the amount of original code.
44290001Sglebius *
45290001Sglebius * (Derivative works does not include programs which link against, run or include
46290001Sglebius * the source verbatim in their source distributions)
47290001Sglebius *
48290001Sglebius * Version: 0.1b
49290001Sglebius */
50290001Sglebius
51290001Sglebius#include "event2/event-config.h"
52290001Sglebius#include "evconfig-private.h"
53290001Sglebius
54290001Sglebius#include <sys/types.h>
55290001Sglebius
56290001Sglebius#ifndef _FORTIFY_SOURCE
57290001Sglebius#define _FORTIFY_SOURCE 3
58290001Sglebius#endif
59290001Sglebius
60290001Sglebius#include <string.h>
61290001Sglebius#include <fcntl.h>
62290001Sglebius#ifdef EVENT__HAVE_SYS_TIME_H
63290001Sglebius#include <sys/time.h>
64290001Sglebius#endif
65290001Sglebius#ifdef EVENT__HAVE_STDINT_H
66290001Sglebius#include <stdint.h>
67290001Sglebius#endif
68290001Sglebius#include <stdlib.h>
69290001Sglebius#include <string.h>
70290001Sglebius#include <errno.h>
71290001Sglebius#ifdef EVENT__HAVE_UNISTD_H
72290001Sglebius#include <unistd.h>
73290001Sglebius#endif
74290001Sglebius#include <limits.h>
75290001Sglebius#include <sys/stat.h>
76290001Sglebius#include <stdio.h>
77290001Sglebius#include <stdarg.h>
78290001Sglebius#ifdef _WIN32
79290001Sglebius#include <winsock2.h>
80290001Sglebius#include <ws2tcpip.h>
81290001Sglebius#ifndef _WIN32_IE
82290001Sglebius#define _WIN32_IE 0x400
83290001Sglebius#endif
84290001Sglebius#include <shlobj.h>
85290001Sglebius#endif
86290001Sglebius
87290001Sglebius#include "event2/dns.h"
88290001Sglebius#include "event2/dns_struct.h"
89290001Sglebius#include "event2/dns_compat.h"
90290001Sglebius#include "event2/util.h"
91290001Sglebius#include "event2/event.h"
92290001Sglebius#include "event2/event_struct.h"
93290001Sglebius#include "event2/thread.h"
94290001Sglebius
95290001Sglebius#include "defer-internal.h"
96290001Sglebius#include "log-internal.h"
97290001Sglebius#include "mm-internal.h"
98290001Sglebius#include "strlcpy-internal.h"
99290001Sglebius#include "ipv6-internal.h"
100290001Sglebius#include "util-internal.h"
101290001Sglebius#include "evthread-internal.h"
102290001Sglebius#ifdef _WIN32
103290001Sglebius#include <ctype.h>
104290001Sglebius#include <winsock2.h>
105290001Sglebius#include <windows.h>
106290001Sglebius#include <iphlpapi.h>
107290001Sglebius#include <io.h>
108290001Sglebius#else
109290001Sglebius#include <sys/socket.h>
110290001Sglebius#include <netinet/in.h>
111290001Sglebius#include <arpa/inet.h>
112290001Sglebius#endif
113290001Sglebius
114290001Sglebius#ifdef EVENT__HAVE_NETINET_IN6_H
115290001Sglebius#include <netinet/in6.h>
116290001Sglebius#endif
117290001Sglebius
118290001Sglebius#define EVDNS_LOG_DEBUG EVENT_LOG_DEBUG
119290001Sglebius#define EVDNS_LOG_WARN EVENT_LOG_WARN
120290001Sglebius#define EVDNS_LOG_MSG EVENT_LOG_MSG
121290001Sglebius
122290001Sglebius#ifndef HOST_NAME_MAX
123290001Sglebius#define HOST_NAME_MAX 255
124290001Sglebius#endif
125290001Sglebius
126290001Sglebius#include <stdio.h>
127290001Sglebius
128290001Sglebius#undef MIN
129290001Sglebius#define MIN(a,b) ((a)<(b)?(a):(b))
130290001Sglebius
131290001Sglebius#define ASSERT_VALID_REQUEST(req) \
132290001Sglebius	EVUTIL_ASSERT((req)->handle && (req)->handle->current_req == (req))
133290001Sglebius
134290001Sglebius#define u64 ev_uint64_t
135290001Sglebius#define u32 ev_uint32_t
136290001Sglebius#define u16 ev_uint16_t
137290001Sglebius#define u8  ev_uint8_t
138290001Sglebius
139290001Sglebius/* maximum number of addresses from a single packet */
140290001Sglebius/* that we bother recording */
141290001Sglebius#define MAX_V4_ADDRS 32
142290001Sglebius#define MAX_V6_ADDRS 32
143290001Sglebius
144290001Sglebius
145290001Sglebius#define TYPE_A	       EVDNS_TYPE_A
146290001Sglebius#define TYPE_CNAME     5
147290001Sglebius#define TYPE_PTR       EVDNS_TYPE_PTR
148290001Sglebius#define TYPE_SOA       EVDNS_TYPE_SOA
149290001Sglebius#define TYPE_AAAA      EVDNS_TYPE_AAAA
150290001Sglebius
151290001Sglebius#define CLASS_INET     EVDNS_CLASS_INET
152290001Sglebius
153290001Sglebius/* Persistent handle.  We keep this separate from 'struct request' since we
154290001Sglebius * need some object to last for as long as an evdns_request is outstanding so
155290001Sglebius * that it can be canceled, whereas a search request can lead to multiple
156290001Sglebius * 'struct request' instances being created over its lifetime. */
157290001Sglebiusstruct evdns_request {
158290001Sglebius	struct request *current_req;
159290001Sglebius	struct evdns_base *base;
160290001Sglebius
161290001Sglebius	int pending_cb; /* Waiting for its callback to be invoked; not
162290001Sglebius			 * owned by event base any more. */
163290001Sglebius
164290001Sglebius	/* elements used by the searching code */
165290001Sglebius	int search_index;
166290001Sglebius	struct search_state *search_state;
167290001Sglebius	char *search_origname;	/* needs to be free()ed */
168290001Sglebius	int search_flags;
169290001Sglebius};
170290001Sglebius
171290001Sglebiusstruct request {
172290001Sglebius	u8 *request;  /* the dns packet data */
173290001Sglebius	u8 request_type; /* TYPE_PTR or TYPE_A or TYPE_AAAA */
174290001Sglebius	unsigned int request_len;
175290001Sglebius	int reissue_count;
176290001Sglebius	int tx_count;  /* the number of times that this packet has been sent */
177290001Sglebius	void *user_pointer;  /* the pointer given to us for this request */
178290001Sglebius	evdns_callback_type user_callback;
179290001Sglebius	struct nameserver *ns;	/* the server which we last sent it */
180290001Sglebius
181290001Sglebius	/* these objects are kept in a circular list */
182290001Sglebius	/* XXX We could turn this into a CIRCLEQ. */
183290001Sglebius	struct request *next, *prev;
184290001Sglebius
185290001Sglebius	struct event timeout_event;
186290001Sglebius
187290001Sglebius	u16 trans_id;  /* the transaction id */
188290001Sglebius	unsigned request_appended :1;	/* true if the request pointer is data which follows this struct */
189290001Sglebius	unsigned transmit_me :1;  /* needs to be transmitted */
190290001Sglebius
191290001Sglebius	/* XXXX This is a horrible hack. */
192290001Sglebius	char **put_cname_in_ptr; /* store the cname here if we get one. */
193290001Sglebius
194290001Sglebius	struct evdns_base *base;
195290001Sglebius
196290001Sglebius	struct evdns_request *handle;
197290001Sglebius};
198290001Sglebius
199290001Sglebiusstruct reply {
200290001Sglebius	unsigned int type;
201290001Sglebius	unsigned int have_answer : 1;
202290001Sglebius	union {
203290001Sglebius		struct {
204290001Sglebius			u32 addrcount;
205290001Sglebius			u32 addresses[MAX_V4_ADDRS];
206290001Sglebius		} a;
207290001Sglebius		struct {
208290001Sglebius			u32 addrcount;
209290001Sglebius			struct in6_addr addresses[MAX_V6_ADDRS];
210290001Sglebius		} aaaa;
211290001Sglebius		struct {
212290001Sglebius			char name[HOST_NAME_MAX];
213290001Sglebius		} ptr;
214290001Sglebius	} data;
215290001Sglebius};
216290001Sglebius
217290001Sglebiusstruct nameserver {
218290001Sglebius	evutil_socket_t socket;	 /* a connected UDP socket */
219290001Sglebius	struct sockaddr_storage address;
220290001Sglebius	ev_socklen_t addrlen;
221290001Sglebius	int failed_times;  /* number of times which we have given this server a chance */
222290001Sglebius	int timedout;  /* number of times in a row a request has timed out */
223290001Sglebius	struct event event;
224290001Sglebius	/* these objects are kept in a circular list */
225290001Sglebius	struct nameserver *next, *prev;
226290001Sglebius	struct event timeout_event;  /* used to keep the timeout for */
227290001Sglebius				     /* when we next probe this server. */
228290001Sglebius				     /* Valid if state == 0 */
229290001Sglebius	/* Outstanding probe request for this nameserver, if any */
230290001Sglebius	struct evdns_request *probe_request;
231290001Sglebius	char state;  /* zero if we think that this server is down */
232290001Sglebius	char choked;  /* true if we have an EAGAIN from this server's socket */
233290001Sglebius	char write_waiting;  /* true if we are waiting for EV_WRITE events */
234290001Sglebius	struct evdns_base *base;
235290001Sglebius
236290001Sglebius	/* Number of currently inflight requests: used
237290001Sglebius	 * to track when we should add/del the event. */
238290001Sglebius	int requests_inflight;
239290001Sglebius};
240290001Sglebius
241290001Sglebius
242290001Sglebius/* Represents a local port where we're listening for DNS requests. Right now, */
243290001Sglebius/* only UDP is supported. */
244290001Sglebiusstruct evdns_server_port {
245290001Sglebius	evutil_socket_t socket; /* socket we use to read queries and write replies. */
246290001Sglebius	int refcnt; /* reference count. */
247290001Sglebius	char choked; /* Are we currently blocked from writing? */
248290001Sglebius	char closing; /* Are we trying to close this port, pending writes? */
249290001Sglebius	evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
250290001Sglebius	void *user_data; /* Opaque pointer passed to user_callback */
251290001Sglebius	struct event event; /* Read/write event */
252290001Sglebius	/* circular list of replies that we want to write. */
253290001Sglebius	struct server_request *pending_replies;
254290001Sglebius	struct event_base *event_base;
255290001Sglebius
256290001Sglebius#ifndef EVENT__DISABLE_THREAD_SUPPORT
257290001Sglebius	void *lock;
258290001Sglebius#endif
259290001Sglebius};
260290001Sglebius
261290001Sglebius/* Represents part of a reply being built.	(That is, a single RR.) */
262290001Sglebiusstruct server_reply_item {
263290001Sglebius	struct server_reply_item *next; /* next item in sequence. */
264290001Sglebius	char *name; /* name part of the RR */
265290001Sglebius	u16 type; /* The RR type */
266290001Sglebius	u16 class; /* The RR class (usually CLASS_INET) */
267290001Sglebius	u32 ttl; /* The RR TTL */
268290001Sglebius	char is_name; /* True iff data is a label */
269290001Sglebius	u16 datalen; /* Length of data; -1 if data is a label */
270290001Sglebius	void *data; /* The contents of the RR */
271290001Sglebius};
272290001Sglebius
273290001Sglebius/* Represents a request that we've received as a DNS server, and holds */
274290001Sglebius/* the components of the reply as we're constructing it. */
275290001Sglebiusstruct server_request {
276290001Sglebius	/* Pointers to the next and previous entries on the list of replies */
277290001Sglebius	/* that we're waiting to write.	 Only set if we have tried to respond */
278290001Sglebius	/* and gotten EAGAIN. */
279290001Sglebius	struct server_request *next_pending;
280290001Sglebius	struct server_request *prev_pending;
281290001Sglebius
282290001Sglebius	u16 trans_id; /* Transaction id. */
283290001Sglebius	struct evdns_server_port *port; /* Which port received this request on? */
284290001Sglebius	struct sockaddr_storage addr; /* Where to send the response */
285290001Sglebius	ev_socklen_t addrlen; /* length of addr */
286290001Sglebius
287290001Sglebius	int n_answer; /* how many answer RRs have been set? */
288290001Sglebius	int n_authority; /* how many authority RRs have been set? */
289290001Sglebius	int n_additional; /* how many additional RRs have been set? */
290290001Sglebius
291290001Sglebius	struct server_reply_item *answer; /* linked list of answer RRs */
292290001Sglebius	struct server_reply_item *authority; /* linked list of authority RRs */
293290001Sglebius	struct server_reply_item *additional; /* linked list of additional RRs */
294290001Sglebius
295290001Sglebius	/* Constructed response.  Only set once we're ready to send a reply. */
296290001Sglebius	/* Once this is set, the RR fields are cleared, and no more should be set. */
297290001Sglebius	char *response;
298290001Sglebius	size_t response_len;
299290001Sglebius
300290001Sglebius	/* Caller-visible fields: flags, questions. */
301290001Sglebius	struct evdns_server_request base;
302290001Sglebius};
303290001Sglebius
304290001Sglebiusstruct evdns_base {
305290001Sglebius	/* An array of n_req_heads circular lists for inflight requests.
306290001Sglebius	 * Each inflight request req is in req_heads[req->trans_id % n_req_heads].
307290001Sglebius	 */
308290001Sglebius	struct request **req_heads;
309290001Sglebius	/* A circular list of requests that we're waiting to send, but haven't
310290001Sglebius	 * sent yet because there are too many requests inflight */
311290001Sglebius	struct request *req_waiting_head;
312290001Sglebius	/* A circular list of nameservers. */
313290001Sglebius	struct nameserver *server_head;
314290001Sglebius	int n_req_heads;
315290001Sglebius
316290001Sglebius	struct event_base *event_base;
317290001Sglebius
318290001Sglebius	/* The number of good nameservers that we have */
319290001Sglebius	int global_good_nameservers;
320290001Sglebius
321290001Sglebius	/* inflight requests are contained in the req_head list */
322290001Sglebius	/* and are actually going out across the network */
323290001Sglebius	int global_requests_inflight;
324290001Sglebius	/* requests which aren't inflight are in the waiting list */
325290001Sglebius	/* and are counted here */
326290001Sglebius	int global_requests_waiting;
327290001Sglebius
328290001Sglebius	int global_max_requests_inflight;
329290001Sglebius
330290001Sglebius	struct timeval global_timeout;	/* 5 seconds by default */
331290001Sglebius	int global_max_reissues;  /* a reissue occurs when we get some errors from the server */
332290001Sglebius	int global_max_retransmits;  /* number of times we'll retransmit a request which timed out */
333290001Sglebius	/* number of timeouts in a row before we consider this server to be down */
334290001Sglebius	int global_max_nameserver_timeout;
335290001Sglebius	/* true iff we will use the 0x20 hack to prevent poisoning attacks. */
336290001Sglebius	int global_randomize_case;
337290001Sglebius
338290001Sglebius	/* The first time that a nameserver fails, how long do we wait before
339290001Sglebius	 * probing to see if it has returned?  */
340290001Sglebius	struct timeval global_nameserver_probe_initial_timeout;
341290001Sglebius
342290001Sglebius	/** Port to bind to for outgoing DNS packets. */
343290001Sglebius	struct sockaddr_storage global_outgoing_address;
344290001Sglebius	/** ev_socklen_t for global_outgoing_address. 0 if it isn't set. */
345290001Sglebius	ev_socklen_t global_outgoing_addrlen;
346290001Sglebius
347290001Sglebius	struct timeval global_getaddrinfo_allow_skew;
348290001Sglebius
349290001Sglebius	int getaddrinfo_ipv4_timeouts;
350290001Sglebius	int getaddrinfo_ipv6_timeouts;
351290001Sglebius	int getaddrinfo_ipv4_answered;
352290001Sglebius	int getaddrinfo_ipv6_answered;
353290001Sglebius
354290001Sglebius	struct search_state *global_search_state;
355290001Sglebius
356290001Sglebius	TAILQ_HEAD(hosts_list, hosts_entry) hostsdb;
357290001Sglebius
358290001Sglebius#ifndef EVENT__DISABLE_THREAD_SUPPORT
359290001Sglebius	void *lock;
360290001Sglebius#endif
361290001Sglebius
362290001Sglebius	int disable_when_inactive;
363290001Sglebius};
364290001Sglebius
365290001Sglebiusstruct hosts_entry {
366290001Sglebius	TAILQ_ENTRY(hosts_entry) next;
367290001Sglebius	union {
368290001Sglebius		struct sockaddr sa;
369290001Sglebius		struct sockaddr_in sin;
370290001Sglebius		struct sockaddr_in6 sin6;
371290001Sglebius	} addr;
372290001Sglebius	int addrlen;
373290001Sglebius	char hostname[1];
374290001Sglebius};
375290001Sglebius
376290001Sglebiusstatic struct evdns_base *current_base = NULL;
377290001Sglebius
378290001Sglebiusstruct evdns_base *
379290001Sglebiusevdns_get_global_base(void)
380290001Sglebius{
381290001Sglebius	return current_base;
382290001Sglebius}
383290001Sglebius
384290001Sglebius/* Given a pointer to an evdns_server_request, get the corresponding */
385290001Sglebius/* server_request. */
386290001Sglebius#define TO_SERVER_REQUEST(base_ptr)					\
387290001Sglebius	((struct server_request*)					\
388290001Sglebius	  (((char*)(base_ptr) - evutil_offsetof(struct server_request, base))))
389290001Sglebius
390290001Sglebius#define REQ_HEAD(base, id) ((base)->req_heads[id % (base)->n_req_heads])
391290001Sglebius
392290001Sglebiusstatic struct nameserver *nameserver_pick(struct evdns_base *base);
393290001Sglebiusstatic void evdns_request_insert(struct request *req, struct request **head);
394290001Sglebiusstatic void evdns_request_remove(struct request *req, struct request **head);
395290001Sglebiusstatic void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg);
396290001Sglebiusstatic int evdns_transmit(struct evdns_base *base);
397290001Sglebiusstatic int evdns_request_transmit(struct request *req);
398290001Sglebiusstatic void nameserver_send_probe(struct nameserver *const ns);
399290001Sglebiusstatic void search_request_finished(struct evdns_request *const);
400290001Sglebiusstatic int search_try_next(struct evdns_request *const req);
401290001Sglebiusstatic 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);
402290001Sglebiusstatic void evdns_requests_pump_waiting_queue(struct evdns_base *base);
403290001Sglebiusstatic u16 transaction_id_pick(struct evdns_base *base);
404290001Sglebiusstatic 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);
405290001Sglebiusstatic void request_submit(struct request *const req);
406290001Sglebius
407290001Sglebiusstatic int server_request_free(struct server_request *req);
408290001Sglebiusstatic void server_request_free_answers(struct server_request *req);
409290001Sglebiusstatic void server_port_free(struct evdns_server_port *port);
410290001Sglebiusstatic void server_port_ready_callback(evutil_socket_t fd, short events, void *arg);
411290001Sglebiusstatic int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename);
412290001Sglebiusstatic int evdns_base_set_option_impl(struct evdns_base *base,
413290001Sglebius    const char *option, const char *val, int flags);
414290001Sglebiusstatic void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests);
415290001Sglebiusstatic void evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg);
416290001Sglebius
417290001Sglebiusstatic int strtoint(const char *const str);
418290001Sglebius
419290001Sglebius#ifdef EVENT__DISABLE_THREAD_SUPPORT
420290001Sglebius#define EVDNS_LOCK(base)  EVUTIL_NIL_STMT_
421290001Sglebius#define EVDNS_UNLOCK(base) EVUTIL_NIL_STMT_
422290001Sglebius#define ASSERT_LOCKED(base) EVUTIL_NIL_STMT_
423290001Sglebius#else
424290001Sglebius#define EVDNS_LOCK(base)			\
425290001Sglebius	EVLOCK_LOCK((base)->lock, 0)
426290001Sglebius#define EVDNS_UNLOCK(base)			\
427290001Sglebius	EVLOCK_UNLOCK((base)->lock, 0)
428290001Sglebius#define ASSERT_LOCKED(base)			\
429290001Sglebius	EVLOCK_ASSERT_LOCKED((base)->lock)
430290001Sglebius#endif
431290001Sglebius
432290001Sglebiusstatic evdns_debug_log_fn_type evdns_log_fn = NULL;
433290001Sglebius
434290001Sglebiusvoid
435290001Sglebiusevdns_set_log_fn(evdns_debug_log_fn_type fn)
436290001Sglebius{
437290001Sglebius	evdns_log_fn = fn;
438290001Sglebius}
439290001Sglebius
440290001Sglebius#ifdef __GNUC__
441290001Sglebius#define EVDNS_LOG_CHECK	 __attribute__ ((format(printf, 2, 3)))
442290001Sglebius#else
443290001Sglebius#define EVDNS_LOG_CHECK
444290001Sglebius#endif
445290001Sglebius
446290001Sglebiusstatic void evdns_log_(int severity, const char *fmt, ...) EVDNS_LOG_CHECK;
447290001Sglebiusstatic void
448290001Sglebiusevdns_log_(int severity, const char *fmt, ...)
449290001Sglebius{
450290001Sglebius	va_list args;
451290001Sglebius	va_start(args,fmt);
452290001Sglebius	if (evdns_log_fn) {
453290001Sglebius		char buf[512];
454290001Sglebius		int is_warn = (severity == EVDNS_LOG_WARN);
455290001Sglebius		evutil_vsnprintf(buf, sizeof(buf), fmt, args);
456290001Sglebius		evdns_log_fn(is_warn, buf);
457290001Sglebius	} else {
458290001Sglebius		event_logv_(severity, NULL, fmt, args);
459290001Sglebius	}
460290001Sglebius	va_end(args);
461290001Sglebius}
462290001Sglebius
463290001Sglebius#define log evdns_log_
464290001Sglebius
465290001Sglebius/* This walks the list of inflight requests to find the */
466290001Sglebius/* one with a matching transaction id. Returns NULL on */
467290001Sglebius/* failure */
468290001Sglebiusstatic struct request *
469290001Sglebiusrequest_find_from_trans_id(struct evdns_base *base, u16 trans_id) {
470290001Sglebius	struct request *req = REQ_HEAD(base, trans_id);
471290001Sglebius	struct request *const started_at = req;
472290001Sglebius
473290001Sglebius	ASSERT_LOCKED(base);
474290001Sglebius
475290001Sglebius	if (req) {
476290001Sglebius		do {
477290001Sglebius			if (req->trans_id == trans_id) return req;
478290001Sglebius			req = req->next;
479290001Sglebius		} while (req != started_at);
480290001Sglebius	}
481290001Sglebius
482290001Sglebius	return NULL;
483290001Sglebius}
484290001Sglebius
485290001Sglebius/* a libevent callback function which is called when a nameserver */
486290001Sglebius/* has gone down and we want to test if it has came back to life yet */
487290001Sglebiusstatic void
488290001Sglebiusnameserver_prod_callback(evutil_socket_t fd, short events, void *arg) {
489290001Sglebius	struct nameserver *const ns = (struct nameserver *) arg;
490290001Sglebius	(void)fd;
491290001Sglebius	(void)events;
492290001Sglebius
493290001Sglebius	EVDNS_LOCK(ns->base);
494290001Sglebius	nameserver_send_probe(ns);
495290001Sglebius	EVDNS_UNLOCK(ns->base);
496290001Sglebius}
497290001Sglebius
498290001Sglebius/* a libevent callback which is called when a nameserver probe (to see if */
499290001Sglebius/* it has come back to life) times out. We increment the count of failed_times */
500290001Sglebius/* and wait longer to send the next probe packet. */
501290001Sglebiusstatic void
502290001Sglebiusnameserver_probe_failed(struct nameserver *const ns) {
503290001Sglebius	struct timeval timeout;
504290001Sglebius	int i;
505290001Sglebius
506290001Sglebius	ASSERT_LOCKED(ns->base);
507290001Sglebius	(void) evtimer_del(&ns->timeout_event);
508290001Sglebius	if (ns->state == 1) {
509290001Sglebius		/* This can happen if the nameserver acts in a way which makes us mark */
510290001Sglebius		/* it as bad and then starts sending good replies. */
511290001Sglebius		return;
512290001Sglebius	}
513290001Sglebius
514290001Sglebius#define MAX_PROBE_TIMEOUT 3600
515290001Sglebius#define TIMEOUT_BACKOFF_FACTOR 3
516290001Sglebius
517290001Sglebius	memcpy(&timeout, &ns->base->global_nameserver_probe_initial_timeout,
518290001Sglebius	    sizeof(struct timeval));
519290001Sglebius	for (i=ns->failed_times; i > 0 && timeout.tv_sec < MAX_PROBE_TIMEOUT; --i) {
520290001Sglebius		timeout.tv_sec *= TIMEOUT_BACKOFF_FACTOR;
521290001Sglebius		timeout.tv_usec *= TIMEOUT_BACKOFF_FACTOR;
522290001Sglebius		if (timeout.tv_usec > 1000000) {
523290001Sglebius			timeout.tv_sec += timeout.tv_usec / 1000000;
524290001Sglebius			timeout.tv_usec %= 1000000;
525290001Sglebius		}
526290001Sglebius	}
527290001Sglebius	if (timeout.tv_sec > MAX_PROBE_TIMEOUT) {
528290001Sglebius		timeout.tv_sec = MAX_PROBE_TIMEOUT;
529290001Sglebius		timeout.tv_usec = 0;
530290001Sglebius	}
531290001Sglebius
532290001Sglebius	ns->failed_times++;
533290001Sglebius
534290001Sglebius	if (evtimer_add(&ns->timeout_event, &timeout) < 0) {
535290001Sglebius		char addrbuf[128];
536290001Sglebius		log(EVDNS_LOG_WARN,
537290001Sglebius		    "Error from libevent when adding timer event for %s",
538290001Sglebius		    evutil_format_sockaddr_port_(
539290001Sglebius			    (struct sockaddr *)&ns->address,
540290001Sglebius			    addrbuf, sizeof(addrbuf)));
541290001Sglebius	}
542290001Sglebius}
543290001Sglebius
544290001Sglebiusstatic void
545290001Sglebiusrequest_swap_ns(struct request *req, struct nameserver *ns) {
546290001Sglebius	if (ns && req->ns != ns) {
547290001Sglebius		EVUTIL_ASSERT(req->ns->requests_inflight > 0);
548290001Sglebius		req->ns->requests_inflight--;
549290001Sglebius		ns->requests_inflight++;
550290001Sglebius
551290001Sglebius		req->ns = ns;
552290001Sglebius	}
553290001Sglebius}
554290001Sglebius
555290001Sglebius/* called when a nameserver has been deemed to have failed. For example, too */
556290001Sglebius/* many packets have timed out etc */
557290001Sglebiusstatic void
558290001Sglebiusnameserver_failed(struct nameserver *const ns, const char *msg) {
559290001Sglebius	struct request *req, *started_at;
560290001Sglebius	struct evdns_base *base = ns->base;
561290001Sglebius	int i;
562290001Sglebius	char addrbuf[128];
563290001Sglebius
564290001Sglebius	ASSERT_LOCKED(base);
565290001Sglebius	/* if this nameserver has already been marked as failed */
566290001Sglebius	/* then don't do anything */
567290001Sglebius	if (!ns->state) return;
568290001Sglebius
569290001Sglebius	log(EVDNS_LOG_MSG, "Nameserver %s has failed: %s",
570290001Sglebius	    evutil_format_sockaddr_port_(
571290001Sglebius		    (struct sockaddr *)&ns->address,
572290001Sglebius		    addrbuf, sizeof(addrbuf)),
573290001Sglebius	    msg);
574290001Sglebius
575290001Sglebius	base->global_good_nameservers--;
576290001Sglebius	EVUTIL_ASSERT(base->global_good_nameservers >= 0);
577290001Sglebius	if (base->global_good_nameservers == 0) {
578290001Sglebius		log(EVDNS_LOG_MSG, "All nameservers have failed");
579290001Sglebius	}
580290001Sglebius
581290001Sglebius	ns->state = 0;
582290001Sglebius	ns->failed_times = 1;
583290001Sglebius
584290001Sglebius	if (evtimer_add(&ns->timeout_event,
585290001Sglebius		&base->global_nameserver_probe_initial_timeout) < 0) {
586290001Sglebius		log(EVDNS_LOG_WARN,
587290001Sglebius		    "Error from libevent when adding timer event for %s",
588290001Sglebius		    evutil_format_sockaddr_port_(
589290001Sglebius			    (struct sockaddr *)&ns->address,
590290001Sglebius			    addrbuf, sizeof(addrbuf)));
591290001Sglebius		/* ???? Do more? */
592290001Sglebius	}
593290001Sglebius
594290001Sglebius	/* walk the list of inflight requests to see if any can be reassigned to */
595290001Sglebius	/* a different server. Requests in the waiting queue don't have a */
596290001Sglebius	/* nameserver assigned yet */
597290001Sglebius
598290001Sglebius	/* if we don't have *any* good nameservers then there's no point */
599290001Sglebius	/* trying to reassign requests to one */
600290001Sglebius	if (!base->global_good_nameservers) return;
601290001Sglebius
602290001Sglebius	for (i = 0; i < base->n_req_heads; ++i) {
603290001Sglebius		req = started_at = base->req_heads[i];
604290001Sglebius		if (req) {
605290001Sglebius			do {
606290001Sglebius				if (req->tx_count == 0 && req->ns == ns) {
607290001Sglebius					/* still waiting to go out, can be moved */
608290001Sglebius					/* to another server */
609290001Sglebius					request_swap_ns(req, nameserver_pick(base));
610290001Sglebius				}
611290001Sglebius				req = req->next;
612290001Sglebius			} while (req != started_at);
613290001Sglebius		}
614290001Sglebius	}
615290001Sglebius}
616290001Sglebius
617290001Sglebiusstatic void
618290001Sglebiusnameserver_up(struct nameserver *const ns)
619290001Sglebius{
620290001Sglebius	char addrbuf[128];
621290001Sglebius	ASSERT_LOCKED(ns->base);
622290001Sglebius	if (ns->state) return;
623290001Sglebius	log(EVDNS_LOG_MSG, "Nameserver %s is back up",
624290001Sglebius	    evutil_format_sockaddr_port_(
625290001Sglebius		    (struct sockaddr *)&ns->address,
626290001Sglebius		    addrbuf, sizeof(addrbuf)));
627290001Sglebius	evtimer_del(&ns->timeout_event);
628290001Sglebius	if (ns->probe_request) {
629290001Sglebius		evdns_cancel_request(ns->base, ns->probe_request);
630290001Sglebius		ns->probe_request = NULL;
631290001Sglebius	}
632290001Sglebius	ns->state = 1;
633290001Sglebius	ns->failed_times = 0;
634290001Sglebius	ns->timedout = 0;
635290001Sglebius	ns->base->global_good_nameservers++;
636290001Sglebius}
637290001Sglebius
638290001Sglebiusstatic void
639290001Sglebiusrequest_trans_id_set(struct request *const req, const u16 trans_id) {
640290001Sglebius	req->trans_id = trans_id;
641290001Sglebius	*((u16 *) req->request) = htons(trans_id);
642290001Sglebius}
643290001Sglebius
644290001Sglebius/* Called to remove a request from a list and dealloc it. */
645290001Sglebius/* head is a pointer to the head of the list it should be */
646290001Sglebius/* removed from or NULL if the request isn't in a list. */
647290001Sglebius/* when free_handle is one, free the handle as well. */
648290001Sglebiusstatic void
649290001Sglebiusrequest_finished(struct request *const req, struct request **head, int free_handle) {
650290001Sglebius	struct evdns_base *base = req->base;
651290001Sglebius	int was_inflight = (head != &base->req_waiting_head);
652290001Sglebius	EVDNS_LOCK(base);
653290001Sglebius	ASSERT_VALID_REQUEST(req);
654290001Sglebius
655290001Sglebius	if (head)
656290001Sglebius		evdns_request_remove(req, head);
657290001Sglebius
658290001Sglebius	log(EVDNS_LOG_DEBUG, "Removing timeout for request %p", req);
659290001Sglebius	if (was_inflight) {
660290001Sglebius		evtimer_del(&req->timeout_event);
661290001Sglebius		base->global_requests_inflight--;
662290001Sglebius		req->ns->requests_inflight--;
663290001Sglebius	} else {
664290001Sglebius		base->global_requests_waiting--;
665290001Sglebius	}
666290001Sglebius	/* it was initialized during request_new / evtimer_assign */
667290001Sglebius	event_debug_unassign(&req->timeout_event);
668290001Sglebius
669290001Sglebius	if (req->ns &&
670290001Sglebius	    req->ns->requests_inflight == 0 &&
671290001Sglebius	    req->base->disable_when_inactive) {
672290001Sglebius		event_del(&req->ns->event);
673290001Sglebius		evtimer_del(&req->ns->timeout_event);
674290001Sglebius	}
675290001Sglebius
676290001Sglebius	if (!req->request_appended) {
677290001Sglebius		/* need to free the request data on it's own */
678290001Sglebius		mm_free(req->request);
679290001Sglebius	} else {
680290001Sglebius		/* the request data is appended onto the header */
681290001Sglebius		/* so everything gets free()ed when we: */
682290001Sglebius	}
683290001Sglebius
684290001Sglebius	if (req->handle) {
685290001Sglebius		EVUTIL_ASSERT(req->handle->current_req == req);
686290001Sglebius
687290001Sglebius		if (free_handle) {
688290001Sglebius			search_request_finished(req->handle);
689290001Sglebius			req->handle->current_req = NULL;
690290001Sglebius			if (! req->handle->pending_cb) {
691290001Sglebius				/* If we're planning to run the callback,
692290001Sglebius				 * don't free the handle until later. */
693290001Sglebius				mm_free(req->handle);
694290001Sglebius			}
695290001Sglebius			req->handle = NULL; /* If we have a bug, let's crash
696290001Sglebius					     * early */
697290001Sglebius		} else {
698290001Sglebius			req->handle->current_req = NULL;
699290001Sglebius		}
700290001Sglebius	}
701290001Sglebius
702290001Sglebius	mm_free(req);
703290001Sglebius
704290001Sglebius	evdns_requests_pump_waiting_queue(base);
705290001Sglebius	EVDNS_UNLOCK(base);
706290001Sglebius}
707290001Sglebius
708290001Sglebius/* This is called when a server returns a funny error code. */
709290001Sglebius/* We try the request again with another server. */
710290001Sglebius/* */
711290001Sglebius/* return: */
712290001Sglebius/*   0 ok */
713290001Sglebius/*   1 failed/reissue is pointless */
714290001Sglebiusstatic int
715290001Sglebiusrequest_reissue(struct request *req) {
716290001Sglebius	const struct nameserver *const last_ns = req->ns;
717290001Sglebius	ASSERT_LOCKED(req->base);
718290001Sglebius	ASSERT_VALID_REQUEST(req);
719290001Sglebius	/* the last nameserver should have been marked as failing */
720290001Sglebius	/* by the caller of this function, therefore pick will try */
721290001Sglebius	/* not to return it */
722290001Sglebius	request_swap_ns(req, nameserver_pick(req->base));
723290001Sglebius	if (req->ns == last_ns) {
724290001Sglebius		/* ... but pick did return it */
725290001Sglebius		/* not a lot of point in trying again with the */
726290001Sglebius		/* same server */
727290001Sglebius		return 1;
728290001Sglebius	}
729290001Sglebius
730290001Sglebius	req->reissue_count++;
731290001Sglebius	req->tx_count = 0;
732290001Sglebius	req->transmit_me = 1;
733290001Sglebius
734290001Sglebius	return 0;
735290001Sglebius}
736290001Sglebius
737290001Sglebius/* this function looks for space on the inflight queue and promotes */
738290001Sglebius/* requests from the waiting queue if it can. */
739290001Sglebius/* */
740290001Sglebius/* TODO: */
741290001Sglebius/* add return code, see at nameserver_pick() and other functions. */
742290001Sglebiusstatic void
743290001Sglebiusevdns_requests_pump_waiting_queue(struct evdns_base *base) {
744290001Sglebius	ASSERT_LOCKED(base);
745290001Sglebius	while (base->global_requests_inflight < base->global_max_requests_inflight &&
746290001Sglebius		   base->global_requests_waiting) {
747290001Sglebius		struct request *req;
748290001Sglebius
749290001Sglebius		EVUTIL_ASSERT(base->req_waiting_head);
750290001Sglebius		req = base->req_waiting_head;
751290001Sglebius
752290001Sglebius		req->ns = nameserver_pick(base);
753290001Sglebius		if (!req->ns)
754290001Sglebius			return;
755290001Sglebius
756290001Sglebius		/* move a request from the waiting queue to the inflight queue */
757290001Sglebius		req->ns->requests_inflight++;
758290001Sglebius
759290001Sglebius		evdns_request_remove(req, &base->req_waiting_head);
760290001Sglebius
761290001Sglebius		base->global_requests_waiting--;
762290001Sglebius		base->global_requests_inflight++;
763290001Sglebius
764290001Sglebius		request_trans_id_set(req, transaction_id_pick(base));
765290001Sglebius
766290001Sglebius		evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
767290001Sglebius		evdns_request_transmit(req);
768290001Sglebius		evdns_transmit(base);
769290001Sglebius	}
770290001Sglebius}
771290001Sglebius
772290001Sglebius/* TODO(nickm) document */
773290001Sglebiusstruct deferred_reply_callback {
774290001Sglebius	struct event_callback deferred;
775290001Sglebius	struct evdns_request *handle;
776290001Sglebius	u8 request_type;
777290001Sglebius	u8 have_reply;
778290001Sglebius	u32 ttl;
779290001Sglebius	u32 err;
780290001Sglebius	evdns_callback_type user_callback;
781290001Sglebius	struct reply reply;
782290001Sglebius};
783290001Sglebius
784290001Sglebiusstatic void
785290001Sglebiusreply_run_callback(struct event_callback *d, void *user_pointer)
786290001Sglebius{
787290001Sglebius	struct deferred_reply_callback *cb =
788290001Sglebius	    EVUTIL_UPCAST(d, struct deferred_reply_callback, deferred);
789290001Sglebius
790290001Sglebius	switch (cb->request_type) {
791290001Sglebius	case TYPE_A:
792290001Sglebius		if (cb->have_reply)
793290001Sglebius			cb->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
794290001Sglebius			    cb->reply.data.a.addrcount, cb->ttl,
795290001Sglebius			    cb->reply.data.a.addresses,
796290001Sglebius			    user_pointer);
797290001Sglebius		else
798290001Sglebius			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
799290001Sglebius		break;
800290001Sglebius	case TYPE_PTR:
801290001Sglebius		if (cb->have_reply) {
802290001Sglebius			char *name = cb->reply.data.ptr.name;
803290001Sglebius			cb->user_callback(DNS_ERR_NONE, DNS_PTR, 1, cb->ttl,
804290001Sglebius			    &name, user_pointer);
805290001Sglebius		} else {
806290001Sglebius			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
807290001Sglebius		}
808290001Sglebius		break;
809290001Sglebius	case TYPE_AAAA:
810290001Sglebius		if (cb->have_reply)
811290001Sglebius			cb->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
812290001Sglebius			    cb->reply.data.aaaa.addrcount, cb->ttl,
813290001Sglebius			    cb->reply.data.aaaa.addresses,
814290001Sglebius			    user_pointer);
815290001Sglebius		else
816290001Sglebius			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
817290001Sglebius		break;
818290001Sglebius	default:
819290001Sglebius		EVUTIL_ASSERT(0);
820290001Sglebius	}
821290001Sglebius
822290001Sglebius	if (cb->handle && cb->handle->pending_cb) {
823290001Sglebius		mm_free(cb->handle);
824290001Sglebius	}
825290001Sglebius
826290001Sglebius	mm_free(cb);
827290001Sglebius}
828290001Sglebius
829290001Sglebiusstatic void
830290001Sglebiusreply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply)
831290001Sglebius{
832290001Sglebius	struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d));
833290001Sglebius
834290001Sglebius	if (!d) {
835290001Sglebius		event_warn("%s: Couldn't allocate space for deferred callback.",
836290001Sglebius		    __func__);
837290001Sglebius		return;
838290001Sglebius	}
839290001Sglebius
840290001Sglebius	ASSERT_LOCKED(req->base);
841290001Sglebius
842290001Sglebius	d->request_type = req->request_type;
843290001Sglebius	d->user_callback = req->user_callback;
844290001Sglebius	d->ttl = ttl;
845290001Sglebius	d->err = err;
846290001Sglebius	if (reply) {
847290001Sglebius		d->have_reply = 1;
848290001Sglebius		memcpy(&d->reply, reply, sizeof(struct reply));
849290001Sglebius	}
850290001Sglebius
851290001Sglebius	if (req->handle) {
852290001Sglebius		req->handle->pending_cb = 1;
853290001Sglebius		d->handle = req->handle;
854290001Sglebius	}
855290001Sglebius
856290001Sglebius	event_deferred_cb_init_(
857290001Sglebius	    &d->deferred,
858290001Sglebius	    event_get_priority(&req->timeout_event),
859290001Sglebius	    reply_run_callback,
860290001Sglebius	    req->user_pointer);
861290001Sglebius	event_deferred_cb_schedule_(
862290001Sglebius		req->base->event_base,
863290001Sglebius		&d->deferred);
864290001Sglebius}
865290001Sglebius
866290001Sglebius/* this processes a parsed reply packet */
867290001Sglebiusstatic void
868290001Sglebiusreply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
869290001Sglebius	int error;
870290001Sglebius	char addrbuf[128];
871290001Sglebius	static const int error_codes[] = {
872290001Sglebius		DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
873290001Sglebius		DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
874290001Sglebius	};
875290001Sglebius
876290001Sglebius	ASSERT_LOCKED(req->base);
877290001Sglebius	ASSERT_VALID_REQUEST(req);
878290001Sglebius
879290001Sglebius	if (flags & 0x020f || !reply || !reply->have_answer) {
880290001Sglebius		/* there was an error */
881290001Sglebius		if (flags & 0x0200) {
882290001Sglebius			error = DNS_ERR_TRUNCATED;
883290001Sglebius		} else if (flags & 0x000f) {
884290001Sglebius			u16 error_code = (flags & 0x000f) - 1;
885290001Sglebius			if (error_code > 4) {
886290001Sglebius				error = DNS_ERR_UNKNOWN;
887290001Sglebius			} else {
888290001Sglebius				error = error_codes[error_code];
889290001Sglebius			}
890290001Sglebius		} else if (reply && !reply->have_answer) {
891290001Sglebius			error = DNS_ERR_NODATA;
892290001Sglebius		} else {
893290001Sglebius			error = DNS_ERR_UNKNOWN;
894290001Sglebius		}
895290001Sglebius
896290001Sglebius		switch (error) {
897290001Sglebius		case DNS_ERR_NOTIMPL:
898290001Sglebius		case DNS_ERR_REFUSED:
899290001Sglebius			/* we regard these errors as marking a bad nameserver */
900290001Sglebius			if (req->reissue_count < req->base->global_max_reissues) {
901290001Sglebius				char msg[64];
902290001Sglebius				evutil_snprintf(msg, sizeof(msg), "Bad response %d (%s)",
903290001Sglebius					 error, evdns_err_to_string(error));
904290001Sglebius				nameserver_failed(req->ns, msg);
905290001Sglebius				if (!request_reissue(req)) return;
906290001Sglebius			}
907290001Sglebius			break;
908290001Sglebius		case DNS_ERR_SERVERFAILED:
909290001Sglebius			/* rcode 2 (servfailed) sometimes means "we
910290001Sglebius			 * are broken" and sometimes (with some binds)
911290001Sglebius			 * means "that request was very confusing."
912290001Sglebius			 * Treat this as a timeout, not a failure.
913290001Sglebius			 */
914290001Sglebius			log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver"
915290001Sglebius				"at %s; will allow the request to time out.",
916290001Sglebius			    evutil_format_sockaddr_port_(
917290001Sglebius				    (struct sockaddr *)&req->ns->address,
918290001Sglebius				    addrbuf, sizeof(addrbuf)));
919290001Sglebius			/* Call the timeout function */
920290001Sglebius			evdns_request_timeout_callback(0, 0, req);
921290001Sglebius			return;
922290001Sglebius		default:
923290001Sglebius			/* we got a good reply from the nameserver: it is up. */
924290001Sglebius			if (req->handle == req->ns->probe_request) {
925290001Sglebius				/* Avoid double-free */
926290001Sglebius				req->ns->probe_request = NULL;
927290001Sglebius			}
928290001Sglebius
929290001Sglebius			nameserver_up(req->ns);
930290001Sglebius		}
931290001Sglebius
932290001Sglebius		if (req->handle->search_state &&
933290001Sglebius		    req->request_type != TYPE_PTR) {
934290001Sglebius			/* if we have a list of domains to search in,
935290001Sglebius			 * try the next one */
936290001Sglebius			if (!search_try_next(req->handle)) {
937290001Sglebius				/* a new request was issued so this
938290001Sglebius				 * request is finished and */
939290001Sglebius				/* the user callback will be made when
940290001Sglebius				 * that request (or a */
941290001Sglebius				/* child of it) finishes. */
942290001Sglebius				return;
943290001Sglebius			}
944290001Sglebius		}
945290001Sglebius
946290001Sglebius		/* all else failed. Pass the failure up */
947290001Sglebius		reply_schedule_callback(req, ttl, error, NULL);
948290001Sglebius		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
949290001Sglebius	} else {
950290001Sglebius		/* all ok, tell the user */
951290001Sglebius		reply_schedule_callback(req, ttl, 0, reply);
952290001Sglebius		if (req->handle == req->ns->probe_request)
953290001Sglebius			req->ns->probe_request = NULL; /* Avoid double-free */
954290001Sglebius		nameserver_up(req->ns);
955290001Sglebius		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
956290001Sglebius	}
957290001Sglebius}
958290001Sglebius
959290001Sglebiusstatic int
960290001Sglebiusname_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
961290001Sglebius	int name_end = -1;
962290001Sglebius	int j = *idx;
963290001Sglebius	int ptr_count = 0;
964290001Sglebius#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&t32_, packet + j, 4); j += 4; x = ntohl(t32_); } while (0)
965290001Sglebius#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&t_, packet + j, 2); j += 2; x = ntohs(t_); } while (0)
966290001Sglebius#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while (0)
967290001Sglebius
968290001Sglebius	char *cp = name_out;
969290001Sglebius	const char *const end = name_out + name_out_len;
970290001Sglebius
971290001Sglebius	/* Normally, names are a series of length prefixed strings terminated */
972290001Sglebius	/* with a length of 0 (the lengths are u8's < 63). */
973290001Sglebius	/* However, the length can start with a pair of 1 bits and that */
974290001Sglebius	/* means that the next 14 bits are a pointer within the current */
975290001Sglebius	/* packet. */
976290001Sglebius
977290001Sglebius	for (;;) {
978290001Sglebius		u8 label_len;
979290001Sglebius		if (j >= length) return -1;
980290001Sglebius		GET8(label_len);
981290001Sglebius		if (!label_len) break;
982290001Sglebius		if (label_len & 0xc0) {
983290001Sglebius			u8 ptr_low;
984290001Sglebius			GET8(ptr_low);
985290001Sglebius			if (name_end < 0) name_end = j;
986290001Sglebius			j = (((int)label_len & 0x3f) << 8) + ptr_low;
987290001Sglebius			/* Make sure that the target offset is in-bounds. */
988290001Sglebius			if (j < 0 || j >= length) return -1;
989290001Sglebius			/* If we've jumped more times than there are characters in the
990290001Sglebius			 * message, we must have a loop. */
991290001Sglebius			if (++ptr_count > length) return -1;
992290001Sglebius			continue;
993290001Sglebius		}
994290001Sglebius		if (label_len > 63) return -1;
995290001Sglebius		if (cp != name_out) {
996290001Sglebius			if (cp + 1 >= end) return -1;
997290001Sglebius			*cp++ = '.';
998290001Sglebius		}
999290001Sglebius		if (cp + label_len >= end) return -1;
1000290001Sglebius		memcpy(cp, packet + j, label_len);
1001290001Sglebius		cp += label_len;
1002290001Sglebius		j += label_len;
1003290001Sglebius	}
1004290001Sglebius	if (cp >= end) return -1;
1005290001Sglebius	*cp = '\0';
1006290001Sglebius	if (name_end < 0)
1007290001Sglebius		*idx = j;
1008290001Sglebius	else
1009290001Sglebius		*idx = name_end;
1010290001Sglebius	return 0;
1011290001Sglebius err:
1012290001Sglebius	return -1;
1013290001Sglebius}
1014290001Sglebius
1015290001Sglebius/* parses a raw request from a nameserver */
1016290001Sglebiusstatic int
1017290001Sglebiusreply_parse(struct evdns_base *base, u8 *packet, int length) {
1018290001Sglebius	int j = 0, k = 0;  /* index into packet */
1019290001Sglebius	u16 t_;	 /* used by the macros */
1020290001Sglebius	u32 t32_;  /* used by the macros */
1021290001Sglebius	char tmp_name[256], cmp_name[256]; /* used by the macros */
1022290001Sglebius	int name_matches = 0;
1023290001Sglebius
1024290001Sglebius	u16 trans_id, questions, answers, authority, additional, datalength;
1025290001Sglebius	u16 flags = 0;
1026290001Sglebius	u32 ttl, ttl_r = 0xffffffff;
1027290001Sglebius	struct reply reply;
1028290001Sglebius	struct request *req = NULL;
1029290001Sglebius	unsigned int i;
1030290001Sglebius
1031290001Sglebius	ASSERT_LOCKED(base);
1032290001Sglebius
1033290001Sglebius	GET16(trans_id);
1034290001Sglebius	GET16(flags);
1035290001Sglebius	GET16(questions);
1036290001Sglebius	GET16(answers);
1037290001Sglebius	GET16(authority);
1038290001Sglebius	GET16(additional);
1039290001Sglebius	(void) authority; /* suppress "unused variable" warnings. */
1040290001Sglebius	(void) additional; /* suppress "unused variable" warnings. */
1041290001Sglebius
1042290001Sglebius	req = request_find_from_trans_id(base, trans_id);
1043290001Sglebius	if (!req) return -1;
1044290001Sglebius	EVUTIL_ASSERT(req->base == base);
1045290001Sglebius
1046290001Sglebius	memset(&reply, 0, sizeof(reply));
1047290001Sglebius
1048290001Sglebius	/* If it's not an answer, it doesn't correspond to any request. */
1049290001Sglebius	if (!(flags & 0x8000)) return -1;  /* must be an answer */
1050290001Sglebius	if ((flags & 0x020f) && (flags & 0x020f) != DNS_ERR_NOTEXIST) {
1051290001Sglebius		/* there was an error and it's not NXDOMAIN */
1052290001Sglebius		goto err;
1053290001Sglebius	}
1054290001Sglebius	/* if (!answers) return; */  /* must have an answer of some form */
1055290001Sglebius
1056290001Sglebius	/* This macro skips a name in the DNS reply. */
1057290001Sglebius#define SKIP_NAME						\
1058290001Sglebius	do { tmp_name[0] = '\0';				\
1059290001Sglebius		if (name_parse(packet, length, &j, tmp_name,	\
1060290001Sglebius			sizeof(tmp_name))<0)			\
1061290001Sglebius			goto err;				\
1062290001Sglebius	} while (0)
1063290001Sglebius#define TEST_NAME							\
1064290001Sglebius	do { tmp_name[0] = '\0';					\
1065290001Sglebius		cmp_name[0] = '\0';					\
1066290001Sglebius		k = j;							\
1067290001Sglebius		if (name_parse(packet, length, &j, tmp_name,		\
1068290001Sglebius			sizeof(tmp_name))<0)				\
1069290001Sglebius			goto err;					\
1070290001Sglebius		if (name_parse(req->request, req->request_len, &k,	\
1071290001Sglebius			cmp_name, sizeof(cmp_name))<0)			\
1072290001Sglebius			goto err;					\
1073290001Sglebius		if (base->global_randomize_case) {			\
1074290001Sglebius			if (strcmp(tmp_name, cmp_name) == 0)		\
1075290001Sglebius				name_matches = 1;			\
1076290001Sglebius		} else {						\
1077290001Sglebius			if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0) \
1078290001Sglebius				name_matches = 1;			\
1079290001Sglebius		}							\
1080290001Sglebius	} while (0)
1081290001Sglebius
1082290001Sglebius	reply.type = req->request_type;
1083290001Sglebius
1084290001Sglebius	/* skip over each question in the reply */
1085290001Sglebius	for (i = 0; i < questions; ++i) {
1086290001Sglebius		/* the question looks like
1087290001Sglebius		 *   <label:name><u16:type><u16:class>
1088290001Sglebius		 */
1089290001Sglebius		TEST_NAME;
1090290001Sglebius		j += 4;
1091290001Sglebius		if (j > length) goto err;
1092290001Sglebius	}
1093290001Sglebius
1094290001Sglebius	if (!name_matches)
1095290001Sglebius		goto err;
1096290001Sglebius
1097290001Sglebius	/* now we have the answer section which looks like
1098290001Sglebius	 * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
1099290001Sglebius	 */
1100290001Sglebius
1101290001Sglebius	for (i = 0; i < answers; ++i) {
1102290001Sglebius		u16 type, class;
1103290001Sglebius
1104290001Sglebius		SKIP_NAME;
1105290001Sglebius		GET16(type);
1106290001Sglebius		GET16(class);
1107290001Sglebius		GET32(ttl);
1108290001Sglebius		GET16(datalength);
1109290001Sglebius
1110290001Sglebius		if (type == TYPE_A && class == CLASS_INET) {
1111290001Sglebius			int addrcount, addrtocopy;
1112290001Sglebius			if (req->request_type != TYPE_A) {
1113290001Sglebius				j += datalength; continue;
1114290001Sglebius			}
1115290001Sglebius			if ((datalength & 3) != 0) /* not an even number of As. */
1116290001Sglebius			    goto err;
1117290001Sglebius			addrcount = datalength >> 2;
1118290001Sglebius			addrtocopy = MIN(MAX_V4_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
1119290001Sglebius
1120290001Sglebius			ttl_r = MIN(ttl_r, ttl);
1121290001Sglebius			/* we only bother with the first four addresses. */
1122290001Sglebius			if (j + 4*addrtocopy > length) goto err;
1123290001Sglebius			memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
1124290001Sglebius				   packet + j, 4*addrtocopy);
1125290001Sglebius			j += 4*addrtocopy;
1126290001Sglebius			reply.data.a.addrcount += addrtocopy;
1127290001Sglebius			reply.have_answer = 1;
1128290001Sglebius			if (reply.data.a.addrcount == MAX_V4_ADDRS) break;
1129290001Sglebius		} else if (type == TYPE_PTR && class == CLASS_INET) {
1130290001Sglebius			if (req->request_type != TYPE_PTR) {
1131290001Sglebius				j += datalength; continue;
1132290001Sglebius			}
1133290001Sglebius			if (name_parse(packet, length, &j, reply.data.ptr.name,
1134290001Sglebius						   sizeof(reply.data.ptr.name))<0)
1135290001Sglebius				goto err;
1136290001Sglebius			ttl_r = MIN(ttl_r, ttl);
1137290001Sglebius			reply.have_answer = 1;
1138290001Sglebius			break;
1139290001Sglebius		} else if (type == TYPE_CNAME) {
1140290001Sglebius			char cname[HOST_NAME_MAX];
1141290001Sglebius			if (!req->put_cname_in_ptr || *req->put_cname_in_ptr) {
1142290001Sglebius				j += datalength; continue;
1143290001Sglebius			}
1144290001Sglebius			if (name_parse(packet, length, &j, cname,
1145290001Sglebius				sizeof(cname))<0)
1146290001Sglebius				goto err;
1147290001Sglebius			*req->put_cname_in_ptr = mm_strdup(cname);
1148290001Sglebius		} else if (type == TYPE_AAAA && class == CLASS_INET) {
1149290001Sglebius			int addrcount, addrtocopy;
1150290001Sglebius			if (req->request_type != TYPE_AAAA) {
1151290001Sglebius				j += datalength; continue;
1152290001Sglebius			}
1153290001Sglebius			if ((datalength & 15) != 0) /* not an even number of AAAAs. */
1154290001Sglebius				goto err;
1155290001Sglebius			addrcount = datalength >> 4;  /* each address is 16 bytes long */
1156290001Sglebius			addrtocopy = MIN(MAX_V6_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
1157290001Sglebius			ttl_r = MIN(ttl_r, ttl);
1158290001Sglebius
1159290001Sglebius			/* we only bother with the first four addresses. */
1160290001Sglebius			if (j + 16*addrtocopy > length) goto err;
1161290001Sglebius			memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
1162290001Sglebius				   packet + j, 16*addrtocopy);
1163290001Sglebius			reply.data.aaaa.addrcount += addrtocopy;
1164290001Sglebius			j += 16*addrtocopy;
1165290001Sglebius			reply.have_answer = 1;
1166290001Sglebius			if (reply.data.aaaa.addrcount == MAX_V6_ADDRS) break;
1167290001Sglebius		} else {
1168290001Sglebius			/* skip over any other type of resource */
1169290001Sglebius			j += datalength;
1170290001Sglebius		}
1171290001Sglebius	}
1172290001Sglebius
1173290001Sglebius	if (!reply.have_answer) {
1174290001Sglebius		for (i = 0; i < authority; ++i) {
1175290001Sglebius			u16 type, class;
1176290001Sglebius			SKIP_NAME;
1177290001Sglebius			GET16(type);
1178290001Sglebius			GET16(class);
1179290001Sglebius			GET32(ttl);
1180290001Sglebius			GET16(datalength);
1181290001Sglebius			if (type == TYPE_SOA && class == CLASS_INET) {
1182290001Sglebius				u32 serial, refresh, retry, expire, minimum;
1183290001Sglebius				SKIP_NAME;
1184290001Sglebius				SKIP_NAME;
1185290001Sglebius				GET32(serial);
1186290001Sglebius				GET32(refresh);
1187290001Sglebius				GET32(retry);
1188290001Sglebius				GET32(expire);
1189290001Sglebius				GET32(minimum);
1190290001Sglebius				(void)expire;
1191290001Sglebius				(void)retry;
1192290001Sglebius				(void)refresh;
1193290001Sglebius				(void)serial;
1194290001Sglebius				ttl_r = MIN(ttl_r, ttl);
1195290001Sglebius				ttl_r = MIN(ttl_r, minimum);
1196290001Sglebius			} else {
1197290001Sglebius				/* skip over any other type of resource */
1198290001Sglebius				j += datalength;
1199290001Sglebius			}
1200290001Sglebius		}
1201290001Sglebius	}
1202290001Sglebius
1203290001Sglebius	if (ttl_r == 0xffffffff)
1204290001Sglebius		ttl_r = 0;
1205290001Sglebius
1206290001Sglebius	reply_handle(req, flags, ttl_r, &reply);
1207290001Sglebius	return 0;
1208290001Sglebius err:
1209290001Sglebius	if (req)
1210290001Sglebius		reply_handle(req, flags, 0, NULL);
1211290001Sglebius	return -1;
1212290001Sglebius}
1213290001Sglebius
1214290001Sglebius/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
1215290001Sglebius/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
1216290001Sglebius/* callback. */
1217290001Sglebiusstatic int
1218290001Sglebiusrequest_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, ev_socklen_t addrlen)
1219290001Sglebius{
1220290001Sglebius	int j = 0;	/* index into packet */
1221290001Sglebius	u16 t_;	 /* used by the macros */
1222290001Sglebius	char tmp_name[256]; /* used by the macros */
1223290001Sglebius
1224290001Sglebius	int i;
1225290001Sglebius	u16 trans_id, flags, questions, answers, authority, additional;
1226290001Sglebius	struct server_request *server_req = NULL;
1227290001Sglebius
1228290001Sglebius	ASSERT_LOCKED(port);
1229290001Sglebius
1230290001Sglebius	/* Get the header fields */
1231290001Sglebius	GET16(trans_id);
1232290001Sglebius	GET16(flags);
1233290001Sglebius	GET16(questions);
1234290001Sglebius	GET16(answers);
1235290001Sglebius	GET16(authority);
1236290001Sglebius	GET16(additional);
1237290001Sglebius	(void)answers;
1238290001Sglebius	(void)additional;
1239290001Sglebius	(void)authority;
1240290001Sglebius
1241290001Sglebius	if (flags & 0x8000) return -1; /* Must not be an answer. */
1242290001Sglebius	flags &= 0x0110; /* Only RD and CD get preserved. */
1243290001Sglebius
1244290001Sglebius	server_req = mm_malloc(sizeof(struct server_request));
1245290001Sglebius	if (server_req == NULL) return -1;
1246290001Sglebius	memset(server_req, 0, sizeof(struct server_request));
1247290001Sglebius
1248290001Sglebius	server_req->trans_id = trans_id;
1249290001Sglebius	memcpy(&server_req->addr, addr, addrlen);
1250290001Sglebius	server_req->addrlen = addrlen;
1251290001Sglebius
1252290001Sglebius	server_req->base.flags = flags;
1253290001Sglebius	server_req->base.nquestions = 0;
1254290001Sglebius	server_req->base.questions = mm_calloc(sizeof(struct evdns_server_question *), questions);
1255290001Sglebius	if (server_req->base.questions == NULL)
1256290001Sglebius		goto err;
1257290001Sglebius
1258290001Sglebius	for (i = 0; i < questions; ++i) {
1259290001Sglebius		u16 type, class;
1260290001Sglebius		struct evdns_server_question *q;
1261290001Sglebius		int namelen;
1262290001Sglebius		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
1263290001Sglebius			goto err;
1264290001Sglebius		GET16(type);
1265290001Sglebius		GET16(class);
1266290001Sglebius		namelen = (int)strlen(tmp_name);
1267290001Sglebius		q = mm_malloc(sizeof(struct evdns_server_question) + namelen);
1268290001Sglebius		if (!q)
1269290001Sglebius			goto err;
1270290001Sglebius		q->type = type;
1271290001Sglebius		q->dns_question_class = class;
1272290001Sglebius		memcpy(q->name, tmp_name, namelen+1);
1273290001Sglebius		server_req->base.questions[server_req->base.nquestions++] = q;
1274290001Sglebius	}
1275290001Sglebius
1276290001Sglebius	/* Ignore answers, authority, and additional. */
1277290001Sglebius
1278290001Sglebius	server_req->port = port;
1279290001Sglebius	port->refcnt++;
1280290001Sglebius
1281290001Sglebius	/* Only standard queries are supported. */
1282290001Sglebius	if (flags & 0x7800) {
1283290001Sglebius		evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
1284290001Sglebius		return -1;
1285290001Sglebius	}
1286290001Sglebius
1287290001Sglebius	port->user_callback(&(server_req->base), port->user_data);
1288290001Sglebius
1289290001Sglebius	return 0;
1290290001Sglebiuserr:
1291290001Sglebius	if (server_req) {
1292290001Sglebius		if (server_req->base.questions) {
1293290001Sglebius			for (i = 0; i < server_req->base.nquestions; ++i)
1294290001Sglebius				mm_free(server_req->base.questions[i]);
1295290001Sglebius			mm_free(server_req->base.questions);
1296290001Sglebius		}
1297290001Sglebius		mm_free(server_req);
1298290001Sglebius	}
1299290001Sglebius	return -1;
1300290001Sglebius
1301290001Sglebius#undef SKIP_NAME
1302290001Sglebius#undef GET32
1303290001Sglebius#undef GET16
1304290001Sglebius#undef GET8
1305290001Sglebius}
1306290001Sglebius
1307290001Sglebius
1308290001Sglebiusvoid
1309290001Sglebiusevdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
1310290001Sglebius{
1311290001Sglebius}
1312290001Sglebius
1313290001Sglebiusvoid
1314290001Sglebiusevdns_set_random_bytes_fn(void (*fn)(char *, size_t))
1315290001Sglebius{
1316290001Sglebius}
1317290001Sglebius
1318290001Sglebius/* Try to choose a strong transaction id which isn't already in flight */
1319290001Sglebiusstatic u16
1320290001Sglebiustransaction_id_pick(struct evdns_base *base) {
1321290001Sglebius	ASSERT_LOCKED(base);
1322290001Sglebius	for (;;) {
1323290001Sglebius		u16 trans_id;
1324290001Sglebius		evutil_secure_rng_get_bytes(&trans_id, sizeof(trans_id));
1325290001Sglebius
1326290001Sglebius		if (trans_id == 0xffff) continue;
1327290001Sglebius		/* now check to see if that id is already inflight */
1328290001Sglebius		if (request_find_from_trans_id(base, trans_id) == NULL)
1329290001Sglebius			return trans_id;
1330290001Sglebius	}
1331290001Sglebius}
1332290001Sglebius
1333290001Sglebius/* choose a namesever to use. This function will try to ignore */
1334290001Sglebius/* nameservers which we think are down and load balance across the rest */
1335290001Sglebius/* by updating the server_head global each time. */
1336290001Sglebiusstatic struct nameserver *
1337290001Sglebiusnameserver_pick(struct evdns_base *base) {
1338290001Sglebius	struct nameserver *started_at = base->server_head, *picked;
1339290001Sglebius	ASSERT_LOCKED(base);
1340290001Sglebius	if (!base->server_head) return NULL;
1341290001Sglebius
1342290001Sglebius	/* if we don't have any good nameservers then there's no */
1343290001Sglebius	/* point in trying to find one. */
1344290001Sglebius	if (!base->global_good_nameservers) {
1345290001Sglebius		base->server_head = base->server_head->next;
1346290001Sglebius		return base->server_head;
1347290001Sglebius	}
1348290001Sglebius
1349290001Sglebius	/* remember that nameservers are in a circular list */
1350290001Sglebius	for (;;) {
1351290001Sglebius		if (base->server_head->state) {
1352290001Sglebius			/* we think this server is currently good */
1353290001Sglebius			picked = base->server_head;
1354290001Sglebius			base->server_head = base->server_head->next;
1355290001Sglebius			return picked;
1356290001Sglebius		}
1357290001Sglebius
1358290001Sglebius		base->server_head = base->server_head->next;
1359290001Sglebius		if (base->server_head == started_at) {
1360290001Sglebius			/* all the nameservers seem to be down */
1361290001Sglebius			/* so we just return this one and hope for the */
1362290001Sglebius			/* best */
1363290001Sglebius			EVUTIL_ASSERT(base->global_good_nameservers == 0);
1364290001Sglebius			picked = base->server_head;
1365290001Sglebius			base->server_head = base->server_head->next;
1366290001Sglebius			return picked;
1367290001Sglebius		}
1368290001Sglebius	}
1369290001Sglebius}
1370290001Sglebius
1371290001Sglebius/* this is called when a namesever socket is ready for reading */
1372290001Sglebiusstatic void
1373290001Sglebiusnameserver_read(struct nameserver *ns) {
1374290001Sglebius	struct sockaddr_storage ss;
1375290001Sglebius	ev_socklen_t addrlen = sizeof(ss);
1376290001Sglebius	u8 packet[1500];
1377290001Sglebius	char addrbuf[128];
1378290001Sglebius	ASSERT_LOCKED(ns->base);
1379290001Sglebius
1380290001Sglebius	for (;;) {
1381290001Sglebius		const int r = recvfrom(ns->socket, (void*)packet,
1382290001Sglebius		    sizeof(packet), 0,
1383290001Sglebius		    (struct sockaddr*)&ss, &addrlen);
1384290001Sglebius		if (r < 0) {
1385290001Sglebius			int err = evutil_socket_geterror(ns->socket);
1386290001Sglebius			if (EVUTIL_ERR_RW_RETRIABLE(err))
1387290001Sglebius				return;
1388290001Sglebius			nameserver_failed(ns,
1389290001Sglebius			    evutil_socket_error_to_string(err));
1390290001Sglebius			return;
1391290001Sglebius		}
1392290001Sglebius		if (evutil_sockaddr_cmp((struct sockaddr*)&ss,
1393290001Sglebius			(struct sockaddr*)&ns->address, 0)) {
1394290001Sglebius			log(EVDNS_LOG_WARN, "Address mismatch on received "
1395290001Sglebius			    "DNS packet.  Apparent source was %s",
1396290001Sglebius			    evutil_format_sockaddr_port_(
1397290001Sglebius				    (struct sockaddr *)&ss,
1398290001Sglebius				    addrbuf, sizeof(addrbuf)));
1399290001Sglebius			return;
1400290001Sglebius		}
1401290001Sglebius
1402290001Sglebius		ns->timedout = 0;
1403290001Sglebius		reply_parse(ns->base, packet, r);
1404290001Sglebius	}
1405290001Sglebius}
1406290001Sglebius
1407290001Sglebius/* Read a packet from a DNS client on a server port s, parse it, and */
1408290001Sglebius/* act accordingly. */
1409290001Sglebiusstatic void
1410290001Sglebiusserver_port_read(struct evdns_server_port *s) {
1411290001Sglebius	u8 packet[1500];
1412290001Sglebius	struct sockaddr_storage addr;
1413290001Sglebius	ev_socklen_t addrlen;
1414290001Sglebius	int r;
1415290001Sglebius	ASSERT_LOCKED(s);
1416290001Sglebius
1417290001Sglebius	for (;;) {
1418290001Sglebius		addrlen = sizeof(struct sockaddr_storage);
1419290001Sglebius		r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0,
1420290001Sglebius					 (struct sockaddr*) &addr, &addrlen);
1421290001Sglebius		if (r < 0) {
1422290001Sglebius			int err = evutil_socket_geterror(s->socket);
1423290001Sglebius			if (EVUTIL_ERR_RW_RETRIABLE(err))
1424290001Sglebius				return;
1425290001Sglebius			log(EVDNS_LOG_WARN,
1426290001Sglebius			    "Error %s (%d) while reading request.",
1427290001Sglebius			    evutil_socket_error_to_string(err), err);
1428290001Sglebius			return;
1429290001Sglebius		}
1430290001Sglebius		request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
1431290001Sglebius	}
1432290001Sglebius}
1433290001Sglebius
1434290001Sglebius/* Try to write all pending replies on a given DNS server port. */
1435290001Sglebiusstatic void
1436290001Sglebiusserver_port_flush(struct evdns_server_port *port)
1437290001Sglebius{
1438290001Sglebius	struct server_request *req = port->pending_replies;
1439290001Sglebius	ASSERT_LOCKED(port);
1440290001Sglebius	while (req) {
1441290001Sglebius		int r = sendto(port->socket, req->response, (int)req->response_len, 0,
1442290001Sglebius			   (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
1443290001Sglebius		if (r < 0) {
1444290001Sglebius			int err = evutil_socket_geterror(port->socket);
1445290001Sglebius			if (EVUTIL_ERR_RW_RETRIABLE(err))
1446290001Sglebius				return;
1447290001Sglebius			log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", evutil_socket_error_to_string(err), err);
1448290001Sglebius		}
1449290001Sglebius		if (server_request_free(req)) {
1450290001Sglebius			/* we released the last reference to req->port. */
1451290001Sglebius			return;
1452290001Sglebius		} else {
1453290001Sglebius			EVUTIL_ASSERT(req != port->pending_replies);
1454290001Sglebius			req = port->pending_replies;
1455290001Sglebius		}
1456290001Sglebius	}
1457290001Sglebius
1458290001Sglebius	/* We have no more pending requests; stop listening for 'writeable' events. */
1459290001Sglebius	(void) event_del(&port->event);
1460290001Sglebius	event_assign(&port->event, port->event_base,
1461290001Sglebius				 port->socket, EV_READ | EV_PERSIST,
1462290001Sglebius				 server_port_ready_callback, port);
1463290001Sglebius
1464290001Sglebius	if (event_add(&port->event, NULL) < 0) {
1465290001Sglebius		log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
1466290001Sglebius		/* ???? Do more? */
1467290001Sglebius	}
1468290001Sglebius}
1469290001Sglebius
1470290001Sglebius/* set if we are waiting for the ability to write to this server. */
1471290001Sglebius/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
1472290001Sglebius/* we stop these events. */
1473290001Sglebiusstatic void
1474290001Sglebiusnameserver_write_waiting(struct nameserver *ns, char waiting) {
1475290001Sglebius	ASSERT_LOCKED(ns->base);
1476290001Sglebius	if (ns->write_waiting == waiting) return;
1477290001Sglebius
1478290001Sglebius	ns->write_waiting = waiting;
1479290001Sglebius	(void) event_del(&ns->event);
1480290001Sglebius	event_assign(&ns->event, ns->base->event_base,
1481290001Sglebius	    ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
1482290001Sglebius	    nameserver_ready_callback, ns);
1483290001Sglebius	if (event_add(&ns->event, NULL) < 0) {
1484290001Sglebius		char addrbuf[128];
1485290001Sglebius		log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
1486290001Sglebius		    evutil_format_sockaddr_port_(
1487290001Sglebius			    (struct sockaddr *)&ns->address,
1488290001Sglebius			    addrbuf, sizeof(addrbuf)));
1489290001Sglebius		/* ???? Do more? */
1490290001Sglebius	}
1491290001Sglebius}
1492290001Sglebius
1493290001Sglebius/* a callback function. Called by libevent when the kernel says that */
1494290001Sglebius/* a nameserver socket is ready for writing or reading */
1495290001Sglebiusstatic void
1496290001Sglebiusnameserver_ready_callback(evutil_socket_t fd, short events, void *arg) {
1497290001Sglebius	struct nameserver *ns = (struct nameserver *) arg;
1498290001Sglebius	(void)fd;
1499290001Sglebius
1500290001Sglebius	EVDNS_LOCK(ns->base);
1501290001Sglebius	if (events & EV_WRITE) {
1502290001Sglebius		ns->choked = 0;
1503290001Sglebius		if (!evdns_transmit(ns->base)) {
1504290001Sglebius			nameserver_write_waiting(ns, 0);
1505290001Sglebius		}
1506290001Sglebius	}
1507290001Sglebius	if (events & EV_READ) {
1508290001Sglebius		nameserver_read(ns);
1509290001Sglebius	}
1510290001Sglebius	EVDNS_UNLOCK(ns->base);
1511290001Sglebius}
1512290001Sglebius
1513290001Sglebius/* a callback function. Called by libevent when the kernel says that */
1514290001Sglebius/* a server socket is ready for writing or reading. */
1515290001Sglebiusstatic void
1516290001Sglebiusserver_port_ready_callback(evutil_socket_t fd, short events, void *arg) {
1517290001Sglebius	struct evdns_server_port *port = (struct evdns_server_port *) arg;
1518290001Sglebius	(void) fd;
1519290001Sglebius
1520290001Sglebius	EVDNS_LOCK(port);
1521290001Sglebius	if (events & EV_WRITE) {
1522290001Sglebius		port->choked = 0;
1523290001Sglebius		server_port_flush(port);
1524290001Sglebius	}
1525290001Sglebius	if (events & EV_READ) {
1526290001Sglebius		server_port_read(port);
1527290001Sglebius	}
1528290001Sglebius	EVDNS_UNLOCK(port);
1529290001Sglebius}
1530290001Sglebius
1531290001Sglebius/* This is an inefficient representation; only use it via the dnslabel_table_*
1532290001Sglebius * functions, so that is can be safely replaced with something smarter later. */
1533290001Sglebius#define MAX_LABELS 128
1534290001Sglebius/* Structures used to implement name compression */
1535290001Sglebiusstruct dnslabel_entry { char *v; off_t pos; };
1536290001Sglebiusstruct dnslabel_table {
1537290001Sglebius	int n_labels; /* number of current entries */
1538290001Sglebius	/* map from name to position in message */
1539290001Sglebius	struct dnslabel_entry labels[MAX_LABELS];
1540290001Sglebius};
1541290001Sglebius
1542290001Sglebius/* Initialize dnslabel_table. */
1543290001Sglebiusstatic void
1544290001Sglebiusdnslabel_table_init(struct dnslabel_table *table)
1545290001Sglebius{
1546290001Sglebius	table->n_labels = 0;
1547290001Sglebius}
1548290001Sglebius
1549290001Sglebius/* Free all storage held by table, but not the table itself. */
1550290001Sglebiusstatic void
1551290001Sglebiusdnslabel_clear(struct dnslabel_table *table)
1552290001Sglebius{
1553290001Sglebius	int i;
1554290001Sglebius	for (i = 0; i < table->n_labels; ++i)
1555290001Sglebius		mm_free(table->labels[i].v);
1556290001Sglebius	table->n_labels = 0;
1557290001Sglebius}
1558290001Sglebius
1559290001Sglebius/* return the position of the label in the current message, or -1 if the label */
1560290001Sglebius/* hasn't been used yet. */
1561290001Sglebiusstatic int
1562290001Sglebiusdnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
1563290001Sglebius{
1564290001Sglebius	int i;
1565290001Sglebius	for (i = 0; i < table->n_labels; ++i) {
1566290001Sglebius		if (!strcmp(label, table->labels[i].v))
1567290001Sglebius			return table->labels[i].pos;
1568290001Sglebius	}
1569290001Sglebius	return -1;
1570290001Sglebius}
1571290001Sglebius
1572290001Sglebius/* remember that we've used the label at position pos */
1573290001Sglebiusstatic int
1574290001Sglebiusdnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
1575290001Sglebius{
1576290001Sglebius	char *v;
1577290001Sglebius	int p;
1578290001Sglebius	if (table->n_labels == MAX_LABELS)
1579290001Sglebius		return (-1);
1580290001Sglebius	v = mm_strdup(label);
1581290001Sglebius	if (v == NULL)
1582290001Sglebius		return (-1);
1583290001Sglebius	p = table->n_labels++;
1584290001Sglebius	table->labels[p].v = v;
1585290001Sglebius	table->labels[p].pos = pos;
1586290001Sglebius
1587290001Sglebius	return (0);
1588290001Sglebius}
1589290001Sglebius
1590290001Sglebius/* Converts a string to a length-prefixed set of DNS labels, starting */
1591290001Sglebius/* at buf[j]. name and buf must not overlap. name_len should be the length */
1592290001Sglebius/* of name.	 table is optional, and is used for compression. */
1593290001Sglebius/* */
1594290001Sglebius/* Input: abc.def */
1595290001Sglebius/* Output: <3>abc<3>def<0> */
1596290001Sglebius/* */
1597290001Sglebius/* Returns the first index after the encoded name, or negative on error. */
1598290001Sglebius/*	 -1	 label was > 63 bytes */
1599290001Sglebius/*	 -2	 name too long to fit in buffer. */
1600290001Sglebius/* */
1601290001Sglebiusstatic off_t
1602290001Sglebiusdnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
1603290001Sglebius				  const char *name, const size_t name_len,
1604290001Sglebius				  struct dnslabel_table *table) {
1605290001Sglebius	const char *end = name + name_len;
1606290001Sglebius	int ref = 0;
1607290001Sglebius	u16 t_;
1608290001Sglebius
1609290001Sglebius#define APPEND16(x) do {						\
1610290001Sglebius		if (j + 2 > (off_t)buf_len)				\
1611290001Sglebius			goto overflow;					\
1612290001Sglebius		t_ = htons(x);						\
1613290001Sglebius		memcpy(buf + j, &t_, 2);				\
1614290001Sglebius		j += 2;							\
1615290001Sglebius	} while (0)
1616290001Sglebius#define APPEND32(x) do {						\
1617290001Sglebius		if (j + 4 > (off_t)buf_len)				\
1618290001Sglebius			goto overflow;					\
1619290001Sglebius		t32_ = htonl(x);					\
1620290001Sglebius		memcpy(buf + j, &t32_, 4);				\
1621290001Sglebius		j += 4;							\
1622290001Sglebius	} while (0)
1623290001Sglebius
1624290001Sglebius	if (name_len > 255) return -2;
1625290001Sglebius
1626290001Sglebius	for (;;) {
1627290001Sglebius		const char *const start = name;
1628290001Sglebius		if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
1629290001Sglebius			APPEND16(ref | 0xc000);
1630290001Sglebius			return j;
1631290001Sglebius		}
1632290001Sglebius		name = strchr(name, '.');
1633290001Sglebius		if (!name) {
1634290001Sglebius			const size_t label_len = end - start;
1635290001Sglebius			if (label_len > 63) return -1;
1636290001Sglebius			if ((size_t)(j+label_len+1) > buf_len) return -2;
1637290001Sglebius			if (table) dnslabel_table_add(table, start, j);
1638290001Sglebius			buf[j++] = (ev_uint8_t)label_len;
1639290001Sglebius
1640290001Sglebius			memcpy(buf + j, start, label_len);
1641290001Sglebius			j += (int) label_len;
1642290001Sglebius			break;
1643290001Sglebius		} else {
1644290001Sglebius			/* append length of the label. */
1645290001Sglebius			const size_t label_len = name - start;
1646290001Sglebius			if (label_len > 63) return -1;
1647290001Sglebius			if ((size_t)(j+label_len+1) > buf_len) return -2;
1648290001Sglebius			if (table) dnslabel_table_add(table, start, j);
1649290001Sglebius			buf[j++] = (ev_uint8_t)label_len;
1650290001Sglebius
1651290001Sglebius			memcpy(buf + j, start, label_len);
1652290001Sglebius			j += (int) label_len;
1653290001Sglebius			/* hop over the '.' */
1654290001Sglebius			name++;
1655290001Sglebius		}
1656290001Sglebius	}
1657290001Sglebius
1658290001Sglebius	/* the labels must be terminated by a 0. */
1659290001Sglebius	/* It's possible that the name ended in a . */
1660290001Sglebius	/* in which case the zero is already there */
1661290001Sglebius	if (!j || buf[j-1]) buf[j++] = 0;
1662290001Sglebius	return j;
1663290001Sglebius overflow:
1664290001Sglebius	return (-2);
1665290001Sglebius}
1666290001Sglebius
1667290001Sglebius/* Finds the length of a dns request for a DNS name of the given */
1668290001Sglebius/* length. The actual request may be smaller than the value returned */
1669290001Sglebius/* here */
1670290001Sglebiusstatic size_t
1671290001Sglebiusevdns_request_len(const size_t name_len) {
1672290001Sglebius	return 96 + /* length of the DNS standard header */
1673290001Sglebius		name_len + 2 +
1674290001Sglebius		4;  /* space for the resource type */
1675290001Sglebius}
1676290001Sglebius
1677290001Sglebius/* build a dns request packet into buf. buf should be at least as long */
1678290001Sglebius/* as evdns_request_len told you it should be. */
1679290001Sglebius/* */
1680290001Sglebius/* Returns the amount of space used. Negative on error. */
1681290001Sglebiusstatic int
1682290001Sglebiusevdns_request_data_build(const char *const name, const size_t name_len,
1683290001Sglebius    const u16 trans_id, const u16 type, const u16 class,
1684290001Sglebius    u8 *const buf, size_t buf_len) {
1685290001Sglebius	off_t j = 0;  /* current offset into buf */
1686290001Sglebius	u16 t_;	 /* used by the macros */
1687290001Sglebius
1688290001Sglebius	APPEND16(trans_id);
1689290001Sglebius	APPEND16(0x0100);  /* standard query, recusion needed */
1690290001Sglebius	APPEND16(1);  /* one question */
1691290001Sglebius	APPEND16(0);  /* no answers */
1692290001Sglebius	APPEND16(0);  /* no authority */
1693290001Sglebius	APPEND16(0);  /* no additional */
1694290001Sglebius
1695290001Sglebius	j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
1696290001Sglebius	if (j < 0) {
1697290001Sglebius		return (int)j;
1698290001Sglebius	}
1699290001Sglebius
1700290001Sglebius	APPEND16(type);
1701290001Sglebius	APPEND16(class);
1702290001Sglebius
1703290001Sglebius	return (int)j;
1704290001Sglebius overflow:
1705290001Sglebius	return (-1);
1706290001Sglebius}
1707290001Sglebius
1708290001Sglebius/* exported function */
1709290001Sglebiusstruct evdns_server_port *
1710290001Sglebiusevdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
1711290001Sglebius{
1712290001Sglebius	struct evdns_server_port *port;
1713290001Sglebius	if (flags)
1714290001Sglebius		return NULL; /* flags not yet implemented */
1715290001Sglebius	if (!(port = mm_malloc(sizeof(struct evdns_server_port))))
1716290001Sglebius		return NULL;
1717290001Sglebius	memset(port, 0, sizeof(struct evdns_server_port));
1718290001Sglebius
1719290001Sglebius
1720290001Sglebius	port->socket = socket;
1721290001Sglebius	port->refcnt = 1;
1722290001Sglebius	port->choked = 0;
1723290001Sglebius	port->closing = 0;
1724290001Sglebius	port->user_callback = cb;
1725290001Sglebius	port->user_data = user_data;
1726290001Sglebius	port->pending_replies = NULL;
1727290001Sglebius	port->event_base = base;
1728290001Sglebius
1729290001Sglebius	event_assign(&port->event, port->event_base,
1730290001Sglebius				 port->socket, EV_READ | EV_PERSIST,
1731290001Sglebius				 server_port_ready_callback, port);
1732290001Sglebius	if (event_add(&port->event, NULL) < 0) {
1733290001Sglebius		mm_free(port);
1734290001Sglebius		return NULL;
1735290001Sglebius	}
1736290001Sglebius	EVTHREAD_ALLOC_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
1737290001Sglebius	return port;
1738290001Sglebius}
1739290001Sglebius
1740290001Sglebiusstruct evdns_server_port *
1741290001Sglebiusevdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
1742290001Sglebius{
1743290001Sglebius	return evdns_add_server_port_with_base(NULL, socket, flags, cb, user_data);
1744290001Sglebius}
1745290001Sglebius
1746290001Sglebius/* exported function */
1747290001Sglebiusvoid
1748290001Sglebiusevdns_close_server_port(struct evdns_server_port *port)
1749290001Sglebius{
1750290001Sglebius	EVDNS_LOCK(port);
1751290001Sglebius	if (--port->refcnt == 0) {
1752290001Sglebius		EVDNS_UNLOCK(port);
1753290001Sglebius		server_port_free(port);
1754290001Sglebius	} else {
1755290001Sglebius		port->closing = 1;
1756290001Sglebius	}
1757290001Sglebius}
1758290001Sglebius
1759290001Sglebius/* exported function */
1760290001Sglebiusint
1761290001Sglebiusevdns_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)
1762290001Sglebius{
1763290001Sglebius	struct server_request *req = TO_SERVER_REQUEST(req_);
1764290001Sglebius	struct server_reply_item **itemp, *item;
1765290001Sglebius	int *countp;
1766290001Sglebius	int result = -1;
1767290001Sglebius
1768290001Sglebius	EVDNS_LOCK(req->port);
1769290001Sglebius	if (req->response) /* have we already answered? */
1770290001Sglebius		goto done;
1771290001Sglebius
1772290001Sglebius	switch (section) {
1773290001Sglebius	case EVDNS_ANSWER_SECTION:
1774290001Sglebius		itemp = &req->answer;
1775290001Sglebius		countp = &req->n_answer;
1776290001Sglebius		break;
1777290001Sglebius	case EVDNS_AUTHORITY_SECTION:
1778290001Sglebius		itemp = &req->authority;
1779290001Sglebius		countp = &req->n_authority;
1780290001Sglebius		break;
1781290001Sglebius	case EVDNS_ADDITIONAL_SECTION:
1782290001Sglebius		itemp = &req->additional;
1783290001Sglebius		countp = &req->n_additional;
1784290001Sglebius		break;
1785290001Sglebius	default:
1786290001Sglebius		goto done;
1787290001Sglebius	}
1788290001Sglebius	while (*itemp) {
1789290001Sglebius		itemp = &((*itemp)->next);
1790290001Sglebius	}
1791290001Sglebius	item = mm_malloc(sizeof(struct server_reply_item));
1792290001Sglebius	if (!item)
1793290001Sglebius		goto done;
1794290001Sglebius	item->next = NULL;
1795290001Sglebius	if (!(item->name = mm_strdup(name))) {
1796290001Sglebius		mm_free(item);
1797290001Sglebius		goto done;
1798290001Sglebius	}
1799290001Sglebius	item->type = type;
1800290001Sglebius	item->dns_question_class = class;
1801290001Sglebius	item->ttl = ttl;
1802290001Sglebius	item->is_name = is_name != 0;
1803290001Sglebius	item->datalen = 0;
1804290001Sglebius	item->data = NULL;
1805290001Sglebius	if (data) {
1806290001Sglebius		if (item->is_name) {
1807290001Sglebius			if (!(item->data = mm_strdup(data))) {
1808290001Sglebius				mm_free(item->name);
1809290001Sglebius				mm_free(item);
1810290001Sglebius				goto done;
1811290001Sglebius			}
1812290001Sglebius			item->datalen = (u16)-1;
1813290001Sglebius		} else {
1814290001Sglebius			if (!(item->data = mm_malloc(datalen))) {
1815290001Sglebius				mm_free(item->name);
1816290001Sglebius				mm_free(item);
1817290001Sglebius				goto done;
1818290001Sglebius			}
1819290001Sglebius			item->datalen = datalen;
1820290001Sglebius			memcpy(item->data, data, datalen);
1821290001Sglebius		}
1822290001Sglebius	}
1823290001Sglebius
1824290001Sglebius	*itemp = item;
1825290001Sglebius	++(*countp);
1826290001Sglebius	result = 0;
1827290001Sglebiusdone:
1828290001Sglebius	EVDNS_UNLOCK(req->port);
1829290001Sglebius	return result;
1830290001Sglebius}
1831290001Sglebius
1832290001Sglebius/* exported function */
1833290001Sglebiusint
1834290001Sglebiusevdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
1835290001Sglebius{
1836290001Sglebius	return evdns_server_request_add_reply(
1837290001Sglebius		  req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
1838290001Sglebius		  ttl, n*4, 0, addrs);
1839290001Sglebius}
1840290001Sglebius
1841290001Sglebius/* exported function */
1842290001Sglebiusint
1843290001Sglebiusevdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
1844290001Sglebius{
1845290001Sglebius	return evdns_server_request_add_reply(
1846290001Sglebius		  req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
1847290001Sglebius		  ttl, n*16, 0, addrs);
1848290001Sglebius}
1849290001Sglebius
1850290001Sglebius/* exported function */
1851290001Sglebiusint
1852290001Sglebiusevdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
1853290001Sglebius{
1854290001Sglebius	u32 a;
1855290001Sglebius	char buf[32];
1856290001Sglebius	if (in && inaddr_name)
1857290001Sglebius		return -1;
1858290001Sglebius	else if (!in && !inaddr_name)
1859290001Sglebius		return -1;
1860290001Sglebius	if (in) {
1861290001Sglebius		a = ntohl(in->s_addr);
1862290001Sglebius		evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
1863290001Sglebius				(int)(u8)((a	)&0xff),
1864290001Sglebius				(int)(u8)((a>>8 )&0xff),
1865290001Sglebius				(int)(u8)((a>>16)&0xff),
1866290001Sglebius				(int)(u8)((a>>24)&0xff));
1867290001Sglebius		inaddr_name = buf;
1868290001Sglebius	}
1869290001Sglebius	return evdns_server_request_add_reply(
1870290001Sglebius		  req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
1871290001Sglebius		  ttl, -1, 1, hostname);
1872290001Sglebius}
1873290001Sglebius
1874290001Sglebius/* exported function */
1875290001Sglebiusint
1876290001Sglebiusevdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
1877290001Sglebius{
1878290001Sglebius	return evdns_server_request_add_reply(
1879290001Sglebius		  req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
1880290001Sglebius		  ttl, -1, 1, cname);
1881290001Sglebius}
1882290001Sglebius
1883290001Sglebius/* exported function */
1884290001Sglebiusvoid
1885290001Sglebiusevdns_server_request_set_flags(struct evdns_server_request *exreq, int flags)
1886290001Sglebius{
1887290001Sglebius	struct server_request *req = TO_SERVER_REQUEST(exreq);
1888290001Sglebius	req->base.flags &= ~(EVDNS_FLAGS_AA|EVDNS_FLAGS_RD);
1889290001Sglebius	req->base.flags |= flags;
1890290001Sglebius}
1891290001Sglebius
1892290001Sglebiusstatic int
1893290001Sglebiusevdns_server_request_format_response(struct server_request *req, int err)
1894290001Sglebius{
1895290001Sglebius	unsigned char buf[1500];
1896290001Sglebius	size_t buf_len = sizeof(buf);
1897290001Sglebius	off_t j = 0, r;
1898290001Sglebius	u16 t_;
1899290001Sglebius	u32 t32_;
1900290001Sglebius	int i;
1901290001Sglebius	u16 flags;
1902290001Sglebius	struct dnslabel_table table;
1903290001Sglebius
1904290001Sglebius	if (err < 0 || err > 15) return -1;
1905290001Sglebius
1906290001Sglebius	/* Set response bit and error code; copy OPCODE and RD fields from
1907290001Sglebius	 * question; copy RA and AA if set by caller. */
1908290001Sglebius	flags = req->base.flags;
1909290001Sglebius	flags |= (0x8000 | err);
1910290001Sglebius
1911290001Sglebius	dnslabel_table_init(&table);
1912290001Sglebius	APPEND16(req->trans_id);
1913290001Sglebius	APPEND16(flags);
1914290001Sglebius	APPEND16(req->base.nquestions);
1915290001Sglebius	APPEND16(req->n_answer);
1916290001Sglebius	APPEND16(req->n_authority);
1917290001Sglebius	APPEND16(req->n_additional);
1918290001Sglebius
1919290001Sglebius	/* Add questions. */
1920290001Sglebius	for (i=0; i < req->base.nquestions; ++i) {
1921290001Sglebius		const char *s = req->base.questions[i]->name;
1922290001Sglebius		j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
1923290001Sglebius		if (j < 0) {
1924290001Sglebius			dnslabel_clear(&table);
1925290001Sglebius			return (int) j;
1926290001Sglebius		}
1927290001Sglebius		APPEND16(req->base.questions[i]->type);
1928290001Sglebius		APPEND16(req->base.questions[i]->dns_question_class);
1929290001Sglebius	}
1930290001Sglebius
1931290001Sglebius	/* Add answer, authority, and additional sections. */
1932290001Sglebius	for (i=0; i<3; ++i) {
1933290001Sglebius		struct server_reply_item *item;
1934290001Sglebius		if (i==0)
1935290001Sglebius			item = req->answer;
1936290001Sglebius		else if (i==1)
1937290001Sglebius			item = req->authority;
1938290001Sglebius		else
1939290001Sglebius			item = req->additional;
1940290001Sglebius		while (item) {
1941290001Sglebius			r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
1942290001Sglebius			if (r < 0)
1943290001Sglebius				goto overflow;
1944290001Sglebius			j = r;
1945290001Sglebius
1946290001Sglebius			APPEND16(item->type);
1947290001Sglebius			APPEND16(item->dns_question_class);
1948290001Sglebius			APPEND32(item->ttl);
1949290001Sglebius			if (item->is_name) {
1950290001Sglebius				off_t len_idx = j, name_start;
1951290001Sglebius				j += 2;
1952290001Sglebius				name_start = j;
1953290001Sglebius				r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
1954290001Sglebius				if (r < 0)
1955290001Sglebius					goto overflow;
1956290001Sglebius				j = r;
1957290001Sglebius				t_ = htons( (short) (j-name_start) );
1958290001Sglebius				memcpy(buf+len_idx, &t_, 2);
1959290001Sglebius			} else {
1960290001Sglebius				APPEND16(item->datalen);
1961290001Sglebius				if (j+item->datalen > (off_t)buf_len)
1962290001Sglebius					goto overflow;
1963290001Sglebius				memcpy(buf+j, item->data, item->datalen);
1964290001Sglebius				j += item->datalen;
1965290001Sglebius			}
1966290001Sglebius			item = item->next;
1967290001Sglebius		}
1968290001Sglebius	}
1969290001Sglebius
1970290001Sglebius	if (j > 512) {
1971290001Sglebiusoverflow:
1972290001Sglebius		j = 512;
1973290001Sglebius		buf[2] |= 0x02; /* set the truncated bit. */
1974290001Sglebius	}
1975290001Sglebius
1976290001Sglebius	req->response_len = j;
1977290001Sglebius
1978290001Sglebius	if (!(req->response = mm_malloc(req->response_len))) {
1979290001Sglebius		server_request_free_answers(req);
1980290001Sglebius		dnslabel_clear(&table);
1981290001Sglebius		return (-1);
1982290001Sglebius	}
1983290001Sglebius	memcpy(req->response, buf, req->response_len);
1984290001Sglebius	server_request_free_answers(req);
1985290001Sglebius	dnslabel_clear(&table);
1986290001Sglebius	return (0);
1987290001Sglebius}
1988290001Sglebius
1989290001Sglebius/* exported function */
1990290001Sglebiusint
1991290001Sglebiusevdns_server_request_respond(struct evdns_server_request *req_, int err)
1992290001Sglebius{
1993290001Sglebius	struct server_request *req = TO_SERVER_REQUEST(req_);
1994290001Sglebius	struct evdns_server_port *port = req->port;
1995290001Sglebius	int r = -1;
1996290001Sglebius
1997290001Sglebius	EVDNS_LOCK(port);
1998290001Sglebius	if (!req->response) {
1999290001Sglebius		if ((r = evdns_server_request_format_response(req, err))<0)
2000290001Sglebius			goto done;
2001290001Sglebius	}
2002290001Sglebius
2003290001Sglebius	r = sendto(port->socket, req->response, (int)req->response_len, 0,
2004290001Sglebius			   (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
2005290001Sglebius	if (r<0) {
2006290001Sglebius		int sock_err = evutil_socket_geterror(port->socket);
2007290001Sglebius		if (EVUTIL_ERR_RW_RETRIABLE(sock_err))
2008290001Sglebius			goto done;
2009290001Sglebius
2010290001Sglebius		if (port->pending_replies) {
2011290001Sglebius			req->prev_pending = port->pending_replies->prev_pending;
2012290001Sglebius			req->next_pending = port->pending_replies;
2013290001Sglebius			req->prev_pending->next_pending =
2014290001Sglebius				req->next_pending->prev_pending = req;
2015290001Sglebius		} else {
2016290001Sglebius			req->prev_pending = req->next_pending = req;
2017290001Sglebius			port->pending_replies = req;
2018290001Sglebius			port->choked = 1;
2019290001Sglebius
2020290001Sglebius			(void) event_del(&port->event);
2021290001Sglebius			event_assign(&port->event, port->event_base, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
2022290001Sglebius
2023290001Sglebius			if (event_add(&port->event, NULL) < 0) {
2024290001Sglebius				log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
2025290001Sglebius			}
2026290001Sglebius
2027290001Sglebius		}
2028290001Sglebius
2029290001Sglebius		r = 1;
2030290001Sglebius		goto done;
2031290001Sglebius	}
2032290001Sglebius	if (server_request_free(req)) {
2033290001Sglebius		r = 0;
2034290001Sglebius		goto done;
2035290001Sglebius	}
2036290001Sglebius
2037290001Sglebius	if (port->pending_replies)
2038290001Sglebius		server_port_flush(port);
2039290001Sglebius
2040290001Sglebius	r = 0;
2041290001Sglebiusdone:
2042290001Sglebius	EVDNS_UNLOCK(port);
2043290001Sglebius	return r;
2044290001Sglebius}
2045290001Sglebius
2046290001Sglebius/* Free all storage held by RRs in req. */
2047290001Sglebiusstatic void
2048290001Sglebiusserver_request_free_answers(struct server_request *req)
2049290001Sglebius{
2050290001Sglebius	struct server_reply_item *victim, *next, **list;
2051290001Sglebius	int i;
2052290001Sglebius	for (i = 0; i < 3; ++i) {
2053290001Sglebius		if (i==0)
2054290001Sglebius			list = &req->answer;
2055290001Sglebius		else if (i==1)
2056290001Sglebius			list = &req->authority;
2057290001Sglebius		else
2058290001Sglebius			list = &req->additional;
2059290001Sglebius
2060290001Sglebius		victim = *list;
2061290001Sglebius		while (victim) {
2062290001Sglebius			next = victim->next;
2063290001Sglebius			mm_free(victim->name);
2064290001Sglebius			if (victim->data)
2065290001Sglebius				mm_free(victim->data);
2066290001Sglebius			mm_free(victim);
2067290001Sglebius			victim = next;
2068290001Sglebius		}
2069290001Sglebius		*list = NULL;
2070290001Sglebius	}
2071290001Sglebius}
2072290001Sglebius
2073290001Sglebius/* Free all storage held by req, and remove links to it. */
2074290001Sglebius/* return true iff we just wound up freeing the server_port. */
2075290001Sglebiusstatic int
2076290001Sglebiusserver_request_free(struct server_request *req)
2077290001Sglebius{
2078290001Sglebius	int i, rc=1, lock=0;
2079290001Sglebius	if (req->base.questions) {
2080290001Sglebius		for (i = 0; i < req->base.nquestions; ++i)
2081290001Sglebius			mm_free(req->base.questions[i]);
2082290001Sglebius		mm_free(req->base.questions);
2083290001Sglebius	}
2084290001Sglebius
2085290001Sglebius	if (req->port) {
2086290001Sglebius		EVDNS_LOCK(req->port);
2087290001Sglebius		lock=1;
2088290001Sglebius		if (req->port->pending_replies == req) {
2089290001Sglebius			if (req->next_pending && req->next_pending != req)
2090290001Sglebius				req->port->pending_replies = req->next_pending;
2091290001Sglebius			else
2092290001Sglebius				req->port->pending_replies = NULL;
2093290001Sglebius		}
2094290001Sglebius		rc = --req->port->refcnt;
2095290001Sglebius	}
2096290001Sglebius
2097290001Sglebius	if (req->response) {
2098290001Sglebius		mm_free(req->response);
2099290001Sglebius	}
2100290001Sglebius
2101290001Sglebius	server_request_free_answers(req);
2102290001Sglebius
2103290001Sglebius	if (req->next_pending && req->next_pending != req) {
2104290001Sglebius		req->next_pending->prev_pending = req->prev_pending;
2105290001Sglebius		req->prev_pending->next_pending = req->next_pending;
2106290001Sglebius	}
2107290001Sglebius
2108290001Sglebius	if (rc == 0) {
2109290001Sglebius		EVDNS_UNLOCK(req->port); /* ????? nickm */
2110290001Sglebius		server_port_free(req->port);
2111290001Sglebius		mm_free(req);
2112290001Sglebius		return (1);
2113290001Sglebius	}
2114290001Sglebius	if (lock)
2115290001Sglebius		EVDNS_UNLOCK(req->port);
2116290001Sglebius	mm_free(req);
2117290001Sglebius	return (0);
2118290001Sglebius}
2119290001Sglebius
2120290001Sglebius/* Free all storage held by an evdns_server_port.  Only called when  */
2121290001Sglebiusstatic void
2122290001Sglebiusserver_port_free(struct evdns_server_port *port)
2123290001Sglebius{
2124290001Sglebius	EVUTIL_ASSERT(port);
2125290001Sglebius	EVUTIL_ASSERT(!port->refcnt);
2126290001Sglebius	EVUTIL_ASSERT(!port->pending_replies);
2127290001Sglebius	if (port->socket > 0) {
2128290001Sglebius		evutil_closesocket(port->socket);
2129290001Sglebius		port->socket = -1;
2130290001Sglebius	}
2131290001Sglebius	(void) event_del(&port->event);
2132290001Sglebius	event_debug_unassign(&port->event);
2133290001Sglebius	EVTHREAD_FREE_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
2134290001Sglebius	mm_free(port);
2135290001Sglebius}
2136290001Sglebius
2137290001Sglebius/* exported function */
2138290001Sglebiusint
2139290001Sglebiusevdns_server_request_drop(struct evdns_server_request *req_)
2140290001Sglebius{
2141290001Sglebius	struct server_request *req = TO_SERVER_REQUEST(req_);
2142290001Sglebius	server_request_free(req);
2143290001Sglebius	return 0;
2144290001Sglebius}
2145290001Sglebius
2146290001Sglebius/* exported function */
2147290001Sglebiusint
2148290001Sglebiusevdns_server_request_get_requesting_addr(struct evdns_server_request *req_, struct sockaddr *sa, int addr_len)
2149290001Sglebius{
2150290001Sglebius	struct server_request *req = TO_SERVER_REQUEST(req_);
2151290001Sglebius	if (addr_len < (int)req->addrlen)
2152290001Sglebius		return -1;
2153290001Sglebius	memcpy(sa, &(req->addr), req->addrlen);
2154290001Sglebius	return req->addrlen;
2155290001Sglebius}
2156290001Sglebius
2157290001Sglebius#undef APPEND16
2158290001Sglebius#undef APPEND32
2159290001Sglebius
2160290001Sglebius/* this is a libevent callback function which is called when a request */
2161290001Sglebius/* has timed out. */
2162290001Sglebiusstatic void
2163290001Sglebiusevdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
2164290001Sglebius	struct request *const req = (struct request *) arg;
2165290001Sglebius	struct evdns_base *base = req->base;
2166290001Sglebius
2167290001Sglebius	(void) fd;
2168290001Sglebius	(void) events;
2169290001Sglebius
2170290001Sglebius	log(EVDNS_LOG_DEBUG, "Request %p timed out", arg);
2171290001Sglebius	EVDNS_LOCK(base);
2172290001Sglebius
2173290001Sglebius	if (req->tx_count >= req->base->global_max_retransmits) {
2174290001Sglebius		struct nameserver *ns = req->ns;
2175290001Sglebius		/* this request has failed */
2176290001Sglebius		log(EVDNS_LOG_DEBUG, "Giving up on request %p; tx_count==%d",
2177290001Sglebius		    arg, req->tx_count);
2178290001Sglebius		reply_schedule_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
2179290001Sglebius
2180290001Sglebius		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
2181290001Sglebius		nameserver_failed(ns, "request timed out.");
2182290001Sglebius	} else {
2183290001Sglebius		/* retransmit it */
2184290001Sglebius		log(EVDNS_LOG_DEBUG, "Retransmitting request %p; tx_count==%d",
2185290001Sglebius		    arg, req->tx_count);
2186290001Sglebius		(void) evtimer_del(&req->timeout_event);
2187290001Sglebius		request_swap_ns(req, nameserver_pick(base));
2188290001Sglebius		evdns_request_transmit(req);
2189290001Sglebius
2190290001Sglebius		req->ns->timedout++;
2191290001Sglebius		if (req->ns->timedout > req->base->global_max_nameserver_timeout) {
2192290001Sglebius			req->ns->timedout = 0;
2193290001Sglebius			nameserver_failed(req->ns, "request timed out.");
2194290001Sglebius		}
2195290001Sglebius	}
2196290001Sglebius
2197290001Sglebius	EVDNS_UNLOCK(base);
2198290001Sglebius}
2199290001Sglebius
2200290001Sglebius/* try to send a request to a given server. */
2201290001Sglebius/* */
2202290001Sglebius/* return: */
2203290001Sglebius/*   0 ok */
2204290001Sglebius/*   1 temporary failure */
2205290001Sglebius/*   2 other failure */
2206290001Sglebiusstatic int
2207290001Sglebiusevdns_request_transmit_to(struct request *req, struct nameserver *server) {
2208290001Sglebius	int r;
2209290001Sglebius	ASSERT_LOCKED(req->base);
2210290001Sglebius	ASSERT_VALID_REQUEST(req);
2211290001Sglebius
2212290001Sglebius	if (server->requests_inflight == 1 &&
2213290001Sglebius		req->base->disable_when_inactive &&
2214290001Sglebius		event_add(&server->event, NULL) < 0) {
2215290001Sglebius		return 1;
2216290001Sglebius	}
2217290001Sglebius
2218290001Sglebius	r = sendto(server->socket, (void*)req->request, req->request_len, 0,
2219290001Sglebius	    (struct sockaddr *)&server->address, server->addrlen);
2220290001Sglebius	if (r < 0) {
2221290001Sglebius		int err = evutil_socket_geterror(server->socket);
2222290001Sglebius		if (EVUTIL_ERR_RW_RETRIABLE(err))
2223290001Sglebius			return 1;
2224290001Sglebius		nameserver_failed(req->ns, evutil_socket_error_to_string(err));
2225290001Sglebius		return 2;
2226290001Sglebius	} else if (r != (int)req->request_len) {
2227290001Sglebius		return 1;  /* short write */
2228290001Sglebius	} else {
2229290001Sglebius		return 0;
2230290001Sglebius	}
2231290001Sglebius}
2232290001Sglebius
2233290001Sglebius/* try to send a request, updating the fields of the request */
2234290001Sglebius/* as needed */
2235290001Sglebius/* */
2236290001Sglebius/* return: */
2237290001Sglebius/*   0 ok */
2238290001Sglebius/*   1 failed */
2239290001Sglebiusstatic int
2240290001Sglebiusevdns_request_transmit(struct request *req) {
2241290001Sglebius	int retcode = 0, r;
2242290001Sglebius
2243290001Sglebius	ASSERT_LOCKED(req->base);
2244290001Sglebius	ASSERT_VALID_REQUEST(req);
2245290001Sglebius	/* if we fail to send this packet then this flag marks it */
2246290001Sglebius	/* for evdns_transmit */
2247290001Sglebius	req->transmit_me = 1;
2248290001Sglebius	EVUTIL_ASSERT(req->trans_id != 0xffff);
2249290001Sglebius
2250290001Sglebius	if (!req->ns)
2251290001Sglebius	{
2252290001Sglebius		/* unable to transmit request if no nameservers */
2253290001Sglebius		return 1;
2254290001Sglebius	}
2255290001Sglebius
2256290001Sglebius	if (req->ns->choked) {
2257290001Sglebius		/* don't bother trying to write to a socket */
2258290001Sglebius		/* which we have had EAGAIN from */
2259290001Sglebius		return 1;
2260290001Sglebius	}
2261290001Sglebius
2262290001Sglebius	r = evdns_request_transmit_to(req, req->ns);
2263290001Sglebius	switch (r) {
2264290001Sglebius	case 1:
2265290001Sglebius		/* temp failure */
2266290001Sglebius		req->ns->choked = 1;
2267290001Sglebius		nameserver_write_waiting(req->ns, 1);
2268290001Sglebius		return 1;
2269290001Sglebius	case 2:
2270290001Sglebius		/* failed to transmit the request entirely. */
2271290001Sglebius		retcode = 1;
2272290001Sglebius		/* fall through: we'll set a timeout, which will time out,
2273290001Sglebius		 * and make us retransmit the request anyway. */
2274290001Sglebius	default:
2275290001Sglebius		/* all ok */
2276290001Sglebius		log(EVDNS_LOG_DEBUG,
2277290001Sglebius		    "Setting timeout for request %p, sent to nameserver %p", req, req->ns);
2278290001Sglebius		if (evtimer_add(&req->timeout_event, &req->base->global_timeout) < 0) {
2279290001Sglebius			log(EVDNS_LOG_WARN,
2280290001Sglebius		      "Error from libevent when adding timer for request %p",
2281290001Sglebius			    req);
2282290001Sglebius			/* ???? Do more? */
2283290001Sglebius		}
2284290001Sglebius		req->tx_count++;
2285290001Sglebius		req->transmit_me = 0;
2286290001Sglebius		return retcode;
2287290001Sglebius	}
2288290001Sglebius}
2289290001Sglebius
2290290001Sglebiusstatic void
2291290001Sglebiusnameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
2292290001Sglebius	struct nameserver *const ns = (struct nameserver *) arg;
2293290001Sglebius	(void) type;
2294290001Sglebius	(void) count;
2295290001Sglebius	(void) ttl;
2296290001Sglebius	(void) addresses;
2297290001Sglebius
2298290001Sglebius	if (result == DNS_ERR_CANCEL) {
2299290001Sglebius		/* We canceled this request because the nameserver came up
2300290001Sglebius		 * for some other reason.  Do not change our opinion about
2301290001Sglebius		 * the nameserver. */
2302290001Sglebius		return;
2303290001Sglebius	}
2304290001Sglebius
2305290001Sglebius	EVDNS_LOCK(ns->base);
2306290001Sglebius	ns->probe_request = NULL;
2307290001Sglebius	if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
2308290001Sglebius		/* this is a good reply */
2309290001Sglebius		nameserver_up(ns);
2310290001Sglebius	} else {
2311290001Sglebius		nameserver_probe_failed(ns);
2312290001Sglebius	}
2313290001Sglebius	EVDNS_UNLOCK(ns->base);
2314290001Sglebius}
2315290001Sglebius
2316290001Sglebiusstatic void
2317290001Sglebiusnameserver_send_probe(struct nameserver *const ns) {
2318290001Sglebius	struct evdns_request *handle;
2319290001Sglebius	struct request *req;
2320290001Sglebius	char addrbuf[128];
2321290001Sglebius	/* here we need to send a probe to a given nameserver */
2322290001Sglebius	/* in the hope that it is up now. */
2323290001Sglebius
2324290001Sglebius	ASSERT_LOCKED(ns->base);
2325290001Sglebius	log(EVDNS_LOG_DEBUG, "Sending probe to %s",
2326290001Sglebius	    evutil_format_sockaddr_port_(
2327290001Sglebius		    (struct sockaddr *)&ns->address,
2328290001Sglebius		    addrbuf, sizeof(addrbuf)));
2329290001Sglebius	handle = mm_calloc(1, sizeof(*handle));
2330290001Sglebius	if (!handle) return;
2331290001Sglebius	req = request_new(ns->base, handle, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
2332290001Sglebius	if (!req) {
2333290001Sglebius		mm_free(handle);
2334290001Sglebius		return;
2335290001Sglebius	}
2336290001Sglebius	ns->probe_request = handle;
2337290001Sglebius	/* we force this into the inflight queue no matter what */
2338290001Sglebius	request_trans_id_set(req, transaction_id_pick(ns->base));
2339290001Sglebius	req->ns = ns;
2340290001Sglebius	request_submit(req);
2341290001Sglebius}
2342290001Sglebius
2343290001Sglebius/* returns: */
2344290001Sglebius/*   0 didn't try to transmit anything */
2345290001Sglebius/*   1 tried to transmit something */
2346290001Sglebiusstatic int
2347290001Sglebiusevdns_transmit(struct evdns_base *base) {
2348290001Sglebius	char did_try_to_transmit = 0;
2349290001Sglebius	int i;
2350290001Sglebius
2351290001Sglebius	ASSERT_LOCKED(base);
2352290001Sglebius	for (i = 0; i < base->n_req_heads; ++i) {
2353290001Sglebius		if (base->req_heads[i]) {
2354290001Sglebius			struct request *const started_at = base->req_heads[i], *req = started_at;
2355290001Sglebius			/* first transmit all the requests which are currently waiting */
2356290001Sglebius			do {
2357290001Sglebius				if (req->transmit_me) {
2358290001Sglebius					did_try_to_transmit = 1;
2359290001Sglebius					evdns_request_transmit(req);
2360290001Sglebius				}
2361290001Sglebius
2362290001Sglebius				req = req->next;
2363290001Sglebius			} while (req != started_at);
2364290001Sglebius		}
2365290001Sglebius	}
2366290001Sglebius
2367290001Sglebius	return did_try_to_transmit;
2368290001Sglebius}
2369290001Sglebius
2370290001Sglebius/* exported function */
2371290001Sglebiusint
2372290001Sglebiusevdns_base_count_nameservers(struct evdns_base *base)
2373290001Sglebius{
2374290001Sglebius	const struct nameserver *server;
2375290001Sglebius	int n = 0;
2376290001Sglebius
2377290001Sglebius	EVDNS_LOCK(base);
2378290001Sglebius	server = base->server_head;
2379290001Sglebius	if (!server)
2380290001Sglebius		goto done;
2381290001Sglebius	do {
2382290001Sglebius		++n;
2383290001Sglebius		server = server->next;
2384290001Sglebius	} while (server != base->server_head);
2385290001Sglebiusdone:
2386290001Sglebius	EVDNS_UNLOCK(base);
2387290001Sglebius	return n;
2388290001Sglebius}
2389290001Sglebius
2390290001Sglebiusint
2391290001Sglebiusevdns_count_nameservers(void)
2392290001Sglebius{
2393290001Sglebius	return evdns_base_count_nameservers(current_base);
2394290001Sglebius}
2395290001Sglebius
2396290001Sglebius/* exported function */
2397290001Sglebiusint
2398290001Sglebiusevdns_base_clear_nameservers_and_suspend(struct evdns_base *base)
2399290001Sglebius{
2400290001Sglebius	struct nameserver *server, *started_at;
2401290001Sglebius	int i;
2402290001Sglebius
2403290001Sglebius	EVDNS_LOCK(base);
2404290001Sglebius	server = base->server_head;
2405290001Sglebius	started_at = base->server_head;
2406290001Sglebius	if (!server) {
2407290001Sglebius		EVDNS_UNLOCK(base);
2408290001Sglebius		return 0;
2409290001Sglebius	}
2410290001Sglebius	while (1) {
2411290001Sglebius		struct nameserver *next = server->next;
2412290001Sglebius		(void) event_del(&server->event);
2413290001Sglebius		if (evtimer_initialized(&server->timeout_event))
2414290001Sglebius			(void) evtimer_del(&server->timeout_event);
2415290001Sglebius		if (server->probe_request) {
2416290001Sglebius			evdns_cancel_request(server->base, server->probe_request);
2417290001Sglebius			server->probe_request = NULL;
2418290001Sglebius		}
2419290001Sglebius		if (server->socket >= 0)
2420290001Sglebius			evutil_closesocket(server->socket);
2421290001Sglebius		mm_free(server);
2422290001Sglebius		if (next == started_at)
2423290001Sglebius			break;
2424290001Sglebius		server = next;
2425290001Sglebius	}
2426290001Sglebius	base->server_head = NULL;
2427290001Sglebius	base->global_good_nameservers = 0;
2428290001Sglebius
2429290001Sglebius	for (i = 0; i < base->n_req_heads; ++i) {
2430290001Sglebius		struct request *req, *req_started_at;
2431290001Sglebius		req = req_started_at = base->req_heads[i];
2432290001Sglebius		while (req) {
2433290001Sglebius			struct request *next = req->next;
2434290001Sglebius			req->tx_count = req->reissue_count = 0;
2435290001Sglebius			req->ns = NULL;
2436290001Sglebius			/* ???? What to do about searches? */
2437290001Sglebius			(void) evtimer_del(&req->timeout_event);
2438290001Sglebius			req->trans_id = 0;
2439290001Sglebius			req->transmit_me = 0;
2440290001Sglebius
2441290001Sglebius			base->global_requests_waiting++;
2442290001Sglebius			evdns_request_insert(req, &base->req_waiting_head);
2443290001Sglebius			/* We want to insert these suspended elements at the front of
2444290001Sglebius			 * the waiting queue, since they were pending before any of
2445290001Sglebius			 * the waiting entries were added.  This is a circular list,
2446290001Sglebius			 * so we can just shift the start back by one.*/
2447290001Sglebius			base->req_waiting_head = base->req_waiting_head->prev;
2448290001Sglebius
2449290001Sglebius			if (next == req_started_at)
2450290001Sglebius				break;
2451290001Sglebius			req = next;
2452290001Sglebius		}
2453290001Sglebius		base->req_heads[i] = NULL;
2454290001Sglebius	}
2455290001Sglebius
2456290001Sglebius	base->global_requests_inflight = 0;
2457290001Sglebius
2458290001Sglebius	EVDNS_UNLOCK(base);
2459290001Sglebius	return 0;
2460290001Sglebius}
2461290001Sglebius
2462290001Sglebiusint
2463290001Sglebiusevdns_clear_nameservers_and_suspend(void)
2464290001Sglebius{
2465290001Sglebius	return evdns_base_clear_nameservers_and_suspend(current_base);
2466290001Sglebius}
2467290001Sglebius
2468290001Sglebius
2469290001Sglebius/* exported function */
2470290001Sglebiusint
2471290001Sglebiusevdns_base_resume(struct evdns_base *base)
2472290001Sglebius{
2473290001Sglebius	EVDNS_LOCK(base);
2474290001Sglebius	evdns_requests_pump_waiting_queue(base);
2475290001Sglebius	EVDNS_UNLOCK(base);
2476290001Sglebius
2477290001Sglebius	return 0;
2478290001Sglebius}
2479290001Sglebius
2480290001Sglebiusint
2481290001Sglebiusevdns_resume(void)
2482290001Sglebius{
2483290001Sglebius	return evdns_base_resume(current_base);
2484290001Sglebius}
2485290001Sglebius
2486290001Sglebiusstatic int
2487290001Sglebiusevdns_nameserver_add_impl_(struct evdns_base *base, const struct sockaddr *address, int addrlen) {
2488290001Sglebius	/* first check to see if we already have this nameserver */
2489290001Sglebius
2490290001Sglebius	const struct nameserver *server = base->server_head, *const started_at = base->server_head;
2491290001Sglebius	struct nameserver *ns;
2492290001Sglebius	int err = 0;
2493290001Sglebius	char addrbuf[128];
2494290001Sglebius
2495290001Sglebius	ASSERT_LOCKED(base);
2496290001Sglebius	if (server) {
2497290001Sglebius		do {
2498290001Sglebius			if (!evutil_sockaddr_cmp((struct sockaddr*)&server->address, address, 1)) return 3;
2499290001Sglebius			server = server->next;
2500290001Sglebius		} while (server != started_at);
2501290001Sglebius	}
2502290001Sglebius	if (addrlen > (int)sizeof(ns->address)) {
2503290001Sglebius		log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
2504290001Sglebius		return 2;
2505290001Sglebius	}
2506290001Sglebius
2507290001Sglebius	ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver));
2508290001Sglebius	if (!ns) return -1;
2509290001Sglebius
2510290001Sglebius	memset(ns, 0, sizeof(struct nameserver));
2511290001Sglebius	ns->base = base;
2512290001Sglebius
2513290001Sglebius	evtimer_assign(&ns->timeout_event, ns->base->event_base, nameserver_prod_callback, ns);
2514290001Sglebius
2515290001Sglebius	ns->socket = evutil_socket_(address->sa_family,
2516290001Sglebius	    SOCK_DGRAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
2517290001Sglebius	if (ns->socket < 0) { err = 1; goto out1; }
2518290001Sglebius
2519290001Sglebius	if (base->global_outgoing_addrlen &&
2520290001Sglebius	    !evutil_sockaddr_is_loopback_(address)) {
2521290001Sglebius		if (bind(ns->socket,
2522290001Sglebius			(struct sockaddr*)&base->global_outgoing_address,
2523290001Sglebius			base->global_outgoing_addrlen) < 0) {
2524290001Sglebius			log(EVDNS_LOG_WARN,"Couldn't bind to outgoing address");
2525290001Sglebius			err = 2;
2526290001Sglebius			goto out2;
2527290001Sglebius		}
2528290001Sglebius	}
2529290001Sglebius
2530290001Sglebius	memcpy(&ns->address, address, addrlen);
2531290001Sglebius	ns->addrlen = addrlen;
2532290001Sglebius	ns->state = 1;
2533290001Sglebius	event_assign(&ns->event, ns->base->event_base, ns->socket,
2534290001Sglebius				 EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
2535290001Sglebius	if (!base->disable_when_inactive && event_add(&ns->event, NULL) < 0) {
2536290001Sglebius		err = 2;
2537290001Sglebius		goto out2;
2538290001Sglebius	}
2539290001Sglebius
2540290001Sglebius	log(EVDNS_LOG_DEBUG, "Added nameserver %s as %p",
2541290001Sglebius	    evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), ns);
2542290001Sglebius
2543290001Sglebius	/* insert this nameserver into the list of them */
2544290001Sglebius	if (!base->server_head) {
2545290001Sglebius		ns->next = ns->prev = ns;
2546290001Sglebius		base->server_head = ns;
2547290001Sglebius	} else {
2548290001Sglebius		ns->next = base->server_head->next;
2549290001Sglebius		ns->prev = base->server_head;
2550290001Sglebius		base->server_head->next = ns;
2551290001Sglebius		ns->next->prev = ns;
2552290001Sglebius	}
2553290001Sglebius
2554290001Sglebius	base->global_good_nameservers++;
2555290001Sglebius
2556290001Sglebius	return 0;
2557290001Sglebius
2558290001Sglebiusout2:
2559290001Sglebius	evutil_closesocket(ns->socket);
2560290001Sglebiusout1:
2561290001Sglebius	event_debug_unassign(&ns->event);
2562290001Sglebius	mm_free(ns);
2563290001Sglebius	log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d",
2564290001Sglebius	    evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), err);
2565290001Sglebius	return err;
2566290001Sglebius}
2567290001Sglebius
2568290001Sglebius/* exported function */
2569290001Sglebiusint
2570290001Sglebiusevdns_base_nameserver_add(struct evdns_base *base, unsigned long int address)
2571290001Sglebius{
2572290001Sglebius	struct sockaddr_in sin;
2573290001Sglebius	int res;
2574290001Sglebius	memset(&sin, 0, sizeof(sin));
2575290001Sglebius	sin.sin_addr.s_addr = address;
2576290001Sglebius	sin.sin_port = htons(53);
2577290001Sglebius	sin.sin_family = AF_INET;
2578290001Sglebius	EVDNS_LOCK(base);
2579290001Sglebius	res = evdns_nameserver_add_impl_(base, (struct sockaddr*)&sin, sizeof(sin));
2580290001Sglebius	EVDNS_UNLOCK(base);
2581290001Sglebius	return res;
2582290001Sglebius}
2583290001Sglebius
2584290001Sglebiusint
2585290001Sglebiusevdns_nameserver_add(unsigned long int address) {
2586290001Sglebius	if (!current_base)
2587290001Sglebius		current_base = evdns_base_new(NULL, 0);
2588290001Sglebius	return evdns_base_nameserver_add(current_base, address);
2589290001Sglebius}
2590290001Sglebius
2591290001Sglebiusstatic void
2592290001Sglebiussockaddr_setport(struct sockaddr *sa, ev_uint16_t port)
2593290001Sglebius{
2594290001Sglebius	if (sa->sa_family == AF_INET) {
2595290001Sglebius		((struct sockaddr_in *)sa)->sin_port = htons(port);
2596290001Sglebius	} else if (sa->sa_family == AF_INET6) {
2597290001Sglebius		((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
2598290001Sglebius	}
2599290001Sglebius}
2600290001Sglebius
2601290001Sglebiusstatic ev_uint16_t
2602290001Sglebiussockaddr_getport(struct sockaddr *sa)
2603290001Sglebius{
2604290001Sglebius	if (sa->sa_family == AF_INET) {
2605290001Sglebius		return ntohs(((struct sockaddr_in *)sa)->sin_port);
2606290001Sglebius	} else if (sa->sa_family == AF_INET6) {
2607290001Sglebius		return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
2608290001Sglebius	} else {
2609290001Sglebius		return 0;
2610290001Sglebius	}
2611290001Sglebius}
2612290001Sglebius
2613290001Sglebius/* exported function */
2614290001Sglebiusint
2615290001Sglebiusevdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) {
2616290001Sglebius	struct sockaddr_storage ss;
2617290001Sglebius	struct sockaddr *sa;
2618290001Sglebius	int len = sizeof(ss);
2619290001Sglebius	int res;
2620290001Sglebius	if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss,
2621290001Sglebius		&len)) {
2622290001Sglebius		log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s",
2623290001Sglebius			ip_as_string);
2624290001Sglebius		return 4;
2625290001Sglebius	}
2626290001Sglebius	sa = (struct sockaddr *) &ss;
2627290001Sglebius	if (sockaddr_getport(sa) == 0)
2628290001Sglebius		sockaddr_setport(sa, 53);
2629290001Sglebius
2630290001Sglebius	EVDNS_LOCK(base);
2631290001Sglebius	res = evdns_nameserver_add_impl_(base, sa, len);
2632290001Sglebius	EVDNS_UNLOCK(base);
2633290001Sglebius	return res;
2634290001Sglebius}
2635290001Sglebius
2636290001Sglebiusint
2637290001Sglebiusevdns_nameserver_ip_add(const char *ip_as_string) {
2638290001Sglebius	if (!current_base)
2639290001Sglebius		current_base = evdns_base_new(NULL, 0);
2640290001Sglebius	return evdns_base_nameserver_ip_add(current_base, ip_as_string);
2641290001Sglebius}
2642290001Sglebius
2643290001Sglebiusint
2644290001Sglebiusevdns_base_nameserver_sockaddr_add(struct evdns_base *base,
2645290001Sglebius    const struct sockaddr *sa, ev_socklen_t len, unsigned flags)
2646290001Sglebius{
2647290001Sglebius	int res;
2648290001Sglebius	EVUTIL_ASSERT(base);
2649290001Sglebius	EVDNS_LOCK(base);
2650290001Sglebius	res = evdns_nameserver_add_impl_(base, sa, len);
2651290001Sglebius	EVDNS_UNLOCK(base);
2652290001Sglebius	return res;
2653290001Sglebius}
2654290001Sglebius
2655290001Sglebiusint
2656290001Sglebiusevdns_base_get_nameserver_addr(struct evdns_base *base, int idx,
2657290001Sglebius    struct sockaddr *sa, ev_socklen_t len)
2658290001Sglebius{
2659290001Sglebius	int result = -1;
2660290001Sglebius	int i;
2661290001Sglebius	struct nameserver *server;
2662290001Sglebius	EVDNS_LOCK(base);
2663290001Sglebius	server = base->server_head;
2664290001Sglebius	for (i = 0; i < idx && server; ++i, server = server->next) {
2665290001Sglebius		if (server->next == base->server_head)
2666290001Sglebius			goto done;
2667290001Sglebius	}
2668290001Sglebius	if (! server)
2669290001Sglebius		goto done;
2670290001Sglebius
2671290001Sglebius	if (server->addrlen > len) {
2672290001Sglebius		result = (int) server->addrlen;
2673290001Sglebius		goto done;
2674290001Sglebius	}
2675290001Sglebius
2676290001Sglebius	memcpy(sa, &server->address, server->addrlen);
2677290001Sglebius	result = (int) server->addrlen;
2678290001Sglebiusdone:
2679290001Sglebius	EVDNS_UNLOCK(base);
2680290001Sglebius	return result;
2681290001Sglebius}
2682290001Sglebius
2683290001Sglebius/* remove from the queue */
2684290001Sglebiusstatic void
2685290001Sglebiusevdns_request_remove(struct request *req, struct request **head)
2686290001Sglebius{
2687290001Sglebius	ASSERT_LOCKED(req->base);
2688290001Sglebius	ASSERT_VALID_REQUEST(req);
2689290001Sglebius
2690290001Sglebius#if 0
2691290001Sglebius	{
2692290001Sglebius		struct request *ptr;
2693290001Sglebius		int found = 0;
2694290001Sglebius		EVUTIL_ASSERT(*head != NULL);
2695290001Sglebius
2696290001Sglebius		ptr = *head;
2697290001Sglebius		do {
2698290001Sglebius			if (ptr == req) {
2699290001Sglebius				found = 1;
2700290001Sglebius				break;
2701290001Sglebius			}
2702290001Sglebius			ptr = ptr->next;
2703290001Sglebius		} while (ptr != *head);
2704290001Sglebius		EVUTIL_ASSERT(found);
2705290001Sglebius
2706290001Sglebius		EVUTIL_ASSERT(req->next);
2707290001Sglebius	}
2708290001Sglebius#endif
2709290001Sglebius
2710290001Sglebius	if (req->next == req) {
2711290001Sglebius		/* only item in the list */
2712290001Sglebius		*head = NULL;
2713290001Sglebius	} else {
2714290001Sglebius		req->next->prev = req->prev;
2715290001Sglebius		req->prev->next = req->next;
2716290001Sglebius		if (*head == req) *head = req->next;
2717290001Sglebius	}
2718290001Sglebius	req->next = req->prev = NULL;
2719290001Sglebius}
2720290001Sglebius
2721290001Sglebius/* insert into the tail of the queue */
2722290001Sglebiusstatic void
2723290001Sglebiusevdns_request_insert(struct request *req, struct request **head) {
2724290001Sglebius	ASSERT_LOCKED(req->base);
2725290001Sglebius	ASSERT_VALID_REQUEST(req);
2726290001Sglebius	if (!*head) {
2727290001Sglebius		*head = req;
2728290001Sglebius		req->next = req->prev = req;
2729290001Sglebius		return;
2730290001Sglebius	}
2731290001Sglebius
2732290001Sglebius	req->prev = (*head)->prev;
2733290001Sglebius	req->prev->next = req;
2734290001Sglebius	req->next = *head;
2735290001Sglebius	(*head)->prev = req;
2736290001Sglebius}
2737290001Sglebius
2738290001Sglebiusstatic int
2739290001Sglebiusstring_num_dots(const char *s) {
2740290001Sglebius	int count = 0;
2741290001Sglebius	while ((s = strchr(s, '.'))) {
2742290001Sglebius		s++;
2743290001Sglebius		count++;
2744290001Sglebius	}
2745290001Sglebius	return count;
2746290001Sglebius}
2747290001Sglebius
2748290001Sglebiusstatic struct request *
2749290001Sglebiusrequest_new(struct evdns_base *base, struct evdns_request *handle, int type,
2750290001Sglebius	    const char *name, int flags, evdns_callback_type callback,
2751290001Sglebius	    void *user_ptr) {
2752290001Sglebius
2753290001Sglebius	const char issuing_now =
2754290001Sglebius	    (base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0;
2755290001Sglebius
2756290001Sglebius	const size_t name_len = strlen(name);
2757290001Sglebius	const size_t request_max_len = evdns_request_len(name_len);
2758290001Sglebius	const u16 trans_id = issuing_now ? transaction_id_pick(base) : 0xffff;
2759290001Sglebius	/* the request data is alloced in a single block with the header */
2760290001Sglebius	struct request *const req =
2761290001Sglebius	    mm_malloc(sizeof(struct request) + request_max_len);
2762290001Sglebius	int rlen;
2763290001Sglebius	char namebuf[256];
2764290001Sglebius	(void) flags;
2765290001Sglebius
2766290001Sglebius	ASSERT_LOCKED(base);
2767290001Sglebius
2768290001Sglebius	if (!req) return NULL;
2769290001Sglebius
2770290001Sglebius	if (name_len >= sizeof(namebuf)) {
2771290001Sglebius		mm_free(req);
2772290001Sglebius		return NULL;
2773290001Sglebius	}
2774290001Sglebius
2775290001Sglebius	memset(req, 0, sizeof(struct request));
2776290001Sglebius	req->base = base;
2777290001Sglebius
2778290001Sglebius	evtimer_assign(&req->timeout_event, req->base->event_base, evdns_request_timeout_callback, req);
2779290001Sglebius
2780290001Sglebius	if (base->global_randomize_case) {
2781290001Sglebius		unsigned i;
2782290001Sglebius		char randbits[(sizeof(namebuf)+7)/8];
2783290001Sglebius		strlcpy(namebuf, name, sizeof(namebuf));
2784290001Sglebius		evutil_secure_rng_get_bytes(randbits, (name_len+7)/8);
2785290001Sglebius		for (i = 0; i < name_len; ++i) {
2786290001Sglebius			if (EVUTIL_ISALPHA_(namebuf[i])) {
2787290001Sglebius				if ((randbits[i >> 3] & (1<<(i & 7))))
2788290001Sglebius					namebuf[i] |= 0x20;
2789290001Sglebius				else
2790290001Sglebius					namebuf[i] &= ~0x20;
2791290001Sglebius			}
2792290001Sglebius		}
2793290001Sglebius		name = namebuf;
2794290001Sglebius	}
2795290001Sglebius
2796290001Sglebius	/* request data lives just after the header */
2797290001Sglebius	req->request = ((u8 *) req) + sizeof(struct request);
2798290001Sglebius	/* denotes that the request data shouldn't be free()ed */
2799290001Sglebius	req->request_appended = 1;
2800290001Sglebius	rlen = evdns_request_data_build(name, name_len, trans_id,
2801290001Sglebius	    type, CLASS_INET, req->request, request_max_len);
2802290001Sglebius	if (rlen < 0)
2803290001Sglebius		goto err1;
2804290001Sglebius
2805290001Sglebius	req->request_len = rlen;
2806290001Sglebius	req->trans_id = trans_id;
2807290001Sglebius	req->tx_count = 0;
2808290001Sglebius	req->request_type = type;
2809290001Sglebius	req->user_pointer = user_ptr;
2810290001Sglebius	req->user_callback = callback;
2811290001Sglebius	req->ns = issuing_now ? nameserver_pick(base) : NULL;
2812290001Sglebius	req->next = req->prev = NULL;
2813290001Sglebius	req->handle = handle;
2814290001Sglebius	if (handle) {
2815290001Sglebius		handle->current_req = req;
2816290001Sglebius		handle->base = base;
2817290001Sglebius	}
2818290001Sglebius
2819290001Sglebius	return req;
2820290001Sglebiuserr1:
2821290001Sglebius	mm_free(req);
2822290001Sglebius	return NULL;
2823290001Sglebius}
2824290001Sglebius
2825290001Sglebiusstatic void
2826290001Sglebiusrequest_submit(struct request *const req) {
2827290001Sglebius	struct evdns_base *base = req->base;
2828290001Sglebius	ASSERT_LOCKED(base);
2829290001Sglebius	ASSERT_VALID_REQUEST(req);
2830290001Sglebius	if (req->ns) {
2831290001Sglebius		/* if it has a nameserver assigned then this is going */
2832290001Sglebius		/* straight into the inflight queue */
2833290001Sglebius		evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
2834290001Sglebius
2835290001Sglebius		base->global_requests_inflight++;
2836290001Sglebius		req->ns->requests_inflight++;
2837290001Sglebius
2838290001Sglebius		evdns_request_transmit(req);
2839290001Sglebius	} else {
2840290001Sglebius		evdns_request_insert(req, &base->req_waiting_head);
2841290001Sglebius		base->global_requests_waiting++;
2842290001Sglebius	}
2843290001Sglebius}
2844290001Sglebius
2845290001Sglebius/* exported function */
2846290001Sglebiusvoid
2847290001Sglebiusevdns_cancel_request(struct evdns_base *base, struct evdns_request *handle)
2848290001Sglebius{
2849290001Sglebius	struct request *req;
2850290001Sglebius
2851290001Sglebius	if (!handle->current_req)
2852290001Sglebius		return;
2853290001Sglebius
2854290001Sglebius	if (!base) {
2855290001Sglebius		/* This redundancy is silly; can we fix it? (Not for 2.0) XXXX */
2856290001Sglebius		base = handle->base;
2857290001Sglebius		if (!base)
2858290001Sglebius			base = handle->current_req->base;
2859290001Sglebius	}
2860290001Sglebius
2861290001Sglebius	EVDNS_LOCK(base);
2862290001Sglebius	if (handle->pending_cb) {
2863290001Sglebius		EVDNS_UNLOCK(base);
2864290001Sglebius		return;
2865290001Sglebius	}
2866290001Sglebius
2867290001Sglebius	req = handle->current_req;
2868290001Sglebius	ASSERT_VALID_REQUEST(req);
2869290001Sglebius
2870290001Sglebius	reply_schedule_callback(req, 0, DNS_ERR_CANCEL, NULL);
2871290001Sglebius	if (req->ns) {
2872290001Sglebius		/* remove from inflight queue */
2873290001Sglebius		request_finished(req, &REQ_HEAD(base, req->trans_id), 1);
2874290001Sglebius	} else {
2875290001Sglebius		/* remove from global_waiting head */
2876290001Sglebius		request_finished(req, &base->req_waiting_head, 1);
2877290001Sglebius	}
2878290001Sglebius	EVDNS_UNLOCK(base);
2879290001Sglebius}
2880290001Sglebius
2881290001Sglebius/* exported function */
2882290001Sglebiusstruct evdns_request *
2883290001Sglebiusevdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags,
2884290001Sglebius    evdns_callback_type callback, void *ptr) {
2885290001Sglebius	struct evdns_request *handle;
2886290001Sglebius	struct request *req;
2887290001Sglebius	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
2888290001Sglebius	handle = mm_calloc(1, sizeof(*handle));
2889290001Sglebius	if (handle == NULL)
2890290001Sglebius		return NULL;
2891290001Sglebius	EVDNS_LOCK(base);
2892290001Sglebius	if (flags & DNS_QUERY_NO_SEARCH) {
2893290001Sglebius		req =
2894290001Sglebius			request_new(base, handle, TYPE_A, name, flags,
2895290001Sglebius				    callback, ptr);
2896290001Sglebius		if (req)
2897290001Sglebius			request_submit(req);
2898290001Sglebius	} else {
2899290001Sglebius		search_request_new(base, handle, TYPE_A, name, flags,
2900290001Sglebius		    callback, ptr);
2901290001Sglebius	}
2902290001Sglebius	if (handle->current_req == NULL) {
2903290001Sglebius		mm_free(handle);
2904290001Sglebius		handle = NULL;
2905290001Sglebius	}
2906290001Sglebius	EVDNS_UNLOCK(base);
2907290001Sglebius	return handle;
2908290001Sglebius}
2909290001Sglebius
2910290001Sglebiusint evdns_resolve_ipv4(const char *name, int flags,
2911290001Sglebius					   evdns_callback_type callback, void *ptr)
2912290001Sglebius{
2913290001Sglebius	return evdns_base_resolve_ipv4(current_base, name, flags, callback, ptr)
2914290001Sglebius		? 0 : -1;
2915290001Sglebius}
2916290001Sglebius
2917290001Sglebius
2918290001Sglebius/* exported function */
2919290001Sglebiusstruct evdns_request *
2920290001Sglebiusevdns_base_resolve_ipv6(struct evdns_base *base,
2921290001Sglebius    const char *name, int flags,
2922290001Sglebius    evdns_callback_type callback, void *ptr)
2923290001Sglebius{
2924290001Sglebius	struct evdns_request *handle;
2925290001Sglebius	struct request *req;
2926290001Sglebius	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
2927290001Sglebius	handle = mm_calloc(1, sizeof(*handle));
2928290001Sglebius	if (handle == NULL)
2929290001Sglebius		return NULL;
2930290001Sglebius	EVDNS_LOCK(base);
2931290001Sglebius	if (flags & DNS_QUERY_NO_SEARCH) {
2932290001Sglebius		req = request_new(base, handle, TYPE_AAAA, name, flags,
2933290001Sglebius				  callback, ptr);
2934290001Sglebius		if (req)
2935290001Sglebius			request_submit(req);
2936290001Sglebius	} else {
2937290001Sglebius		search_request_new(base, handle, TYPE_AAAA, name, flags,
2938290001Sglebius		    callback, ptr);
2939290001Sglebius	}
2940290001Sglebius	if (handle->current_req == NULL) {
2941290001Sglebius		mm_free(handle);
2942290001Sglebius		handle = NULL;
2943290001Sglebius	}
2944290001Sglebius	EVDNS_UNLOCK(base);
2945290001Sglebius	return handle;
2946290001Sglebius}
2947290001Sglebius
2948290001Sglebiusint evdns_resolve_ipv6(const char *name, int flags,
2949290001Sglebius    evdns_callback_type callback, void *ptr) {
2950290001Sglebius	return evdns_base_resolve_ipv6(current_base, name, flags, callback, ptr)
2951290001Sglebius		? 0 : -1;
2952290001Sglebius}
2953290001Sglebius
2954290001Sglebiusstruct evdns_request *
2955290001Sglebiusevdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
2956290001Sglebius	char buf[32];
2957290001Sglebius	struct evdns_request *handle;
2958290001Sglebius	struct request *req;
2959290001Sglebius	u32 a;
2960290001Sglebius	EVUTIL_ASSERT(in);
2961290001Sglebius	a = ntohl(in->s_addr);
2962290001Sglebius	evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
2963290001Sglebius			(int)(u8)((a	)&0xff),
2964290001Sglebius			(int)(u8)((a>>8 )&0xff),
2965290001Sglebius			(int)(u8)((a>>16)&0xff),
2966290001Sglebius			(int)(u8)((a>>24)&0xff));
2967290001Sglebius	handle = mm_calloc(1, sizeof(*handle));
2968290001Sglebius	if (handle == NULL)
2969290001Sglebius		return NULL;
2970290001Sglebius	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
2971290001Sglebius	EVDNS_LOCK(base);
2972290001Sglebius	req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
2973290001Sglebius	if (req)
2974290001Sglebius		request_submit(req);
2975290001Sglebius	if (handle->current_req == NULL) {
2976290001Sglebius		mm_free(handle);
2977290001Sglebius		handle = NULL;
2978290001Sglebius	}
2979290001Sglebius	EVDNS_UNLOCK(base);
2980290001Sglebius	return (handle);
2981290001Sglebius}
2982290001Sglebius
2983290001Sglebiusint evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
2984290001Sglebius	return evdns_base_resolve_reverse(current_base, in, flags, callback, ptr)
2985290001Sglebius		? 0 : -1;
2986290001Sglebius}
2987290001Sglebius
2988290001Sglebiusstruct evdns_request *
2989290001Sglebiusevdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
2990290001Sglebius	/* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
2991290001Sglebius	char buf[73];
2992290001Sglebius	char *cp;
2993290001Sglebius	struct evdns_request *handle;
2994290001Sglebius	struct request *req;
2995290001Sglebius	int i;
2996290001Sglebius	EVUTIL_ASSERT(in);
2997290001Sglebius	cp = buf;
2998290001Sglebius	for (i=15; i >= 0; --i) {
2999290001Sglebius		u8 byte = in->s6_addr[i];
3000290001Sglebius		*cp++ = "0123456789abcdef"[byte & 0x0f];
3001290001Sglebius		*cp++ = '.';
3002290001Sglebius		*cp++ = "0123456789abcdef"[byte >> 4];
3003290001Sglebius		*cp++ = '.';
3004290001Sglebius	}
3005290001Sglebius	EVUTIL_ASSERT(cp + strlen("ip6.arpa") < buf+sizeof(buf));
3006290001Sglebius	memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
3007290001Sglebius	handle = mm_calloc(1, sizeof(*handle));
3008290001Sglebius	if (handle == NULL)
3009290001Sglebius		return NULL;
3010290001Sglebius	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
3011290001Sglebius	EVDNS_LOCK(base);
3012290001Sglebius	req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
3013290001Sglebius	if (req)
3014290001Sglebius		request_submit(req);
3015290001Sglebius	if (handle->current_req == NULL) {
3016290001Sglebius		mm_free(handle);
3017290001Sglebius		handle = NULL;
3018290001Sglebius	}
3019290001Sglebius	EVDNS_UNLOCK(base);
3020290001Sglebius	return (handle);
3021290001Sglebius}
3022290001Sglebius
3023290001Sglebiusint evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
3024290001Sglebius	return evdns_base_resolve_reverse_ipv6(current_base, in, flags, callback, ptr)
3025290001Sglebius		? 0 : -1;
3026290001Sglebius}
3027290001Sglebius
3028290001Sglebius/* ================================================================= */
3029290001Sglebius/* Search support */
3030290001Sglebius/* */
3031290001Sglebius/* the libc resolver has support for searching a number of domains */
3032290001Sglebius/* to find a name. If nothing else then it takes the single domain */
3033290001Sglebius/* from the gethostname() call. */
3034290001Sglebius/* */
3035290001Sglebius/* It can also be configured via the domain and search options in a */
3036290001Sglebius/* resolv.conf. */
3037290001Sglebius/* */
3038290001Sglebius/* The ndots option controls how many dots it takes for the resolver */
3039290001Sglebius/* to decide that a name is non-local and so try a raw lookup first. */
3040290001Sglebius
3041290001Sglebiusstruct search_domain {
3042290001Sglebius	int len;
3043290001Sglebius	struct search_domain *next;
3044290001Sglebius	/* the text string is appended to this structure */
3045290001Sglebius};
3046290001Sglebius
3047290001Sglebiusstruct search_state {
3048290001Sglebius	int refcount;
3049290001Sglebius	int ndots;
3050290001Sglebius	int num_domains;
3051290001Sglebius	struct search_domain *head;
3052290001Sglebius};
3053290001Sglebius
3054290001Sglebiusstatic void
3055290001Sglebiussearch_state_decref(struct search_state *const state) {
3056290001Sglebius	if (!state) return;
3057290001Sglebius	state->refcount--;
3058290001Sglebius	if (!state->refcount) {
3059290001Sglebius		struct search_domain *next, *dom;
3060290001Sglebius		for (dom = state->head; dom; dom = next) {
3061290001Sglebius			next = dom->next;
3062290001Sglebius			mm_free(dom);
3063290001Sglebius		}
3064290001Sglebius		mm_free(state);
3065290001Sglebius	}
3066290001Sglebius}
3067290001Sglebius
3068290001Sglebiusstatic struct search_state *
3069290001Sglebiussearch_state_new(void) {
3070290001Sglebius	struct search_state *state = (struct search_state *) mm_malloc(sizeof(struct search_state));
3071290001Sglebius	if (!state) return NULL;
3072290001Sglebius	memset(state, 0, sizeof(struct search_state));
3073290001Sglebius	state->refcount = 1;
3074290001Sglebius	state->ndots = 1;
3075290001Sglebius
3076290001Sglebius	return state;
3077290001Sglebius}
3078290001Sglebius
3079290001Sglebiusstatic void
3080290001Sglebiussearch_postfix_clear(struct evdns_base *base) {
3081290001Sglebius	search_state_decref(base->global_search_state);
3082290001Sglebius
3083290001Sglebius	base->global_search_state = search_state_new();
3084290001Sglebius}
3085290001Sglebius
3086290001Sglebius/* exported function */
3087290001Sglebiusvoid
3088290001Sglebiusevdns_base_search_clear(struct evdns_base *base)
3089290001Sglebius{
3090290001Sglebius	EVDNS_LOCK(base);
3091290001Sglebius	search_postfix_clear(base);
3092290001Sglebius	EVDNS_UNLOCK(base);
3093290001Sglebius}
3094290001Sglebius
3095290001Sglebiusvoid
3096290001Sglebiusevdns_search_clear(void) {
3097290001Sglebius	evdns_base_search_clear(current_base);
3098290001Sglebius}
3099290001Sglebius
3100290001Sglebiusstatic void
3101290001Sglebiussearch_postfix_add(struct evdns_base *base, const char *domain) {
3102290001Sglebius	size_t domain_len;
3103290001Sglebius	struct search_domain *sdomain;
3104290001Sglebius	while (domain[0] == '.') domain++;
3105290001Sglebius	domain_len = strlen(domain);
3106290001Sglebius
3107290001Sglebius	ASSERT_LOCKED(base);
3108290001Sglebius	if (!base->global_search_state) base->global_search_state = search_state_new();
3109290001Sglebius	if (!base->global_search_state) return;
3110290001Sglebius	base->global_search_state->num_domains++;
3111290001Sglebius
3112290001Sglebius	sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len);
3113290001Sglebius	if (!sdomain) return;
3114290001Sglebius	memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
3115290001Sglebius	sdomain->next = base->global_search_state->head;
3116290001Sglebius	sdomain->len = (int) domain_len;
3117290001Sglebius
3118290001Sglebius	base->global_search_state->head = sdomain;
3119290001Sglebius}
3120290001Sglebius
3121290001Sglebius/* reverse the order of members in the postfix list. This is needed because, */
3122290001Sglebius/* when parsing resolv.conf we push elements in the wrong order */
3123290001Sglebiusstatic void
3124290001Sglebiussearch_reverse(struct evdns_base *base) {
3125290001Sglebius	struct search_domain *cur, *prev = NULL, *next;
3126290001Sglebius	ASSERT_LOCKED(base);
3127290001Sglebius	cur = base->global_search_state->head;
3128290001Sglebius	while (cur) {
3129290001Sglebius		next = cur->next;
3130290001Sglebius		cur->next = prev;
3131290001Sglebius		prev = cur;
3132290001Sglebius		cur = next;
3133290001Sglebius	}
3134290001Sglebius
3135290001Sglebius	base->global_search_state->head = prev;
3136290001Sglebius}
3137290001Sglebius
3138290001Sglebius/* exported function */
3139290001Sglebiusvoid
3140290001Sglebiusevdns_base_search_add(struct evdns_base *base, const char *domain) {
3141290001Sglebius	EVDNS_LOCK(base);
3142290001Sglebius	search_postfix_add(base, domain);
3143290001Sglebius	EVDNS_UNLOCK(base);
3144290001Sglebius}
3145290001Sglebiusvoid
3146290001Sglebiusevdns_search_add(const char *domain) {
3147290001Sglebius	evdns_base_search_add(current_base, domain);
3148290001Sglebius}
3149290001Sglebius
3150290001Sglebius/* exported function */
3151290001Sglebiusvoid
3152290001Sglebiusevdns_base_search_ndots_set(struct evdns_base *base, const int ndots) {
3153290001Sglebius	EVDNS_LOCK(base);
3154290001Sglebius	if (!base->global_search_state) base->global_search_state = search_state_new();
3155290001Sglebius	if (base->global_search_state)
3156290001Sglebius		base->global_search_state->ndots = ndots;
3157290001Sglebius	EVDNS_UNLOCK(base);
3158290001Sglebius}
3159290001Sglebiusvoid
3160290001Sglebiusevdns_search_ndots_set(const int ndots) {
3161290001Sglebius	evdns_base_search_ndots_set(current_base, ndots);
3162290001Sglebius}
3163290001Sglebius
3164290001Sglebiusstatic void
3165290001Sglebiussearch_set_from_hostname(struct evdns_base *base) {
3166290001Sglebius	char hostname[HOST_NAME_MAX + 1], *domainname;
3167290001Sglebius
3168290001Sglebius	ASSERT_LOCKED(base);
3169290001Sglebius	search_postfix_clear(base);
3170290001Sglebius	if (gethostname(hostname, sizeof(hostname))) return;
3171290001Sglebius	domainname = strchr(hostname, '.');
3172290001Sglebius	if (!domainname) return;
3173290001Sglebius	search_postfix_add(base, domainname);
3174290001Sglebius}
3175290001Sglebius
3176290001Sglebius/* warning: returns malloced string */
3177290001Sglebiusstatic char *
3178290001Sglebiussearch_make_new(const struct search_state *const state, int n, const char *const base_name) {
3179290001Sglebius	const size_t base_len = strlen(base_name);
3180290001Sglebius	const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
3181290001Sglebius	struct search_domain *dom;
3182290001Sglebius
3183290001Sglebius	for (dom = state->head; dom; dom = dom->next) {
3184290001Sglebius		if (!n--) {
3185290001Sglebius			/* this is the postfix we want */
3186290001Sglebius			/* the actual postfix string is kept at the end of the structure */
3187290001Sglebius			const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
3188290001Sglebius			const int postfix_len = dom->len;
3189290001Sglebius			char *const newname = (char *) mm_malloc(base_len + need_to_append_dot + postfix_len + 1);
3190290001Sglebius			if (!newname) return NULL;
3191290001Sglebius			memcpy(newname, base_name, base_len);
3192290001Sglebius			if (need_to_append_dot) newname[base_len] = '.';
3193290001Sglebius			memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
3194290001Sglebius			newname[base_len + need_to_append_dot + postfix_len] = 0;
3195290001Sglebius			return newname;
3196290001Sglebius		}
3197290001Sglebius	}
3198290001Sglebius
3199290001Sglebius	/* we ran off the end of the list and still didn't find the requested string */
3200290001Sglebius	EVUTIL_ASSERT(0);
3201290001Sglebius	return NULL; /* unreachable; stops warnings in some compilers. */
3202290001Sglebius}
3203290001Sglebius
3204290001Sglebiusstatic struct request *
3205290001Sglebiussearch_request_new(struct evdns_base *base, struct evdns_request *handle,
3206290001Sglebius		   int type, const char *const name, int flags,
3207290001Sglebius		   evdns_callback_type user_callback, void *user_arg) {
3208290001Sglebius	ASSERT_LOCKED(base);
3209290001Sglebius	EVUTIL_ASSERT(type == TYPE_A || type == TYPE_AAAA);
3210290001Sglebius	EVUTIL_ASSERT(handle->current_req == NULL);
3211290001Sglebius	if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
3212290001Sglebius	     base->global_search_state &&
3213290001Sglebius		 base->global_search_state->num_domains) {
3214290001Sglebius		/* we have some domains to search */
3215290001Sglebius		struct request *req;
3216290001Sglebius		if (string_num_dots(name) >= base->global_search_state->ndots) {
3217290001Sglebius			req = request_new(base, handle, type, name, flags, user_callback, user_arg);
3218290001Sglebius			if (!req) return NULL;
3219290001Sglebius			handle->search_index = -1;
3220290001Sglebius		} else {
3221290001Sglebius			char *const new_name = search_make_new(base->global_search_state, 0, name);
3222290001Sglebius			if (!new_name) return NULL;
3223290001Sglebius			req = request_new(base, handle, type, new_name, flags, user_callback, user_arg);
3224290001Sglebius			mm_free(new_name);
3225290001Sglebius			if (!req) return NULL;
3226290001Sglebius			handle->search_index = 0;
3227290001Sglebius		}
3228290001Sglebius		EVUTIL_ASSERT(handle->search_origname == NULL);
3229290001Sglebius		handle->search_origname = mm_strdup(name);
3230290001Sglebius		if (handle->search_origname == NULL) {
3231290001Sglebius			/* XXX Should we dealloc req? If yes, how? */
3232290001Sglebius			if (req)
3233290001Sglebius				mm_free(req);
3234290001Sglebius			return NULL;
3235290001Sglebius		}
3236290001Sglebius		handle->search_state = base->global_search_state;
3237290001Sglebius		handle->search_flags = flags;
3238290001Sglebius		base->global_search_state->refcount++;
3239290001Sglebius		request_submit(req);
3240290001Sglebius		return req;
3241290001Sglebius	} else {
3242290001Sglebius		struct request *const req = request_new(base, handle, type, name, flags, user_callback, user_arg);
3243290001Sglebius		if (!req) return NULL;
3244290001Sglebius		request_submit(req);
3245290001Sglebius		return req;
3246290001Sglebius	}
3247290001Sglebius}
3248290001Sglebius
3249290001Sglebius/* this is called when a request has failed to find a name. We need to check */
3250290001Sglebius/* if it is part of a search and, if so, try the next name in the list */
3251290001Sglebius/* returns: */
3252290001Sglebius/*   0 another request has been submitted */
3253290001Sglebius/*   1 no more requests needed */
3254290001Sglebiusstatic int
3255290001Sglebiussearch_try_next(struct evdns_request *const handle) {
3256290001Sglebius	struct request *req = handle->current_req;
3257290001Sglebius	struct evdns_base *base = req->base;
3258290001Sglebius	struct request *newreq;
3259290001Sglebius	ASSERT_LOCKED(base);
3260290001Sglebius	if (handle->search_state) {
3261290001Sglebius		/* it is part of a search */
3262290001Sglebius		char *new_name;
3263290001Sglebius		handle->search_index++;
3264290001Sglebius		if (handle->search_index >= handle->search_state->num_domains) {
3265290001Sglebius			/* no more postfixes to try, however we may need to try */
3266290001Sglebius			/* this name without a postfix */
3267290001Sglebius			if (string_num_dots(handle->search_origname) < handle->search_state->ndots) {
3268290001Sglebius				/* yep, we need to try it raw */
3269290001Sglebius				newreq = request_new(base, NULL, req->request_type, handle->search_origname, handle->search_flags, req->user_callback, req->user_pointer);
3270290001Sglebius				log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", handle->search_origname);
3271290001Sglebius				if (newreq) {
3272290001Sglebius					search_request_finished(handle);
3273290001Sglebius					goto submit_next;
3274290001Sglebius				}
3275290001Sglebius			}
3276290001Sglebius			return 1;
3277290001Sglebius		}
3278290001Sglebius
3279290001Sglebius		new_name = search_make_new(handle->search_state, handle->search_index, handle->search_origname);
3280290001Sglebius		if (!new_name) return 1;
3281290001Sglebius		log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, handle->search_index);
3282290001Sglebius		newreq = request_new(base, NULL, req->request_type, new_name, handle->search_flags, req->user_callback, req->user_pointer);
3283290001Sglebius		mm_free(new_name);
3284290001Sglebius		if (!newreq) return 1;
3285290001Sglebius		goto submit_next;
3286290001Sglebius	}
3287290001Sglebius	return 1;
3288290001Sglebius
3289290001Sglebiussubmit_next:
3290290001Sglebius	request_finished(req, &REQ_HEAD(req->base, req->trans_id), 0);
3291290001Sglebius	handle->current_req = newreq;
3292290001Sglebius	newreq->handle = handle;
3293290001Sglebius	request_submit(newreq);
3294290001Sglebius	return 0;
3295290001Sglebius}
3296290001Sglebius
3297290001Sglebiusstatic void
3298290001Sglebiussearch_request_finished(struct evdns_request *const handle) {
3299290001Sglebius	ASSERT_LOCKED(handle->current_req->base);
3300290001Sglebius	if (handle->search_state) {
3301290001Sglebius		search_state_decref(handle->search_state);
3302290001Sglebius		handle->search_state = NULL;
3303290001Sglebius	}
3304290001Sglebius	if (handle->search_origname) {
3305290001Sglebius		mm_free(handle->search_origname);
3306290001Sglebius		handle->search_origname = NULL;
3307290001Sglebius	}
3308290001Sglebius}
3309290001Sglebius
3310290001Sglebius/* ================================================================= */
3311290001Sglebius/* Parsing resolv.conf files */
3312290001Sglebius
3313290001Sglebiusstatic void
3314290001Sglebiusevdns_resolv_set_defaults(struct evdns_base *base, int flags) {
3315290001Sglebius	/* if the file isn't found then we assume a local resolver */
3316290001Sglebius	ASSERT_LOCKED(base);
3317290001Sglebius	if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base);
3318290001Sglebius	if (flags & DNS_OPTION_NAMESERVERS) evdns_base_nameserver_ip_add(base,"127.0.0.1");
3319290001Sglebius}
3320290001Sglebius
3321290001Sglebius#ifndef EVENT__HAVE_STRTOK_R
3322290001Sglebiusstatic char *
3323290001Sglebiusstrtok_r(char *s, const char *delim, char **state) {
3324290001Sglebius	char *cp, *start;
3325290001Sglebius	start = cp = s ? s : *state;
3326290001Sglebius	if (!cp)
3327290001Sglebius		return NULL;
3328290001Sglebius	while (*cp && !strchr(delim, *cp))
3329290001Sglebius		++cp;
3330290001Sglebius	if (!*cp) {
3331290001Sglebius		if (cp == start)
3332290001Sglebius			return NULL;
3333290001Sglebius		*state = NULL;
3334290001Sglebius		return start;
3335290001Sglebius	} else {
3336290001Sglebius		*cp++ = '\0';
3337290001Sglebius		*state = cp;
3338290001Sglebius		return start;
3339290001Sglebius	}
3340290001Sglebius}
3341290001Sglebius#endif
3342290001Sglebius
3343290001Sglebius/* helper version of atoi which returns -1 on error */
3344290001Sglebiusstatic int
3345290001Sglebiusstrtoint(const char *const str)
3346290001Sglebius{
3347290001Sglebius	char *endptr;
3348290001Sglebius	const int r = strtol(str, &endptr, 10);
3349290001Sglebius	if (*endptr) return -1;
3350290001Sglebius	return r;
3351290001Sglebius}
3352290001Sglebius
3353290001Sglebius/* Parse a number of seconds into a timeval; return -1 on error. */
3354290001Sglebiusstatic int
3355290001Sglebiusevdns_strtotimeval(const char *const str, struct timeval *out)
3356290001Sglebius{
3357290001Sglebius	double d;
3358290001Sglebius	char *endptr;
3359290001Sglebius	d = strtod(str, &endptr);
3360290001Sglebius	if (*endptr) return -1;
3361290001Sglebius	if (d < 0) return -1;
3362290001Sglebius	out->tv_sec = (int) d;
3363290001Sglebius	out->tv_usec = (int) ((d - (int) d)*1000000);
3364290001Sglebius	if (out->tv_sec == 0 && out->tv_usec < 1000) /* less than 1 msec */
3365290001Sglebius		return -1;
3366290001Sglebius	return 0;
3367290001Sglebius}
3368290001Sglebius
3369290001Sglebius/* helper version of atoi that returns -1 on error and clips to bounds. */
3370290001Sglebiusstatic int
3371290001Sglebiusstrtoint_clipped(const char *const str, int min, int max)
3372290001Sglebius{
3373290001Sglebius	int r = strtoint(str);
3374290001Sglebius	if (r == -1)
3375290001Sglebius		return r;
3376290001Sglebius	else if (r<min)
3377290001Sglebius		return min;
3378290001Sglebius	else if (r>max)
3379290001Sglebius		return max;
3380290001Sglebius	else
3381290001Sglebius		return r;
3382290001Sglebius}
3383290001Sglebius
3384290001Sglebiusstatic int
3385290001Sglebiusevdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
3386290001Sglebius{
3387290001Sglebius	int old_n_heads = base->n_req_heads, n_heads;
3388290001Sglebius	struct request **old_heads = base->req_heads, **new_heads, *req;
3389290001Sglebius	int i;
3390290001Sglebius
3391290001Sglebius	ASSERT_LOCKED(base);
3392290001Sglebius	if (maxinflight < 1)
3393290001Sglebius		maxinflight = 1;
3394290001Sglebius	n_heads = (maxinflight+4) / 5;
3395290001Sglebius	EVUTIL_ASSERT(n_heads > 0);
3396290001Sglebius	new_heads = mm_calloc(n_heads, sizeof(struct request*));
3397290001Sglebius	if (!new_heads)
3398290001Sglebius		return (-1);
3399290001Sglebius	if (old_heads) {
3400290001Sglebius		for (i = 0; i < old_n_heads; ++i) {
3401290001Sglebius			while (old_heads[i]) {
3402290001Sglebius				req = old_heads[i];
3403290001Sglebius				evdns_request_remove(req, &old_heads[i]);
3404290001Sglebius				evdns_request_insert(req, &new_heads[req->trans_id % n_heads]);
3405290001Sglebius			}
3406290001Sglebius		}
3407290001Sglebius		mm_free(old_heads);
3408290001Sglebius	}
3409290001Sglebius	base->req_heads = new_heads;
3410290001Sglebius	base->n_req_heads = n_heads;
3411290001Sglebius	base->global_max_requests_inflight = maxinflight;
3412290001Sglebius	return (0);
3413290001Sglebius}
3414290001Sglebius
3415290001Sglebius/* exported function */
3416290001Sglebiusint
3417290001Sglebiusevdns_base_set_option(struct evdns_base *base,
3418290001Sglebius    const char *option, const char *val)
3419290001Sglebius{
3420290001Sglebius	int res;
3421290001Sglebius	EVDNS_LOCK(base);
3422290001Sglebius	res = evdns_base_set_option_impl(base, option, val, DNS_OPTIONS_ALL);
3423290001Sglebius	EVDNS_UNLOCK(base);
3424290001Sglebius	return res;
3425290001Sglebius}
3426290001Sglebius
3427290001Sglebiusstatic inline int
3428290001Sglebiusstr_matches_option(const char *s1, const char *optionname)
3429290001Sglebius{
3430290001Sglebius	/* Option names are given as "option:" We accept either 'option' in
3431290001Sglebius	 * s1, or 'option:randomjunk'.  The latter form is to implement the
3432290001Sglebius	 * resolv.conf parser. */
3433290001Sglebius	size_t optlen = strlen(optionname);
3434290001Sglebius	size_t slen = strlen(s1);
3435290001Sglebius	if (slen == optlen || slen == optlen - 1)
3436290001Sglebius		return !strncmp(s1, optionname, slen);
3437290001Sglebius	else if (slen > optlen)
3438290001Sglebius		return !strncmp(s1, optionname, optlen);
3439290001Sglebius	else
3440290001Sglebius		return 0;
3441290001Sglebius}
3442290001Sglebius
3443290001Sglebiusstatic int
3444290001Sglebiusevdns_base_set_option_impl(struct evdns_base *base,
3445290001Sglebius    const char *option, const char *val, int flags)
3446290001Sglebius{
3447290001Sglebius	ASSERT_LOCKED(base);
3448290001Sglebius	if (str_matches_option(option, "ndots:")) {
3449290001Sglebius		const int ndots = strtoint(val);
3450290001Sglebius		if (ndots == -1) return -1;
3451290001Sglebius		if (!(flags & DNS_OPTION_SEARCH)) return 0;
3452290001Sglebius		log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
3453290001Sglebius		if (!base->global_search_state) base->global_search_state = search_state_new();
3454290001Sglebius		if (!base->global_search_state) return -1;
3455290001Sglebius		base->global_search_state->ndots = ndots;
3456290001Sglebius	} else if (str_matches_option(option, "timeout:")) {
3457290001Sglebius		struct timeval tv;
3458290001Sglebius		if (evdns_strtotimeval(val, &tv) == -1) return -1;
3459290001Sglebius		if (!(flags & DNS_OPTION_MISC)) return 0;
3460290001Sglebius		log(EVDNS_LOG_DEBUG, "Setting timeout to %s", val);
3461290001Sglebius		memcpy(&base->global_timeout, &tv, sizeof(struct timeval));
3462290001Sglebius	} else if (str_matches_option(option, "getaddrinfo-allow-skew:")) {
3463290001Sglebius		struct timeval tv;
3464290001Sglebius		if (evdns_strtotimeval(val, &tv) == -1) return -1;
3465290001Sglebius		if (!(flags & DNS_OPTION_MISC)) return 0;
3466290001Sglebius		log(EVDNS_LOG_DEBUG, "Setting getaddrinfo-allow-skew to %s",
3467290001Sglebius		    val);
3468290001Sglebius		memcpy(&base->global_getaddrinfo_allow_skew, &tv,
3469290001Sglebius		    sizeof(struct timeval));
3470290001Sglebius	} else if (str_matches_option(option, "max-timeouts:")) {
3471290001Sglebius		const int maxtimeout = strtoint_clipped(val, 1, 255);
3472290001Sglebius		if (maxtimeout == -1) return -1;
3473290001Sglebius		if (!(flags & DNS_OPTION_MISC)) return 0;
3474290001Sglebius		log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
3475290001Sglebius			maxtimeout);
3476290001Sglebius		base->global_max_nameserver_timeout = maxtimeout;
3477290001Sglebius	} else if (str_matches_option(option, "max-inflight:")) {
3478290001Sglebius		const int maxinflight = strtoint_clipped(val, 1, 65000);
3479290001Sglebius		if (maxinflight == -1) return -1;
3480290001Sglebius		if (!(flags & DNS_OPTION_MISC)) return 0;
3481290001Sglebius		log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
3482290001Sglebius			maxinflight);
3483290001Sglebius		evdns_base_set_max_requests_inflight(base, maxinflight);
3484290001Sglebius	} else if (str_matches_option(option, "attempts:")) {
3485290001Sglebius		int retries = strtoint(val);
3486290001Sglebius		if (retries == -1) return -1;
3487290001Sglebius		if (retries > 255) retries = 255;
3488290001Sglebius		if (!(flags & DNS_OPTION_MISC)) return 0;
3489290001Sglebius		log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
3490290001Sglebius		base->global_max_retransmits = retries;
3491290001Sglebius	} else if (str_matches_option(option, "randomize-case:")) {
3492290001Sglebius		int randcase = strtoint(val);
3493290001Sglebius		if (!(flags & DNS_OPTION_MISC)) return 0;
3494290001Sglebius		base->global_randomize_case = randcase;
3495290001Sglebius	} else if (str_matches_option(option, "bind-to:")) {
3496290001Sglebius		/* XXX This only applies to successive nameservers, not
3497290001Sglebius		 * to already-configured ones.	We might want to fix that. */
3498290001Sglebius		int len = sizeof(base->global_outgoing_address);
3499290001Sglebius		if (!(flags & DNS_OPTION_NAMESERVERS)) return 0;
3500290001Sglebius		if (evutil_parse_sockaddr_port(val,
3501290001Sglebius			(struct sockaddr*)&base->global_outgoing_address, &len))
3502290001Sglebius			return -1;
3503290001Sglebius		base->global_outgoing_addrlen = len;
3504290001Sglebius	} else if (str_matches_option(option, "initial-probe-timeout:")) {
3505290001Sglebius		struct timeval tv;
3506290001Sglebius		if (evdns_strtotimeval(val, &tv) == -1) return -1;
3507290001Sglebius		if (tv.tv_sec > 3600)
3508290001Sglebius			tv.tv_sec = 3600;
3509290001Sglebius		if (!(flags & DNS_OPTION_MISC)) return 0;
3510290001Sglebius		log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s",
3511290001Sglebius		    val);
3512290001Sglebius		memcpy(&base->global_nameserver_probe_initial_timeout, &tv,
3513290001Sglebius		    sizeof(tv));
3514290001Sglebius	}
3515290001Sglebius	return 0;
3516290001Sglebius}
3517290001Sglebius
3518290001Sglebiusint
3519290001Sglebiusevdns_set_option(const char *option, const char *val, int flags)
3520290001Sglebius{
3521290001Sglebius	if (!current_base)
3522290001Sglebius		current_base = evdns_base_new(NULL, 0);
3523290001Sglebius	return evdns_base_set_option(current_base, option, val);
3524290001Sglebius}
3525290001Sglebius
3526290001Sglebiusstatic void
3527290001Sglebiusresolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) {
3528290001Sglebius	char *strtok_state;
3529290001Sglebius	static const char *const delims = " \t";
3530290001Sglebius#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
3531290001Sglebius
3532290001Sglebius
3533290001Sglebius	char *const first_token = strtok_r(start, delims, &strtok_state);
3534290001Sglebius	ASSERT_LOCKED(base);
3535290001Sglebius	if (!first_token) return;
3536290001Sglebius
3537290001Sglebius	if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
3538290001Sglebius		const char *const nameserver = NEXT_TOKEN;
3539290001Sglebius
3540290001Sglebius		if (nameserver)
3541290001Sglebius			evdns_base_nameserver_ip_add(base, nameserver);
3542290001Sglebius	} else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
3543290001Sglebius		const char *const domain = NEXT_TOKEN;
3544290001Sglebius		if (domain) {
3545290001Sglebius			search_postfix_clear(base);
3546290001Sglebius			search_postfix_add(base, domain);
3547290001Sglebius		}
3548290001Sglebius	} else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
3549290001Sglebius		const char *domain;
3550290001Sglebius		search_postfix_clear(base);
3551290001Sglebius
3552290001Sglebius		while ((domain = NEXT_TOKEN)) {
3553290001Sglebius			search_postfix_add(base, domain);
3554290001Sglebius		}
3555290001Sglebius		search_reverse(base);
3556290001Sglebius	} else if (!strcmp(first_token, "options")) {
3557290001Sglebius		const char *option;
3558290001Sglebius		while ((option = NEXT_TOKEN)) {
3559290001Sglebius			const char *val = strchr(option, ':');
3560290001Sglebius			evdns_base_set_option_impl(base, option, val ? val+1 : "", flags);
3561290001Sglebius		}
3562290001Sglebius	}
3563290001Sglebius#undef NEXT_TOKEN
3564290001Sglebius}
3565290001Sglebius
3566290001Sglebius/* exported function */
3567290001Sglebius/* returns: */
3568290001Sglebius/*   0 no errors */
3569290001Sglebius/*   1 failed to open file */
3570290001Sglebius/*   2 failed to stat file */
3571290001Sglebius/*   3 file too large */
3572290001Sglebius/*   4 out of memory */
3573290001Sglebius/*   5 short read from file */
3574290001Sglebiusint
3575290001Sglebiusevdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename) {
3576290001Sglebius	int res;
3577290001Sglebius	EVDNS_LOCK(base);
3578290001Sglebius	res = evdns_base_resolv_conf_parse_impl(base, flags, filename);
3579290001Sglebius	EVDNS_UNLOCK(base);
3580290001Sglebius	return res;
3581290001Sglebius}
3582290001Sglebius
3583290001Sglebiusstatic char *
3584290001Sglebiusevdns_get_default_hosts_filename(void)
3585290001Sglebius{
3586290001Sglebius#ifdef _WIN32
3587290001Sglebius	/* Windows is a little coy about where it puts its configuration
3588290001Sglebius	 * files.  Sure, they're _usually_ in C:\windows\system32, but
3589290001Sglebius	 * there's no reason in principle they couldn't be in
3590290001Sglebius	 * W:\hoboken chicken emergency\
3591290001Sglebius	 */
3592290001Sglebius	char path[MAX_PATH+1];
3593290001Sglebius	static const char hostfile[] = "\\drivers\\etc\\hosts";
3594290001Sglebius	char *path_out;
3595290001Sglebius	size_t len_out;
3596290001Sglebius
3597290001Sglebius	if (! SHGetSpecialFolderPathA(NULL, path, CSIDL_SYSTEM, 0))
3598290001Sglebius		return NULL;
3599290001Sglebius	len_out = strlen(path)+strlen(hostfile)+1;
3600290001Sglebius	path_out = mm_malloc(len_out);
3601290001Sglebius	evutil_snprintf(path_out, len_out, "%s%s", path, hostfile);
3602290001Sglebius	return path_out;
3603290001Sglebius#else
3604290001Sglebius	return mm_strdup("/etc/hosts");
3605290001Sglebius#endif
3606290001Sglebius}
3607290001Sglebius
3608290001Sglebiusstatic int
3609290001Sglebiusevdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) {
3610290001Sglebius	size_t n;
3611290001Sglebius	char *resolv;
3612290001Sglebius	char *start;
3613290001Sglebius	int err = 0;
3614290001Sglebius
3615290001Sglebius	log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
3616290001Sglebius
3617290001Sglebius	if (flags & DNS_OPTION_HOSTSFILE) {
3618290001Sglebius		char *fname = evdns_get_default_hosts_filename();
3619290001Sglebius		evdns_base_load_hosts(base, fname);
3620290001Sglebius		if (fname)
3621290001Sglebius			mm_free(fname);
3622290001Sglebius	}
3623290001Sglebius
3624290001Sglebius	if ((err = evutil_read_file_(filename, &resolv, &n, 0)) < 0) {
3625290001Sglebius		if (err == -1) {
3626290001Sglebius			/* No file. */
3627290001Sglebius			evdns_resolv_set_defaults(base, flags);
3628290001Sglebius			return 1;
3629290001Sglebius		} else {
3630290001Sglebius			return 2;
3631290001Sglebius		}
3632290001Sglebius	}
3633290001Sglebius
3634290001Sglebius	start = resolv;
3635290001Sglebius	for (;;) {
3636290001Sglebius		char *const newline = strchr(start, '\n');
3637290001Sglebius		if (!newline) {
3638290001Sglebius			resolv_conf_parse_line(base, start, flags);
3639290001Sglebius			break;
3640290001Sglebius		} else {
3641290001Sglebius			*newline = 0;
3642290001Sglebius			resolv_conf_parse_line(base, start, flags);
3643290001Sglebius			start = newline + 1;
3644290001Sglebius		}
3645290001Sglebius	}
3646290001Sglebius
3647290001Sglebius	if (!base->server_head && (flags & DNS_OPTION_NAMESERVERS)) {
3648290001Sglebius		/* no nameservers were configured. */
3649290001Sglebius		evdns_base_nameserver_ip_add(base, "127.0.0.1");
3650290001Sglebius		err = 6;
3651290001Sglebius	}
3652290001Sglebius	if (flags & DNS_OPTION_SEARCH && (!base->global_search_state || base->global_search_state->num_domains == 0)) {
3653290001Sglebius		search_set_from_hostname(base);
3654290001Sglebius	}
3655290001Sglebius
3656290001Sglebius	mm_free(resolv);
3657290001Sglebius	return err;
3658290001Sglebius}
3659290001Sglebius
3660290001Sglebiusint
3661290001Sglebiusevdns_resolv_conf_parse(int flags, const char *const filename) {
3662290001Sglebius	if (!current_base)
3663290001Sglebius		current_base = evdns_base_new(NULL, 0);
3664290001Sglebius	return evdns_base_resolv_conf_parse(current_base, flags, filename);
3665290001Sglebius}
3666290001Sglebius
3667290001Sglebius
3668290001Sglebius#ifdef _WIN32
3669290001Sglebius/* Add multiple nameservers from a space-or-comma-separated list. */
3670290001Sglebiusstatic int
3671290001Sglebiusevdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
3672290001Sglebius	const char *addr;
3673290001Sglebius	char *buf;
3674290001Sglebius	int r;
3675290001Sglebius	ASSERT_LOCKED(base);
3676290001Sglebius	while (*ips) {
3677290001Sglebius		while (isspace(*ips) || *ips == ',' || *ips == '\t')
3678290001Sglebius			++ips;
3679290001Sglebius		addr = ips;
3680290001Sglebius		while (isdigit(*ips) || *ips == '.' || *ips == ':' ||
3681290001Sglebius		    *ips=='[' || *ips==']')
3682290001Sglebius			++ips;
3683290001Sglebius		buf = mm_malloc(ips-addr+1);
3684290001Sglebius		if (!buf) return 4;
3685290001Sglebius		memcpy(buf, addr, ips-addr);
3686290001Sglebius		buf[ips-addr] = '\0';
3687290001Sglebius		r = evdns_base_nameserver_ip_add(base, buf);
3688290001Sglebius		mm_free(buf);
3689290001Sglebius		if (r) return r;
3690290001Sglebius	}
3691290001Sglebius	return 0;
3692290001Sglebius}
3693290001Sglebius
3694290001Sglebiustypedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
3695290001Sglebius
3696290001Sglebius/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
3697290001Sglebius/* figure out what our nameservers are. */
3698290001Sglebiusstatic int
3699290001Sglebiusload_nameservers_with_getnetworkparams(struct evdns_base *base)
3700290001Sglebius{
3701290001Sglebius	/* Based on MSDN examples and inspection of  c-ares code. */
3702290001Sglebius	FIXED_INFO *fixed;
3703290001Sglebius	HMODULE handle = 0;
3704290001Sglebius	ULONG size = sizeof(FIXED_INFO);
3705290001Sglebius	void *buf = NULL;
3706290001Sglebius	int status = 0, r, added_any;
3707290001Sglebius	IP_ADDR_STRING *ns;
3708290001Sglebius	GetNetworkParams_fn_t fn;
3709290001Sglebius
3710290001Sglebius	ASSERT_LOCKED(base);
3711290001Sglebius	if (!(handle = evutil_load_windows_system_library_(
3712290001Sglebius			TEXT("iphlpapi.dll")))) {
3713290001Sglebius		log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
3714290001Sglebius		status = -1;
3715290001Sglebius		goto done;
3716290001Sglebius	}
3717290001Sglebius	if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
3718290001Sglebius		log(EVDNS_LOG_WARN, "Could not get address of function.");
3719290001Sglebius		status = -1;
3720290001Sglebius		goto done;
3721290001Sglebius	}
3722290001Sglebius
3723290001Sglebius	buf = mm_malloc(size);
3724290001Sglebius	if (!buf) { status = 4; goto done; }
3725290001Sglebius	fixed = buf;
3726290001Sglebius	r = fn(fixed, &size);
3727290001Sglebius	if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
3728290001Sglebius		status = -1;
3729290001Sglebius		goto done;
3730290001Sglebius	}
3731290001Sglebius	if (r != ERROR_SUCCESS) {
3732290001Sglebius		mm_free(buf);
3733290001Sglebius		buf = mm_malloc(size);
3734290001Sglebius		if (!buf) { status = 4; goto done; }
3735290001Sglebius		fixed = buf;
3736290001Sglebius		r = fn(fixed, &size);
3737290001Sglebius		if (r != ERROR_SUCCESS) {
3738290001Sglebius			log(EVDNS_LOG_DEBUG, "fn() failed.");
3739290001Sglebius			status = -1;
3740290001Sglebius			goto done;
3741290001Sglebius		}
3742290001Sglebius	}
3743290001Sglebius
3744290001Sglebius	EVUTIL_ASSERT(fixed);
3745290001Sglebius	added_any = 0;
3746290001Sglebius	ns = &(fixed->DnsServerList);
3747290001Sglebius	while (ns) {
3748290001Sglebius		r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String);
3749290001Sglebius		if (r) {
3750290001Sglebius			log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
3751290001Sglebius				(ns->IpAddress.String),(int)GetLastError());
3752290001Sglebius			status = r;
3753290001Sglebius		} else {
3754290001Sglebius			++added_any;
3755290001Sglebius			log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
3756290001Sglebius		}
3757290001Sglebius
3758290001Sglebius		ns = ns->Next;
3759290001Sglebius	}
3760290001Sglebius
3761290001Sglebius	if (!added_any) {
3762290001Sglebius		log(EVDNS_LOG_DEBUG, "No nameservers added.");
3763290001Sglebius		if (status == 0)
3764290001Sglebius			status = -1;
3765290001Sglebius	} else {
3766290001Sglebius		status = 0;
3767290001Sglebius	}
3768290001Sglebius
3769290001Sglebius done:
3770290001Sglebius	if (buf)
3771290001Sglebius		mm_free(buf);
3772290001Sglebius	if (handle)
3773290001Sglebius		FreeLibrary(handle);
3774290001Sglebius	return status;
3775290001Sglebius}
3776290001Sglebius
3777290001Sglebiusstatic int
3778290001Sglebiusconfig_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey)
3779290001Sglebius{
3780290001Sglebius	char *buf;
3781290001Sglebius	DWORD bufsz = 0, type = 0;
3782290001Sglebius	int status = 0;
3783290001Sglebius
3784290001Sglebius	ASSERT_LOCKED(base);
3785290001Sglebius	if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
3786290001Sglebius	    != ERROR_MORE_DATA)
3787290001Sglebius		return -1;
3788290001Sglebius	if (!(buf = mm_malloc(bufsz)))
3789290001Sglebius		return -1;
3790290001Sglebius
3791290001Sglebius	if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
3792290001Sglebius	    == ERROR_SUCCESS && bufsz > 1) {
3793290001Sglebius		status = evdns_nameserver_ip_add_line(base,buf);
3794290001Sglebius	}
3795290001Sglebius
3796290001Sglebius	mm_free(buf);
3797290001Sglebius	return status;
3798290001Sglebius}
3799290001Sglebius
3800290001Sglebius#define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\")
3801290001Sglebius#define WIN_NS_9X_KEY  SERVICES_KEY TEXT("VxD\\MSTCP")
3802290001Sglebius#define WIN_NS_NT_KEY  SERVICES_KEY TEXT("Tcpip\\Parameters")
3803290001Sglebius
3804290001Sglebiusstatic int
3805290001Sglebiusload_nameservers_from_registry(struct evdns_base *base)
3806290001Sglebius{
3807290001Sglebius	int found = 0;
3808290001Sglebius	int r;
3809290001Sglebius#define TRY(k, name) \
3810290001Sglebius	if (!found && config_nameserver_from_reg_key(base,k,TEXT(name)) == 0) { \
3811290001Sglebius		log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
3812290001Sglebius		found = 1;						\
3813290001Sglebius	} else if (!found) {						\
3814290001Sglebius		log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
3815290001Sglebius		    #k,#name);						\
3816290001Sglebius	}
3817290001Sglebius
3818290001Sglebius	ASSERT_LOCKED(base);
3819290001Sglebius
3820290001Sglebius	if (((int)GetVersion()) > 0) { /* NT */
3821290001Sglebius		HKEY nt_key = 0, interfaces_key = 0;
3822290001Sglebius
3823290001Sglebius		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
3824290001Sglebius				 KEY_READ, &nt_key) != ERROR_SUCCESS) {
3825290001Sglebius			log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
3826290001Sglebius			return -1;
3827290001Sglebius		}
3828290001Sglebius		r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0,
3829290001Sglebius			     KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
3830290001Sglebius			     &interfaces_key);
3831290001Sglebius		if (r != ERROR_SUCCESS) {
3832290001Sglebius			log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
3833290001Sglebius			return -1;
3834290001Sglebius		}
3835290001Sglebius		TRY(nt_key, "NameServer");
3836290001Sglebius		TRY(nt_key, "DhcpNameServer");
3837290001Sglebius		TRY(interfaces_key, "NameServer");
3838290001Sglebius		TRY(interfaces_key, "DhcpNameServer");
3839290001Sglebius		RegCloseKey(interfaces_key);
3840290001Sglebius		RegCloseKey(nt_key);
3841290001Sglebius	} else {
3842290001Sglebius		HKEY win_key = 0;
3843290001Sglebius		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
3844290001Sglebius				 KEY_READ, &win_key) != ERROR_SUCCESS) {
3845290001Sglebius			log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
3846290001Sglebius			return -1;
3847290001Sglebius		}
3848290001Sglebius		TRY(win_key, "NameServer");
3849290001Sglebius		RegCloseKey(win_key);
3850290001Sglebius	}
3851290001Sglebius
3852290001Sglebius	if (found == 0) {
3853290001Sglebius		log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
3854290001Sglebius	}
3855290001Sglebius
3856290001Sglebius	return found ? 0 : -1;
3857290001Sglebius#undef TRY
3858290001Sglebius}
3859290001Sglebius
3860290001Sglebiusint
3861290001Sglebiusevdns_base_config_windows_nameservers(struct evdns_base *base)
3862290001Sglebius{
3863290001Sglebius	int r;
3864290001Sglebius	char *fname;
3865290001Sglebius	if (base == NULL)
3866290001Sglebius		base = current_base;
3867290001Sglebius	if (base == NULL)
3868290001Sglebius		return -1;
3869290001Sglebius	EVDNS_LOCK(base);
3870290001Sglebius	fname = evdns_get_default_hosts_filename();
3871290001Sglebius	log(EVDNS_LOG_DEBUG, "Loading hosts entries from %s", fname);
3872290001Sglebius	evdns_base_load_hosts(base, fname);
3873290001Sglebius	if (fname)
3874290001Sglebius		mm_free(fname);
3875290001Sglebius
3876290001Sglebius	if (load_nameservers_with_getnetworkparams(base) == 0) {
3877290001Sglebius		EVDNS_UNLOCK(base);
3878290001Sglebius		return 0;
3879290001Sglebius	}
3880290001Sglebius	r = load_nameservers_from_registry(base);
3881290001Sglebius
3882290001Sglebius	EVDNS_UNLOCK(base);
3883290001Sglebius	return r;
3884290001Sglebius}
3885290001Sglebius
3886290001Sglebiusint
3887290001Sglebiusevdns_config_windows_nameservers(void)
3888290001Sglebius{
3889290001Sglebius	if (!current_base) {
3890290001Sglebius		current_base = evdns_base_new(NULL, 1);
3891290001Sglebius		return current_base == NULL ? -1 : 0;
3892290001Sglebius	} else {
3893290001Sglebius		return evdns_base_config_windows_nameservers(current_base);
3894290001Sglebius	}
3895290001Sglebius}
3896290001Sglebius#endif
3897290001Sglebius
3898290001Sglebiusstruct evdns_base *
3899290001Sglebiusevdns_base_new(struct event_base *event_base, int flags)
3900290001Sglebius{
3901290001Sglebius	struct evdns_base *base;
3902290001Sglebius
3903290001Sglebius	if (evutil_secure_rng_init() < 0) {
3904290001Sglebius		log(EVDNS_LOG_WARN, "Unable to seed random number generator; "
3905290001Sglebius		    "DNS can't run.");
3906290001Sglebius		return NULL;
3907290001Sglebius	}
3908290001Sglebius
3909290001Sglebius	/* Give the evutil library a hook into its evdns-enabled
3910290001Sglebius	 * functionality.  We can't just call evdns_getaddrinfo directly or
3911290001Sglebius	 * else libevent-core will depend on libevent-extras. */
3912290001Sglebius	evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo);
3913290001Sglebius
3914290001Sglebius	base = mm_malloc(sizeof(struct evdns_base));
3915290001Sglebius	if (base == NULL)
3916290001Sglebius		return (NULL);
3917290001Sglebius	memset(base, 0, sizeof(struct evdns_base));
3918290001Sglebius	base->req_waiting_head = NULL;
3919290001Sglebius
3920290001Sglebius	EVTHREAD_ALLOC_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
3921290001Sglebius	EVDNS_LOCK(base);
3922290001Sglebius
3923290001Sglebius	/* Set max requests inflight and allocate req_heads. */
3924290001Sglebius	base->req_heads = NULL;
3925290001Sglebius
3926290001Sglebius	evdns_base_set_max_requests_inflight(base, 64);
3927290001Sglebius
3928290001Sglebius	base->server_head = NULL;
3929290001Sglebius	base->event_base = event_base;
3930290001Sglebius	base->global_good_nameservers = base->global_requests_inflight =
3931290001Sglebius		base->global_requests_waiting = 0;
3932290001Sglebius
3933290001Sglebius	base->global_timeout.tv_sec = 5;
3934290001Sglebius	base->global_timeout.tv_usec = 0;
3935290001Sglebius	base->global_max_reissues = 1;
3936290001Sglebius	base->global_max_retransmits = 3;
3937290001Sglebius	base->global_max_nameserver_timeout = 3;
3938290001Sglebius	base->global_search_state = NULL;
3939290001Sglebius	base->global_randomize_case = 1;
3940290001Sglebius	base->global_getaddrinfo_allow_skew.tv_sec = 3;
3941290001Sglebius	base->global_getaddrinfo_allow_skew.tv_usec = 0;
3942290001Sglebius	base->global_nameserver_probe_initial_timeout.tv_sec = 10;
3943290001Sglebius	base->global_nameserver_probe_initial_timeout.tv_usec = 0;
3944290001Sglebius
3945290001Sglebius	TAILQ_INIT(&base->hostsdb);
3946290001Sglebius
3947290001Sglebius#define EVDNS_BASE_ALL_FLAGS (0x8001)
3948290001Sglebius	if (flags & ~EVDNS_BASE_ALL_FLAGS) {
3949290001Sglebius		flags = EVDNS_BASE_INITIALIZE_NAMESERVERS;
3950290001Sglebius		log(EVDNS_LOG_WARN,
3951290001Sglebius		    "Unrecognized flag passed to evdns_base_new(). Assuming "
3952290001Sglebius		    "you meant EVDNS_BASE_INITIALIZE_NAMESERVERS.");
3953290001Sglebius	}
3954290001Sglebius#undef EVDNS_BASE_ALL_FLAGS
3955290001Sglebius
3956290001Sglebius	if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) {
3957290001Sglebius		int r;
3958290001Sglebius#ifdef _WIN32
3959290001Sglebius		r = evdns_base_config_windows_nameservers(base);
3960290001Sglebius#else
3961290001Sglebius		r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
3962290001Sglebius#endif
3963290001Sglebius		if (r == -1) {
3964290001Sglebius			evdns_base_free_and_unlock(base, 0);
3965290001Sglebius			return NULL;
3966290001Sglebius		}
3967290001Sglebius	}
3968290001Sglebius	if (flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE) {
3969290001Sglebius		base->disable_when_inactive = 1;
3970290001Sglebius	}
3971290001Sglebius
3972290001Sglebius	EVDNS_UNLOCK(base);
3973290001Sglebius	return base;
3974290001Sglebius}
3975290001Sglebius
3976290001Sglebiusint
3977290001Sglebiusevdns_init(void)
3978290001Sglebius{
3979290001Sglebius	struct evdns_base *base = evdns_base_new(NULL, 1);
3980290001Sglebius	if (base) {
3981290001Sglebius		current_base = base;
3982290001Sglebius		return 0;
3983290001Sglebius	} else {
3984290001Sglebius		return -1;
3985290001Sglebius	}
3986290001Sglebius}
3987290001Sglebius
3988290001Sglebiusconst char *
3989290001Sglebiusevdns_err_to_string(int err)
3990290001Sglebius{
3991290001Sglebius    switch (err) {
3992290001Sglebius	case DNS_ERR_NONE: return "no error";
3993290001Sglebius	case DNS_ERR_FORMAT: return "misformatted query";
3994290001Sglebius	case DNS_ERR_SERVERFAILED: return "server failed";
3995290001Sglebius	case DNS_ERR_NOTEXIST: return "name does not exist";
3996290001Sglebius	case DNS_ERR_NOTIMPL: return "query not implemented";
3997290001Sglebius	case DNS_ERR_REFUSED: return "refused";
3998290001Sglebius
3999290001Sglebius	case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
4000290001Sglebius	case DNS_ERR_UNKNOWN: return "unknown";
4001290001Sglebius	case DNS_ERR_TIMEOUT: return "request timed out";
4002290001Sglebius	case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
4003290001Sglebius	case DNS_ERR_CANCEL: return "dns request canceled";
4004290001Sglebius	case DNS_ERR_NODATA: return "no records in the reply";
4005290001Sglebius	default: return "[Unknown error code]";
4006290001Sglebius    }
4007290001Sglebius}
4008290001Sglebius
4009290001Sglebiusstatic void
4010290001Sglebiusevdns_nameserver_free(struct nameserver *server)
4011290001Sglebius{
4012290001Sglebius	if (server->socket >= 0)
4013290001Sglebius	evutil_closesocket(server->socket);
4014290001Sglebius	(void) event_del(&server->event);
4015290001Sglebius	event_debug_unassign(&server->event);
4016290001Sglebius	if (server->state == 0)
4017290001Sglebius		(void) event_del(&server->timeout_event);
4018290001Sglebius	if (server->probe_request) {
4019290001Sglebius		evdns_cancel_request(server->base, server->probe_request);
4020290001Sglebius		server->probe_request = NULL;
4021290001Sglebius	}
4022290001Sglebius	event_debug_unassign(&server->timeout_event);
4023290001Sglebius	mm_free(server);
4024290001Sglebius}
4025290001Sglebius
4026290001Sglebiusstatic void
4027290001Sglebiusevdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
4028290001Sglebius{
4029290001Sglebius	struct nameserver *server, *server_next;
4030290001Sglebius	struct search_domain *dom, *dom_next;
4031290001Sglebius	int i;
4032290001Sglebius
4033290001Sglebius	/* Requires that we hold the lock. */
4034290001Sglebius
4035290001Sglebius	/* TODO(nickm) we might need to refcount here. */
4036290001Sglebius
4037290001Sglebius	for (server = base->server_head; server; server = server_next) {
4038290001Sglebius		server_next = server->next;
4039290001Sglebius		evdns_nameserver_free(server);
4040290001Sglebius		if (server_next == base->server_head)
4041290001Sglebius			break;
4042290001Sglebius	}
4043290001Sglebius	base->server_head = NULL;
4044290001Sglebius	base->global_good_nameservers = 0;
4045290001Sglebius
4046290001Sglebius	for (i = 0; i < base->n_req_heads; ++i) {
4047290001Sglebius		while (base->req_heads[i]) {
4048290001Sglebius			if (fail_requests)
4049290001Sglebius				reply_schedule_callback(base->req_heads[i], 0, DNS_ERR_SHUTDOWN, NULL);
4050290001Sglebius			request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1);
4051290001Sglebius		}
4052290001Sglebius	}
4053290001Sglebius	while (base->req_waiting_head) {
4054290001Sglebius		if (fail_requests)
4055290001Sglebius			reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
4056290001Sglebius		request_finished(base->req_waiting_head, &base->req_waiting_head, 1);
4057290001Sglebius	}
4058290001Sglebius	base->global_requests_inflight = base->global_requests_waiting = 0;
4059290001Sglebius
4060290001Sglebius
4061290001Sglebius	if (base->global_search_state) {
4062290001Sglebius		for (dom = base->global_search_state->head; dom; dom = dom_next) {
4063290001Sglebius			dom_next = dom->next;
4064290001Sglebius			mm_free(dom);
4065290001Sglebius		}
4066290001Sglebius		mm_free(base->global_search_state);
4067290001Sglebius		base->global_search_state = NULL;
4068290001Sglebius	}
4069290001Sglebius
4070290001Sglebius	{
4071290001Sglebius		struct hosts_entry *victim;
4072290001Sglebius		while ((victim = TAILQ_FIRST(&base->hostsdb))) {
4073290001Sglebius			TAILQ_REMOVE(&base->hostsdb, victim, next);
4074290001Sglebius			mm_free(victim);
4075290001Sglebius		}
4076290001Sglebius	}
4077290001Sglebius
4078290001Sglebius	mm_free(base->req_heads);
4079290001Sglebius
4080290001Sglebius	EVDNS_UNLOCK(base);
4081290001Sglebius	EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
4082290001Sglebius
4083290001Sglebius	mm_free(base);
4084290001Sglebius}
4085290001Sglebius
4086290001Sglebiusvoid
4087290001Sglebiusevdns_base_free(struct evdns_base *base, int fail_requests)
4088290001Sglebius{
4089290001Sglebius	EVDNS_LOCK(base);
4090290001Sglebius	evdns_base_free_and_unlock(base, fail_requests);
4091290001Sglebius}
4092290001Sglebius
4093290001Sglebiusvoid
4094290001Sglebiusevdns_base_clear_host_addresses(struct evdns_base *base)
4095290001Sglebius{
4096290001Sglebius	struct hosts_entry *victim;
4097290001Sglebius	EVDNS_LOCK(base);
4098290001Sglebius	while ((victim = TAILQ_FIRST(&base->hostsdb))) {
4099290001Sglebius		TAILQ_REMOVE(&base->hostsdb, victim, next);
4100290001Sglebius		mm_free(victim);
4101290001Sglebius	}
4102290001Sglebius	EVDNS_UNLOCK(base);
4103290001Sglebius}
4104290001Sglebius
4105290001Sglebiusvoid
4106290001Sglebiusevdns_shutdown(int fail_requests)
4107290001Sglebius{
4108290001Sglebius	if (current_base) {
4109290001Sglebius		struct evdns_base *b = current_base;
4110290001Sglebius		current_base = NULL;
4111290001Sglebius		evdns_base_free(b, fail_requests);
4112290001Sglebius	}
4113290001Sglebius	evdns_log_fn = NULL;
4114290001Sglebius}
4115290001Sglebius
4116290001Sglebiusstatic int
4117290001Sglebiusevdns_base_parse_hosts_line(struct evdns_base *base, char *line)
4118290001Sglebius{
4119290001Sglebius	char *strtok_state;
4120290001Sglebius	static const char *const delims = " \t";
4121290001Sglebius	char *const addr = strtok_r(line, delims, &strtok_state);
4122290001Sglebius	char *hostname, *hash;
4123290001Sglebius	struct sockaddr_storage ss;
4124290001Sglebius	int socklen = sizeof(ss);
4125290001Sglebius	ASSERT_LOCKED(base);
4126290001Sglebius
4127290001Sglebius#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
4128290001Sglebius
4129290001Sglebius	if (!addr || *addr == '#')
4130290001Sglebius		return 0;
4131290001Sglebius
4132290001Sglebius	memset(&ss, 0, sizeof(ss));
4133290001Sglebius	if (evutil_parse_sockaddr_port(addr, (struct sockaddr*)&ss, &socklen)<0)
4134290001Sglebius		return -1;
4135290001Sglebius	if (socklen > (int)sizeof(struct sockaddr_in6))
4136290001Sglebius		return -1;
4137290001Sglebius
4138290001Sglebius	if (sockaddr_getport((struct sockaddr*)&ss))
4139290001Sglebius		return -1;
4140290001Sglebius
4141290001Sglebius	while ((hostname = NEXT_TOKEN)) {
4142290001Sglebius		struct hosts_entry *he;
4143290001Sglebius		size_t namelen;
4144290001Sglebius		if ((hash = strchr(hostname, '#'))) {
4145290001Sglebius			if (hash == hostname)
4146290001Sglebius				return 0;
4147290001Sglebius			*hash = '\0';
4148290001Sglebius		}
4149290001Sglebius
4150290001Sglebius		namelen = strlen(hostname);
4151290001Sglebius
4152290001Sglebius		he = mm_calloc(1, sizeof(struct hosts_entry)+namelen);
4153290001Sglebius		if (!he)
4154290001Sglebius			return -1;
4155290001Sglebius		EVUTIL_ASSERT(socklen <= (int)sizeof(he->addr));
4156290001Sglebius		memcpy(&he->addr, &ss, socklen);
4157290001Sglebius		memcpy(he->hostname, hostname, namelen+1);
4158290001Sglebius		he->addrlen = socklen;
4159290001Sglebius
4160290001Sglebius		TAILQ_INSERT_TAIL(&base->hostsdb, he, next);
4161290001Sglebius
4162290001Sglebius		if (hash)
4163290001Sglebius			return 0;
4164290001Sglebius	}
4165290001Sglebius
4166290001Sglebius	return 0;
4167290001Sglebius#undef NEXT_TOKEN
4168290001Sglebius}
4169290001Sglebius
4170290001Sglebiusstatic int
4171290001Sglebiusevdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname)
4172290001Sglebius{
4173290001Sglebius	char *str=NULL, *cp, *eol;
4174290001Sglebius	size_t len;
4175290001Sglebius	int err=0;
4176290001Sglebius
4177290001Sglebius	ASSERT_LOCKED(base);
4178290001Sglebius
4179290001Sglebius	if (hosts_fname == NULL ||
4180290001Sglebius	    (err = evutil_read_file_(hosts_fname, &str, &len, 0)) < 0) {
4181290001Sglebius		char tmp[64];
4182290001Sglebius		strlcpy(tmp, "127.0.0.1   localhost", sizeof(tmp));
4183290001Sglebius		evdns_base_parse_hosts_line(base, tmp);
4184290001Sglebius		strlcpy(tmp, "::1   localhost", sizeof(tmp));
4185290001Sglebius		evdns_base_parse_hosts_line(base, tmp);
4186290001Sglebius		return err ? -1 : 0;
4187290001Sglebius	}
4188290001Sglebius
4189290001Sglebius	/* This will break early if there is a NUL in the hosts file.
4190290001Sglebius	 * Probably not a problem.*/
4191290001Sglebius	cp = str;
4192290001Sglebius	for (;;) {
4193290001Sglebius		eol = strchr(cp, '\n');
4194290001Sglebius
4195290001Sglebius		if (eol) {
4196290001Sglebius			*eol = '\0';
4197290001Sglebius			evdns_base_parse_hosts_line(base, cp);
4198290001Sglebius			cp = eol+1;
4199290001Sglebius		} else {
4200290001Sglebius			evdns_base_parse_hosts_line(base, cp);
4201290001Sglebius			break;
4202290001Sglebius		}
4203290001Sglebius	}
4204290001Sglebius
4205290001Sglebius	mm_free(str);
4206290001Sglebius	return 0;
4207290001Sglebius}
4208290001Sglebius
4209290001Sglebiusint
4210290001Sglebiusevdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname)
4211290001Sglebius{
4212290001Sglebius	int res;
4213290001Sglebius	if (!base)
4214290001Sglebius		base = current_base;
4215290001Sglebius	EVDNS_LOCK(base);
4216290001Sglebius	res = evdns_base_load_hosts_impl(base, hosts_fname);
4217290001Sglebius	EVDNS_UNLOCK(base);
4218290001Sglebius	return res;
4219290001Sglebius}
4220290001Sglebius
4221290001Sglebius/* A single request for a getaddrinfo, either v4 or v6. */
4222290001Sglebiusstruct getaddrinfo_subrequest {
4223290001Sglebius	struct evdns_request *r;
4224290001Sglebius	ev_uint32_t type;
4225290001Sglebius};
4226290001Sglebius
4227290001Sglebius/* State data used to implement an in-progress getaddrinfo. */
4228290001Sglebiusstruct evdns_getaddrinfo_request {
4229290001Sglebius	struct evdns_base *evdns_base;
4230290001Sglebius	/* Copy of the modified 'hints' data that we'll use to build
4231290001Sglebius	 * answers. */
4232290001Sglebius	struct evutil_addrinfo hints;
4233290001Sglebius	/* The callback to invoke when we're done */
4234290001Sglebius	evdns_getaddrinfo_cb user_cb;
4235290001Sglebius	/* User-supplied data to give to the callback. */
4236290001Sglebius	void *user_data;
4237290001Sglebius	/* The port to use when building sockaddrs. */
4238290001Sglebius	ev_uint16_t port;
4239290001Sglebius	/* The sub_request for an A record (if any) */
4240290001Sglebius	struct getaddrinfo_subrequest ipv4_request;
4241290001Sglebius	/* The sub_request for an AAAA record (if any) */
4242290001Sglebius	struct getaddrinfo_subrequest ipv6_request;
4243290001Sglebius
4244290001Sglebius	/* The cname result that we were told (if any) */
4245290001Sglebius	char *cname_result;
4246290001Sglebius
4247290001Sglebius	/* If we have one request answered and one request still inflight,
4248290001Sglebius	 * then this field holds the answer from the first request... */
4249290001Sglebius	struct evutil_addrinfo *pending_result;
4250290001Sglebius	/* And this event is a timeout that will tell us to cancel the second
4251290001Sglebius	 * request if it's taking a long time. */
4252290001Sglebius	struct event timeout;
4253290001Sglebius
4254290001Sglebius	/* And this field holds the error code from the first request... */
4255290001Sglebius	int pending_error;
4256290001Sglebius	/* If this is set, the user canceled this request. */
4257290001Sglebius	unsigned user_canceled : 1;
4258290001Sglebius	/* If this is set, the user can no longer cancel this request; we're
4259290001Sglebius	 * just waiting for the free. */
4260290001Sglebius	unsigned request_done : 1;
4261290001Sglebius};
4262290001Sglebius
4263290001Sglebius/* Convert an evdns errors to the equivalent getaddrinfo error. */
4264290001Sglebiusstatic int
4265290001Sglebiusevdns_err_to_getaddrinfo_err(int e1)
4266290001Sglebius{
4267290001Sglebius	/* XXX Do this better! */
4268290001Sglebius	if (e1 == DNS_ERR_NONE)
4269290001Sglebius		return 0;
4270290001Sglebius	else if (e1 == DNS_ERR_NOTEXIST)
4271290001Sglebius		return EVUTIL_EAI_NONAME;
4272290001Sglebius	else
4273290001Sglebius		return EVUTIL_EAI_FAIL;
4274290001Sglebius}
4275290001Sglebius
4276290001Sglebius/* Return the more informative of two getaddrinfo errors. */
4277290001Sglebiusstatic int
4278290001Sglebiusgetaddrinfo_merge_err(int e1, int e2)
4279290001Sglebius{
4280290001Sglebius	/* XXXX be cleverer here. */
4281290001Sglebius	if (e1 == 0)
4282290001Sglebius		return e2;
4283290001Sglebius	else
4284290001Sglebius		return e1;
4285290001Sglebius}
4286290001Sglebius
4287290001Sglebiusstatic void
4288290001Sglebiusfree_getaddrinfo_request(struct evdns_getaddrinfo_request *data)
4289290001Sglebius{
4290290001Sglebius	/* DO NOT CALL this if either of the requests is pending.  Only once
4291290001Sglebius	 * both callbacks have been invoked is it safe to free the request */
4292290001Sglebius	if (data->pending_result)
4293290001Sglebius		evutil_freeaddrinfo(data->pending_result);
4294290001Sglebius	if (data->cname_result)
4295290001Sglebius		mm_free(data->cname_result);
4296290001Sglebius	event_del(&data->timeout);
4297290001Sglebius	mm_free(data);
4298290001Sglebius	return;
4299290001Sglebius}
4300290001Sglebius
4301290001Sglebiusstatic void
4302290001Sglebiusadd_cname_to_reply(struct evdns_getaddrinfo_request *data,
4303290001Sglebius    struct evutil_addrinfo *ai)
4304290001Sglebius{
4305290001Sglebius	if (data->cname_result && ai) {
4306290001Sglebius		ai->ai_canonname = data->cname_result;
4307290001Sglebius		data->cname_result = NULL;
4308290001Sglebius	}
4309290001Sglebius}
4310290001Sglebius
4311290001Sglebius/* Callback: invoked when one request in a mixed-format A/AAAA getaddrinfo
4312290001Sglebius * request has finished, but the other one took too long to answer. Pass
4313290001Sglebius * along the answer we got, and cancel the other request.
4314290001Sglebius */
4315290001Sglebiusstatic void
4316290001Sglebiusevdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr)
4317290001Sglebius{
4318290001Sglebius	int v4_timedout = 0, v6_timedout = 0;
4319290001Sglebius	struct evdns_getaddrinfo_request *data = ptr;
4320290001Sglebius
4321290001Sglebius	/* Cancel any pending requests, and note which one */
4322290001Sglebius	if (data->ipv4_request.r) {
4323290001Sglebius		/* XXXX This does nothing if the request's callback is already
4324290001Sglebius		 * running (pending_cb is set). */
4325290001Sglebius		evdns_cancel_request(NULL, data->ipv4_request.r);
4326290001Sglebius		v4_timedout = 1;
4327290001Sglebius		EVDNS_LOCK(data->evdns_base);
4328290001Sglebius		++data->evdns_base->getaddrinfo_ipv4_timeouts;
4329290001Sglebius		EVDNS_UNLOCK(data->evdns_base);
4330290001Sglebius	}
4331290001Sglebius	if (data->ipv6_request.r) {
4332290001Sglebius		/* XXXX This does nothing if the request's callback is already
4333290001Sglebius		 * running (pending_cb is set). */
4334290001Sglebius		evdns_cancel_request(NULL, data->ipv6_request.r);
4335290001Sglebius		v6_timedout = 1;
4336290001Sglebius		EVDNS_LOCK(data->evdns_base);
4337290001Sglebius		++data->evdns_base->getaddrinfo_ipv6_timeouts;
4338290001Sglebius		EVDNS_UNLOCK(data->evdns_base);
4339290001Sglebius	}
4340290001Sglebius
4341290001Sglebius	/* We only use this timeout callback when we have an answer for
4342290001Sglebius	 * one address. */
4343290001Sglebius	EVUTIL_ASSERT(!v4_timedout || !v6_timedout);
4344290001Sglebius
4345290001Sglebius	/* Report the outcome of the other request that didn't time out. */
4346290001Sglebius	if (data->pending_result) {
4347290001Sglebius		add_cname_to_reply(data, data->pending_result);
4348290001Sglebius		data->user_cb(0, data->pending_result, data->user_data);
4349290001Sglebius		data->pending_result = NULL;
4350290001Sglebius	} else {
4351290001Sglebius		int e = data->pending_error;
4352290001Sglebius		if (!e)
4353290001Sglebius			e = EVUTIL_EAI_AGAIN;
4354290001Sglebius		data->user_cb(e, NULL, data->user_data);
4355290001Sglebius	}
4356290001Sglebius
4357290001Sglebius	data->user_cb = NULL; /* prevent double-call if evdns callbacks are
4358290001Sglebius			       * in-progress. XXXX It would be better if this
4359290001Sglebius			       * weren't necessary. */
4360290001Sglebius
4361290001Sglebius	if (!v4_timedout && !v6_timedout) {
4362290001Sglebius		/* should be impossible? XXXX */
4363290001Sglebius		free_getaddrinfo_request(data);
4364290001Sglebius	}
4365290001Sglebius}
4366290001Sglebius
4367290001Sglebiusstatic int
4368290001Sglebiusevdns_getaddrinfo_set_timeout(struct evdns_base *evdns_base,
4369290001Sglebius    struct evdns_getaddrinfo_request *data)
4370290001Sglebius{
4371290001Sglebius	return event_add(&data->timeout, &evdns_base->global_getaddrinfo_allow_skew);
4372290001Sglebius}
4373290001Sglebius
4374290001Sglebiusstatic inline int
4375290001Sglebiusevdns_result_is_answer(int result)
4376290001Sglebius{
4377290001Sglebius	return (result != DNS_ERR_NOTIMPL && result != DNS_ERR_REFUSED &&
4378290001Sglebius	    result != DNS_ERR_SERVERFAILED && result != DNS_ERR_CANCEL);
4379290001Sglebius}
4380290001Sglebius
4381290001Sglebiusstatic void
4382290001Sglebiusevdns_getaddrinfo_gotresolve(int result, char type, int count,
4383290001Sglebius    int ttl, void *addresses, void *arg)
4384290001Sglebius{
4385290001Sglebius	int i;
4386290001Sglebius	struct getaddrinfo_subrequest *req = arg;
4387290001Sglebius	struct getaddrinfo_subrequest *other_req;
4388290001Sglebius	struct evdns_getaddrinfo_request *data;
4389290001Sglebius
4390290001Sglebius	struct evutil_addrinfo *res;
4391290001Sglebius
4392290001Sglebius	struct sockaddr_in sin;
4393290001Sglebius	struct sockaddr_in6 sin6;
4394290001Sglebius	struct sockaddr *sa;
4395290001Sglebius	int socklen, addrlen;
4396290001Sglebius	void *addrp;
4397290001Sglebius	int err;
4398290001Sglebius	int user_canceled;
4399290001Sglebius
4400290001Sglebius	EVUTIL_ASSERT(req->type == DNS_IPv4_A || req->type == DNS_IPv6_AAAA);
4401290001Sglebius	if (req->type == DNS_IPv4_A) {
4402290001Sglebius		data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv4_request);
4403290001Sglebius		other_req = &data->ipv6_request;
4404290001Sglebius	} else {
4405290001Sglebius		data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv6_request);
4406290001Sglebius		other_req = &data->ipv4_request;
4407290001Sglebius	}
4408290001Sglebius
4409290001Sglebius	EVDNS_LOCK(data->evdns_base);
4410290001Sglebius	if (evdns_result_is_answer(result)) {
4411290001Sglebius		if (req->type == DNS_IPv4_A)
4412290001Sglebius			++data->evdns_base->getaddrinfo_ipv4_answered;
4413290001Sglebius		else
4414290001Sglebius			++data->evdns_base->getaddrinfo_ipv6_answered;
4415290001Sglebius	}
4416290001Sglebius	user_canceled = data->user_canceled;
4417290001Sglebius	if (other_req->r == NULL)
4418290001Sglebius		data->request_done = 1;
4419290001Sglebius	EVDNS_UNLOCK(data->evdns_base);
4420290001Sglebius
4421290001Sglebius	req->r = NULL;
4422290001Sglebius
4423290001Sglebius	if (result == DNS_ERR_CANCEL && ! user_canceled) {
4424290001Sglebius		/* Internal cancel request from timeout or internal error.
4425290001Sglebius		 * we already answered the user. */
4426290001Sglebius		if (other_req->r == NULL)
4427290001Sglebius			free_getaddrinfo_request(data);
4428290001Sglebius		return;
4429290001Sglebius	}
4430290001Sglebius
4431290001Sglebius	if (data->user_cb == NULL) {
4432290001Sglebius		/* We already answered.  XXXX This shouldn't be needed; see
4433290001Sglebius		 * comments in evdns_getaddrinfo_timeout_cb */
4434290001Sglebius		free_getaddrinfo_request(data);
4435290001Sglebius		return;
4436290001Sglebius	}
4437290001Sglebius
4438290001Sglebius	if (result == DNS_ERR_NONE) {
4439290001Sglebius		if (count == 0)
4440290001Sglebius			err = EVUTIL_EAI_NODATA;
4441290001Sglebius		else
4442290001Sglebius			err = 0;
4443290001Sglebius	} else {
4444290001Sglebius		err = evdns_err_to_getaddrinfo_err(result);
4445290001Sglebius	}
4446290001Sglebius
4447290001Sglebius	if (err) {
4448290001Sglebius		/* Looks like we got an error. */
4449290001Sglebius		if (other_req->r) {
4450290001Sglebius			/* The other request is still working; maybe it will
4451290001Sglebius			 * succeed. */
4452290001Sglebius			/* XXXX handle failure from set_timeout */
4453290001Sglebius			evdns_getaddrinfo_set_timeout(data->evdns_base, data);
4454290001Sglebius			data->pending_error = err;
4455290001Sglebius			return;
4456290001Sglebius		}
4457290001Sglebius
4458290001Sglebius		if (user_canceled) {
4459290001Sglebius			data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
4460290001Sglebius		} else if (data->pending_result) {
4461290001Sglebius			/* If we have an answer waiting, and we weren't
4462290001Sglebius			 * canceled, ignore this error. */
4463290001Sglebius			add_cname_to_reply(data, data->pending_result);
4464290001Sglebius			data->user_cb(0, data->pending_result, data->user_data);
4465290001Sglebius			data->pending_result = NULL;
4466290001Sglebius		} else {
4467290001Sglebius			if (data->pending_error)
4468290001Sglebius				err = getaddrinfo_merge_err(err,
4469290001Sglebius				    data->pending_error);
4470290001Sglebius			data->user_cb(err, NULL, data->user_data);
4471290001Sglebius		}
4472290001Sglebius		free_getaddrinfo_request(data);
4473290001Sglebius		return;
4474290001Sglebius	} else if (user_canceled) {
4475290001Sglebius		if (other_req->r) {
4476290001Sglebius			/* The other request is still working; let it hit this
4477290001Sglebius			 * callback with EVUTIL_EAI_CANCEL callback and report
4478290001Sglebius			 * the failure. */
4479290001Sglebius			return;
4480290001Sglebius		}
4481290001Sglebius		data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
4482290001Sglebius		free_getaddrinfo_request(data);
4483290001Sglebius		return;
4484290001Sglebius	}
4485290001Sglebius
4486290001Sglebius	/* Looks like we got some answers. We should turn them into addrinfos
4487290001Sglebius	 * and then either queue those or return them all. */
4488290001Sglebius	EVUTIL_ASSERT(type == DNS_IPv4_A || type == DNS_IPv6_AAAA);
4489290001Sglebius
4490290001Sglebius	if (type == DNS_IPv4_A) {
4491290001Sglebius		memset(&sin, 0, sizeof(sin));
4492290001Sglebius		sin.sin_family = AF_INET;
4493290001Sglebius		sin.sin_port = htons(data->port);
4494290001Sglebius
4495290001Sglebius		sa = (struct sockaddr *)&sin;
4496290001Sglebius		socklen = sizeof(sin);
4497290001Sglebius		addrlen = 4;
4498290001Sglebius		addrp = &sin.sin_addr.s_addr;
4499290001Sglebius	} else {
4500290001Sglebius		memset(&sin6, 0, sizeof(sin6));
4501290001Sglebius		sin6.sin6_family = AF_INET6;
4502290001Sglebius		sin6.sin6_port = htons(data->port);
4503290001Sglebius
4504290001Sglebius		sa = (struct sockaddr *)&sin6;
4505290001Sglebius		socklen = sizeof(sin6);
4506290001Sglebius		addrlen = 16;
4507290001Sglebius		addrp = &sin6.sin6_addr.s6_addr;
4508290001Sglebius	}
4509290001Sglebius
4510290001Sglebius	res = NULL;
4511290001Sglebius	for (i=0; i < count; ++i) {
4512290001Sglebius		struct evutil_addrinfo *ai;
4513290001Sglebius		memcpy(addrp, ((char*)addresses)+i*addrlen, addrlen);
4514290001Sglebius		ai = evutil_new_addrinfo_(sa, socklen, &data->hints);
4515290001Sglebius		if (!ai) {
4516290001Sglebius			if (other_req->r) {
4517290001Sglebius				evdns_cancel_request(NULL, other_req->r);
4518290001Sglebius			}
4519290001Sglebius			data->user_cb(EVUTIL_EAI_MEMORY, NULL, data->user_data);
4520290001Sglebius			if (res)
4521290001Sglebius				evutil_freeaddrinfo(res);
4522290001Sglebius
4523290001Sglebius			if (other_req->r == NULL)
4524290001Sglebius				free_getaddrinfo_request(data);
4525290001Sglebius			return;
4526290001Sglebius		}
4527290001Sglebius		res = evutil_addrinfo_append_(res, ai);
4528290001Sglebius	}
4529290001Sglebius
4530290001Sglebius	if (other_req->r) {
4531290001Sglebius		/* The other request is still in progress; wait for it */
4532290001Sglebius		/* XXXX handle failure from set_timeout */
4533290001Sglebius		evdns_getaddrinfo_set_timeout(data->evdns_base, data);
4534290001Sglebius		data->pending_result = res;
4535290001Sglebius		return;
4536290001Sglebius	} else {
4537290001Sglebius		/* The other request is done or never started; append its
4538290001Sglebius		 * results (if any) and return them. */
4539290001Sglebius		if (data->pending_result) {
4540290001Sglebius			if (req->type == DNS_IPv4_A)
4541290001Sglebius				res = evutil_addrinfo_append_(res,
4542290001Sglebius				    data->pending_result);
4543290001Sglebius			else
4544290001Sglebius				res = evutil_addrinfo_append_(
4545290001Sglebius				    data->pending_result, res);
4546290001Sglebius			data->pending_result = NULL;
4547290001Sglebius		}
4548290001Sglebius
4549290001Sglebius		/* Call the user callback. */
4550290001Sglebius		add_cname_to_reply(data, res);
4551290001Sglebius		data->user_cb(0, res, data->user_data);
4552290001Sglebius
4553290001Sglebius		/* Free data. */
4554290001Sglebius		free_getaddrinfo_request(data);
4555290001Sglebius	}
4556290001Sglebius}
4557290001Sglebius
4558290001Sglebiusstatic struct hosts_entry *
4559290001Sglebiusfind_hosts_entry(struct evdns_base *base, const char *hostname,
4560290001Sglebius    struct hosts_entry *find_after)
4561290001Sglebius{
4562290001Sglebius	struct hosts_entry *e;
4563290001Sglebius
4564290001Sglebius	if (find_after)
4565290001Sglebius		e = TAILQ_NEXT(find_after, next);
4566290001Sglebius	else
4567290001Sglebius		e = TAILQ_FIRST(&base->hostsdb);
4568290001Sglebius
4569290001Sglebius	for (; e; e = TAILQ_NEXT(e, next)) {
4570290001Sglebius		if (!evutil_ascii_strcasecmp(e->hostname, hostname))
4571290001Sglebius			return e;
4572290001Sglebius	}
4573290001Sglebius	return NULL;
4574290001Sglebius}
4575290001Sglebius
4576290001Sglebiusstatic int
4577290001Sglebiusevdns_getaddrinfo_fromhosts(struct evdns_base *base,
4578290001Sglebius    const char *nodename, struct evutil_addrinfo *hints, ev_uint16_t port,
4579290001Sglebius    struct evutil_addrinfo **res)
4580290001Sglebius{
4581290001Sglebius	int n_found = 0;
4582290001Sglebius	struct hosts_entry *e;
4583290001Sglebius	struct evutil_addrinfo *ai=NULL;
4584290001Sglebius	int f = hints->ai_family;
4585290001Sglebius
4586290001Sglebius	EVDNS_LOCK(base);
4587290001Sglebius	for (e = find_hosts_entry(base, nodename, NULL); e;
4588290001Sglebius	    e = find_hosts_entry(base, nodename, e)) {
4589290001Sglebius		struct evutil_addrinfo *ai_new;
4590290001Sglebius		++n_found;
4591290001Sglebius		if ((e->addr.sa.sa_family == AF_INET && f == PF_INET6) ||
4592290001Sglebius		    (e->addr.sa.sa_family == AF_INET6 && f == PF_INET))
4593290001Sglebius			continue;
4594290001Sglebius		ai_new = evutil_new_addrinfo_(&e->addr.sa, e->addrlen, hints);
4595290001Sglebius		if (!ai_new) {
4596290001Sglebius			n_found = 0;
4597290001Sglebius			goto out;
4598290001Sglebius		}
4599290001Sglebius		sockaddr_setport(ai_new->ai_addr, port);
4600290001Sglebius		ai = evutil_addrinfo_append_(ai, ai_new);
4601290001Sglebius	}
4602290001Sglebius	EVDNS_UNLOCK(base);
4603290001Sglebiusout:
4604290001Sglebius	if (n_found) {
4605290001Sglebius		/* Note that we return an empty answer if we found entries for
4606290001Sglebius		 * this hostname but none were of the right address type. */
4607290001Sglebius		*res = ai;
4608290001Sglebius		return 0;
4609290001Sglebius	} else {
4610290001Sglebius		if (ai)
4611290001Sglebius			evutil_freeaddrinfo(ai);
4612290001Sglebius		return -1;
4613290001Sglebius	}
4614290001Sglebius}
4615290001Sglebius
4616290001Sglebiusstruct evdns_getaddrinfo_request *
4617290001Sglebiusevdns_getaddrinfo(struct evdns_base *dns_base,
4618290001Sglebius    const char *nodename, const char *servname,
4619290001Sglebius    const struct evutil_addrinfo *hints_in,
4620290001Sglebius    evdns_getaddrinfo_cb cb, void *arg)
4621290001Sglebius{
4622290001Sglebius	struct evdns_getaddrinfo_request *data;
4623290001Sglebius	struct evutil_addrinfo hints;
4624290001Sglebius	struct evutil_addrinfo *res = NULL;
4625290001Sglebius	int err;
4626290001Sglebius	int port = 0;
4627290001Sglebius	int want_cname = 0;
4628290001Sglebius
4629290001Sglebius	if (!dns_base) {
4630290001Sglebius		dns_base = current_base;
4631290001Sglebius		if (!dns_base) {
4632290001Sglebius			log(EVDNS_LOG_WARN,
4633290001Sglebius			    "Call to getaddrinfo_async with no "
4634290001Sglebius			    "evdns_base configured.");
4635290001Sglebius			cb(EVUTIL_EAI_FAIL, NULL, arg); /* ??? better error? */
4636290001Sglebius			return NULL;
4637290001Sglebius		}
4638290001Sglebius	}
4639290001Sglebius
4640290001Sglebius	/* If we _must_ answer this immediately, do so. */
4641290001Sglebius	if ((hints_in && (hints_in->ai_flags & EVUTIL_AI_NUMERICHOST))) {
4642290001Sglebius		res = NULL;
4643290001Sglebius		err = evutil_getaddrinfo(nodename, servname, hints_in, &res);
4644290001Sglebius		cb(err, res, arg);
4645290001Sglebius		return NULL;
4646290001Sglebius	}
4647290001Sglebius
4648290001Sglebius	if (hints_in) {
4649290001Sglebius		memcpy(&hints, hints_in, sizeof(hints));
4650290001Sglebius	} else {
4651290001Sglebius		memset(&hints, 0, sizeof(hints));
4652290001Sglebius		hints.ai_family = PF_UNSPEC;
4653290001Sglebius	}
4654290001Sglebius
4655290001Sglebius	evutil_adjust_hints_for_addrconfig_(&hints);
4656290001Sglebius
4657290001Sglebius	/* Now try to see if we _can_ answer immediately. */
4658290001Sglebius	/* (It would be nice to do this by calling getaddrinfo directly, with
4659290001Sglebius	 * AI_NUMERICHOST, on plaforms that have it, but we can't: there isn't
4660290001Sglebius	 * a reliable way to distinguish the "that wasn't a numeric host!" case
4661290001Sglebius	 * from any other EAI_NONAME cases.) */
4662290001Sglebius	err = evutil_getaddrinfo_common_(nodename, servname, &hints, &res, &port);
4663290001Sglebius	if (err != EVUTIL_EAI_NEED_RESOLVE) {
4664290001Sglebius		cb(err, res, arg);
4665290001Sglebius		return NULL;
4666290001Sglebius	}
4667290001Sglebius
4668290001Sglebius	/* If there is an entry in the hosts file, we should give it now. */
4669290001Sglebius	if (!evdns_getaddrinfo_fromhosts(dns_base, nodename, &hints, port, &res)) {
4670290001Sglebius		cb(0, res, arg);
4671290001Sglebius		return NULL;
4672290001Sglebius	}
4673290001Sglebius
4674290001Sglebius	/* Okay, things are serious now. We're going to need to actually
4675290001Sglebius	 * launch a request.
4676290001Sglebius	 */
4677290001Sglebius	data = mm_calloc(1,sizeof(struct evdns_getaddrinfo_request));
4678290001Sglebius	if (!data) {
4679290001Sglebius		cb(EVUTIL_EAI_MEMORY, NULL, arg);
4680290001Sglebius		return NULL;
4681290001Sglebius	}
4682290001Sglebius
4683290001Sglebius	memcpy(&data->hints, &hints, sizeof(data->hints));
4684290001Sglebius	data->port = (ev_uint16_t)port;
4685290001Sglebius	data->ipv4_request.type = DNS_IPv4_A;
4686290001Sglebius	data->ipv6_request.type = DNS_IPv6_AAAA;
4687290001Sglebius	data->user_cb = cb;
4688290001Sglebius	data->user_data = arg;
4689290001Sglebius	data->evdns_base = dns_base;
4690290001Sglebius
4691290001Sglebius	want_cname = (hints.ai_flags & EVUTIL_AI_CANONNAME);
4692290001Sglebius
4693290001Sglebius	/* If we are asked for a PF_UNSPEC address, we launch two requests in
4694290001Sglebius	 * parallel: one for an A address and one for an AAAA address.  We
4695290001Sglebius	 * can't send just one request, since many servers only answer one
4696290001Sglebius	 * question per DNS request.
4697290001Sglebius	 *
4698290001Sglebius	 * Once we have the answer to one request, we allow for a short
4699290001Sglebius	 * timeout before we report it, to see if the other one arrives.  If
4700290001Sglebius	 * they both show up in time, then we report both the answers.
4701290001Sglebius	 *
4702290001Sglebius	 * If too many addresses of one type time out or fail, we should stop
4703290001Sglebius	 * launching those requests. (XXX we don't do that yet.)
4704290001Sglebius	 */
4705290001Sglebius
4706290001Sglebius	if (hints.ai_family != PF_INET6) {
4707290001Sglebius		log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p",
4708290001Sglebius		    nodename, &data->ipv4_request);
4709290001Sglebius
4710290001Sglebius		data->ipv4_request.r = evdns_base_resolve_ipv4(dns_base,
4711290001Sglebius		    nodename, 0, evdns_getaddrinfo_gotresolve,
4712290001Sglebius		    &data->ipv4_request);
4713290001Sglebius		if (want_cname && data->ipv4_request.r)
4714290001Sglebius			data->ipv4_request.r->current_req->put_cname_in_ptr =
4715290001Sglebius			    &data->cname_result;
4716290001Sglebius	}
4717290001Sglebius	if (hints.ai_family != PF_INET) {
4718290001Sglebius		log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv6 as %p",
4719290001Sglebius		    nodename, &data->ipv6_request);
4720290001Sglebius
4721290001Sglebius		data->ipv6_request.r = evdns_base_resolve_ipv6(dns_base,
4722290001Sglebius		    nodename, 0, evdns_getaddrinfo_gotresolve,
4723290001Sglebius		    &data->ipv6_request);
4724290001Sglebius		if (want_cname && data->ipv6_request.r)
4725290001Sglebius			data->ipv6_request.r->current_req->put_cname_in_ptr =
4726290001Sglebius			    &data->cname_result;
4727290001Sglebius	}
4728290001Sglebius
4729290001Sglebius	evtimer_assign(&data->timeout, dns_base->event_base,
4730290001Sglebius	    evdns_getaddrinfo_timeout_cb, data);
4731290001Sglebius
4732290001Sglebius	if (data->ipv4_request.r || data->ipv6_request.r) {
4733290001Sglebius		return data;
4734290001Sglebius	} else {
4735290001Sglebius		mm_free(data);
4736290001Sglebius		cb(EVUTIL_EAI_FAIL, NULL, arg);
4737290001Sglebius		return NULL;
4738290001Sglebius	}
4739290001Sglebius}
4740290001Sglebius
4741290001Sglebiusvoid
4742290001Sglebiusevdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *data)
4743290001Sglebius{
4744290001Sglebius	EVDNS_LOCK(data->evdns_base);
4745290001Sglebius	if (data->request_done) {
4746290001Sglebius		EVDNS_UNLOCK(data->evdns_base);
4747290001Sglebius		return;
4748290001Sglebius	}
4749290001Sglebius	event_del(&data->timeout);
4750290001Sglebius	data->user_canceled = 1;
4751290001Sglebius	if (data->ipv4_request.r)
4752290001Sglebius		evdns_cancel_request(data->evdns_base, data->ipv4_request.r);
4753290001Sglebius	if (data->ipv6_request.r)
4754290001Sglebius		evdns_cancel_request(data->evdns_base, data->ipv6_request.r);
4755290001Sglebius	EVDNS_UNLOCK(data->evdns_base);
4756290001Sglebius}
4757